Skip to content

Chain steps

Protocol steps (HTTP, SMTP, IMAP, LDAP, DNS, SpamAssassin, Kerberos, SMB, MySQL, MongoDB, PostgreSQL, SQL Server, Redis, FTP, Freestyle) are added by picking an existing probe from the probe picker dialog.

After selecting a probe, the step is either linked to that probe or holds a copy of its configuration, described under Linked and copied steps below. The step name defaults to ProjectName / ProbeName, and the original probe is not modified either way.

Each step can have extractors attached. See Extractors.

Steps run from the top of the list, one after another, and the number beside each step is the position it will run in.

Move a step with the up and down buttons in its header.

Ordering applies to top-level steps. A step inside an ITERATE, CONDITION or PARALLEL block has no position of its own: a parallel block starts all of its children at once, a condition runs one branch or neither of them, and an iteration runs each child once per item.

A step added from a probe is either linked to that probe or a copy of it, and the chip in the step header says which.

A linked step runs the probe’s latest saved version, so editing the probe reaches every chain that links to it. Edits made in the step itself are ignored when it runs.

A copy is a snapshot taken when the step was added. Edit it inside the chain without touching the probe.

The chip opens a menu to move between the two. Detach to copy turns a linked step into an editable copy, Convert to link goes the other way, and Sync from original refreshes a copy from the probe as it stands now. This is available on every step built from a probe, including one nested inside a container.

ITERATE is a container step that executes its child steps once for each item in a list. It supports two payload sources, optional rate control, and configurable stop conditions.

Define the values directly in the step editor, one value per line. This is the most common mode when the list is known upfront.

ITERATE step: static list source with values entered one per line

Read items from a text file on the server’s filesystem. Each non-blank line becomes one iteration item. Useful for large wordlists or credential files that would be impractical to paste inline.

ITERATE step: file source selected with file path field

The path is resolved relative to the server’s working directory, or you can use an absolute path.

FieldDescription
SourceInline list or File
Item variable nameThe variable name injected for each item inside child steps
Values(Inline only) Items to iterate, one per line
File path(File only) Absolute or relative path to the wordlist on the server
Min delay (ms)Minimum pause between iterations. 0 = no delay
Max delay (ms)Maximum pause between iterations, randomized between min and max
Max failuresStop after this many failed iterations. Leave blank for unlimited
Stop on first successWhen enabled, the loop continues past failed iterations and stops as soon as one iteration’s child steps all pass. The overall step result is success if a match is found, failure if the list is exhausted

The current item is injected as {{yourItemVarName}} into all child steps. Variables produced by child steps accumulate in the shared context; after the loop finishes, the last iteration’s values are visible to subsequent steps.

CONDITION evaluates a boolean expression, in JavaScript or Groovy, and executes one of two child step lists depending on the result. New CONDITION steps start in JavaScript; the language is chosen per step. All {{variable}} placeholders in the expression are resolved before evaluation.

CONDITION step: expression field with then and else branches

FieldDescription
ExpressionAn expression that evaluates to a boolean, e.g. {{status}} == '200' or {{count}}.toInteger() > 0
Then branchSteps to execute if the expression is true
Else branchSteps to execute if the expression is false (can be empty)

The branch taken is shown in the execution results. Variables produced by the executed branch are available to subsequent steps.

PARALLEL executes all child steps simultaneously using a thread pool. Each branch receives a snapshot of the current variable context; after all branches complete their extracted variables are merged back (last-writer-wins on name collision).

PARALLEL step: child steps listed for simultaneous execution

Add branches using Add Branch (opens the probe picker) or the Print button. Each branch is a single step, so use a CHAIN_REF or ITERATE inside the branch if you need multi-step logic.

CHAIN_REF calls another chain as a sub-routine. Variable context does not flow automatically. You map values in and results out explicitly.

CHAIN_REF step: sub-chain selector with input and output variable mapping

Map variables from the parent context into the sub-chain. Each row is:

ColumnDescription
Child variableThe variable name the sub-chain will see
Value / expressionA literal value or a {{parentVarName}} reference resolved from the parent context

Map variables from the sub-chain back to the parent context. Each row is:

ColumnDescription
Child variableThe variable name produced by the sub-chain
Parent variable nameThe variable name to assign in the parent context

A sub-chain that fetches an LDAP entry and extracts dn and mail:

Input vars:

Child variableValue
filter(uid={{username}})

Output vars:

Child variableParent variable name
dnldap_dn
mailuser_email

After the CHAIN_REF step, {{ldap_dn}} and {{user_email}} are available in the parent chain.

PRINT writes a line to the execution log. The template can contain any text mixed with {{variable}} references. Every variable resolved so far in the chain is available.

PRINT step: output template field with variable references

FieldDescription
Output templateFree-form text with {{variable}} placeholders, e.g. POST returned {{postId}}, title: {{postTitle}}

PRINT always succeeds and produces no extracted variables of its own. It is mainly useful for debugging a chain’s variable state mid-execution.

Runs a saved script as a step. Pick the script from the list of scripts in the active project.

The script sees every variable the chain has so far, and hands values back with vp.set. Those become chain variables, so a later step reads them as {{name}} like anything else. The step panel lists what the script exports, read out of its source, so you can see what it hands on before you run anything.

def result = vp.send("Orders", "Create order")
vp.set("orderId", result.extract("HTTP_JSON_PATH", "$.id"))
vp.check("order was created", result.isSuccess())

A vp.check that fails fails the step and the chain, and its verdicts count toward the chain’s assertion total, so a chain whose only check lives in a script is still a tested chain.

The Extra variables rows hand the script values under names of your choosing, on top of the chain’s own. The right hand side takes {{placeholders}} or a literal, resolved before the script starts.

Use them when the script should not have to know the chain’s variable names.

Each SCRIPT step shows what the script exported, as name and value, next to the step in the run results. A failed check shows what it wanted and what it got.

Scripts require the Engineering tier or above. Building a chain that contains one is not gated; running it is.

ASSERT checks that a variable’s value satisfies a condition. If the condition is false, the chain stops and the step is marked as failed.

ASSERT step: variable field, operator dropdown, and expected value field

FieldDescription
VariableName of the variable to check (resolved from chain context)
OperatorComparison operator
ExpectedThe value to compare against, supporting {{variable}} references
OperatorMeaning
EQUALSExact string match
NOT_EQUALSNot an exact string match
CONTAINSExpected is a substring of actual
NOT_CONTAINSExpected is not a substring of actual
MATCHESActual matches the regex in Expected
GT / LTNumeric greater/less than
GTE / LTENumeric greater/less than or equal

Use ASSERT to enforce postconditions after a probe step, for example checking that a status code variable equals "200" before proceeding to the next step.