Documentation Index Fetch the complete documentation index at: https://mintlify.com/projectdiscovery/nuclei/llms.txt
Use this file to discover all available pages before exploring further.
Flow control is a powerful template engine introduced in Nuclei v3 that enables conditional execution and request orchestration using JavaScript (ECMAScript 5.1). It provides two-way bindings between JavaScript and Nuclei, allowing you to write complex template logic with full programmatic control.
Why flow control
Flow control solves two major limitations of traditional templates:
Conditional execution - Execute requests only when certain conditions are met
Request orchestration - Control execution order, iterate over values, and implement custom logic
Flow uses Goja as the JavaScript runtime engine (ECMAScript 5.1 compatible).
Basic flow syntax
Add a flow field to your template with JavaScript code:
id : flow-example
info :
name : Simple Flow Example
author : pdteam
severity : info
flow : http(1) && http(2)
http :
- method : GET
path :
- "{{BaseURL}}/step1"
- method : GET
path :
- "{{BaseURL}}/step2"
id : flow-multiline
info :
name : Multi-line Flow
author : pdteam
severity : info
flow : |
http(1);
if (template["emails"]) {
for (let email of template["emails"]) {
set("email", email);
http(2);
}
}
http :
- method : GET
path :
- "{{BaseURL}}"
extractors :
- type : regex
name : emails
internal : true
regex :
- "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+ \\ .[a-zA-Z]{2,}"
- method : GET
path :
- "{{BaseURL}}/user?email={{email}}"
Protocol execution functions
Flow provides functions to execute protocol requests:
Execute all HTTP requests.
Execute specific HTTP request by ID or index. http ( "login" ); // By ID
http ( 1 ); // By index (0-based)
Execute SSL/TLS requests.
Execute network/TCP requests.
All protocol functions return a boolean indicating whether the request matched.
Template context functions
Create or update a variable in template context. set ( "token" , "abc123" );
set ( "count" , 42 );
Get a value from template context (extracted values, variables). let emails = template [ "emails" ];
let token = template [ "auth_token" ];
Helper functions
iterate(value1, value2, ...)
Safely iterate over any value type (arrays, objects, strings, numbers), handling null/empty values. for ( let item of iterate ( template [ "items" ])) {
set ( "item" , item );
http ();
}
Print message to stdout (for debugging). log ( "Current token: " + template [ "token" ]);
Conditional execution
Execute requests only when conditions are met:
WordPress Brute Force
DNS to HTTP Flow
id : wordpress-bruteforce
info :
name : WordPress Login Bruteforce
author : pdteam
severity : high
flow : http("check-wp") && http("bruteforce")
http :
- id : check-wp
method : GET
path :
- "{{BaseURL}}/wp-login.php"
matchers :
- type : word
condition : and
words :
- "WordPress"
- "wp-content"
internal : true
- id : bruteforce
method : POST
path :
- "{{BaseURL}}/wp-login.php"
body : "log={{username}}&pwd={{password}}&wp-submit=Log+In"
attack : clusterbomb
payloads :
username :
- admin
- guest
password :
- password123
- admin123
matchers :
- type : word
negative : true
words :
- "ERROR"
Request orchestration
Iterate over extracted values and execute requests for each:
Extract and Iterate
DNS NS Probe
id : extract-emails
info :
name : Extract Email IDs from Response
author : pdteam
severity : info
flow : |
http(1);
for (let email of template["emails"]) {
set("email", email);
http(2);
}
http :
- method : GET
path :
- "{{BaseURL}}"
extractors :
- type : regex
name : emails
internal : true
regex :
- "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+ \\ .[a-zA-Z]{2,}"
- method : GET
path :
- "{{BaseURL}}/user/{{base64(email)}}"
matchers :
- type : word
words :
- "Welcome"
Advanced patterns
VHost enumeration
id : vhost-enum-flow
info :
name : VHost Enumeration
author : pdteam
severity : info
flow : |
ssl();
dns();
// Collect all potential vhosts
let vhosts = [];
// Add subject CN if exists
if (template["ssl_subject_cn"]) {
vhosts.push(template["ssl_subject_cn"].replace("*.", ""));
}
// Add subject alternative names
if (template["ssl_subject_an"]) {
for (let san of iterate(template["ssl_subject_an"])) {
vhosts.push(san.replace("*.", ""));
}
}
// Add PTR record
if (template["ptr_record"]) {
vhosts.push(template["ptr_record"].replace(/\.$/, ""));
}
// Test each vhost
for (let vhost of vhosts) {
set("vhost", vhost);
http();
}
ssl :
- address : "{{Host}}:{{Port}}"
dns :
- name : "{{FQDN}}"
type : PTR
extractors :
- type : regex
name : ptr_record
internal : true
group : 1
regex :
- "IN \t PTR \t (.+)"
http :
- raw :
- |
GET / HTTP/1.1
Host: {{vhost}}
matchers :
- type : status
negative : true
status :
- 400
- 502
Multi-protocol value sharing
id : dns-http-dynamic-values
info :
name : Multi-Protocol Dynamic Values
author : pdteam
severity : info
flow : dns() && http()
dns :
- name : "{{FQDN}}"
type : CNAME
extractors :
- type : dsl
name : blogid
internal : true
dsl :
- "trim_suffix(cname, '.vercel-dns.com')"
http :
- method : GET
path :
- "{{BaseURL}}"
matchers :
- type : dsl
condition : and
dsl :
- "contains(body, 'home')"
- "blogid == 'cname'"
Flow vs workflows
Advantages:
Single template file
Full JavaScript control
Iterate over extracted values
Custom conditional logic
Access to all JavaScript features
Best for:
Complex multi-step templates
Dynamic iteration
Custom orchestration logic
Templates with data processing
Advantages:
Reuse existing templates
Technology-based organization
Community template ecosystem
Simpler syntax
Best for:
Combining multiple templates
Technology-specific checks
Progressive scanning
Template library organization
JavaScript features
Flow supports ECMAScript 5.1, including:
Variables: let, var, const
Control flow: if, else, for, while, switch
Functions: function() {}, anonymous functions
Arrays: [], .push(), .pop(), .length
Objects: {}, property access
Operators: &&, ||, !, ==, ===, >, <
String manipulation: .replace(), .substring(), .indexOf()
ECMAScript 5.1 does NOT support:
Arrow functions (=>)
Template literals (`string ${var}`)
Destructuring
async/await
ES6+ features
Use traditional JavaScript syntax instead.
Using DSL functions in flow
You can use Nuclei DSL helper functions in flow:
flow : |
dns();
// Use DSL functions via JavaScript
let domain = template["cname"];
let cleaned = dsl("to_lower(trim_suffix('" + domain + "', '.'))");
set("clean_domain", cleaned);
http();
Debugging flows
Use the log() function for debugging:
flow : |
log("Starting flow execution");
http(1);
log("HTTP request 1 completed");
let emails = template["emails"];
log("Found " + emails.length + " emails");
for (let email of emails) {
log("Testing email: " + email);
set("email", email);
http(2);
}
Real-world examples
JWT Refresh Flow
Progressive Exploitation
id : jwt-refresh-flow
info :
name : JWT Token Refresh Flow
author : pdteam
severity : info
flow : |
// Get initial JWT
http("login");
// Use JWT for requests
for (let i = 0; i < 5; i++) {
if (!http("protected")) {
// If request fails, refresh token
http("refresh");
http("protected");
}
}
http :
- id : login
method : POST
path :
- "{{BaseURL}}/api/login"
body : '{"username":"test","password":"test"}'
extractors :
- type : json
name : jwt_token
internal : true
json :
- ".token"
- id : protected
method : GET
path :
- "{{BaseURL}}/api/data"
headers :
Authorization : "Bearer {{jwt_token}}"
- id : refresh
method : POST
path :
- "{{BaseURL}}/api/refresh"
headers :
Authorization : "Bearer {{jwt_token}}"
extractors :
- type : json
name : jwt_token
internal : true
json :
- ".token"
Best practices
Use internal matchers - Hide intermediate checks with internal: true
Extract only needed data - Use internal: true on extractors used in flow
Validate extracted values - Check if values exist before using them
Log for debugging - Use log() during development
Handle errors gracefully - Use conditional checks before executing requests
Keep flow logic simple - Complex logic can be hard to debug
Document flow logic - Add comments explaining the orchestration
Test thoroughly - Verify all execution paths work as expected
Common patterns
Conditional chaining
if ( http ( 1 ) && http ( 2 )) {
http ( 3 );
}
Loop with condition
for ( let item of template [ "items" ]) {
set ( "item" , item );
if ( http ()) {
break ; // Stop on first match
}
}
Retry logic
let success = false ;
let retries = 3 ;
while ( ! success && retries > 0 ) {
success = http ();
retries -- ;
}
Multiple protocol orchestration
ssl ();
dns ();
if ( template [ "ssl_subject_cn" ] || template [ "ptr_record" ]) {
http ();
}
Workflows Multi-template workflows
Variables Template context
Extractors Extract dynamic values
Helper Functions DSL functions