Skip to content

fuzz_http

Synchronously fuzz an HTTP request with HTTPMessage-typed positions. The schema mirrors resend_http plus a positions[] list -- each position is a typed path into the HTTPMessage shape. The cartesian product of all positions yields the variant sequence.

This tool is synchronous: it runs every variant in-process and returns the full per-variant result list when finished. There is no concurrency or rate limit -- pace from the client side. For larger asynchronous fuzz campaigns the legacy runner is being phased out in N9; this tool replaces it for typed HTTP fuzzing.

Limits

  • Maximum variants per call: 1000 (cartesian product across all positions)
  • Maximum positions per call: 32
  • Maximum decoded payload size per position: 1 MiB

Each variant is executed sequentially with a fresh dial. Per-variant SafetyFilter input gating runs after position substitution, before the upstream dial -- a blocked variant is recorded with error and the run continues.

Parameters

fuzz_http inherits every base field from resend_http (flow_id, method, scheme, authority, path, raw_query, headers, body, body_encoding, body_set, body_patches, override_host, tls_fingerprint, timeout_ms, tag).

Parameter Type Required Default Description
(base fields) -- -- -- See resend_http. When flow_id is empty, method, scheme, authority, path are required
positions array Yes Ordered position list (see below). At least one entry
stop_on_5xx boolean No false Abort remaining variants once any variant returns a 5xx response

positions

Each position substitutes one typed path into the HTTPMessage shape:

Field Type Required Default Description
path string Yes Typed path: method, scheme, authority, path, raw_query, body, headers[N].name, headers[N].value
payloads string[] Yes List of values to substitute at this path. At least one element
encoding string No "text" "text" or "base64". Applies to every payload

Position payloads are written verbatim, including CR/LF. This is intentional: fuzz_http is the surface for request smuggling, header injection, and CRLF-injection fuzzing. The base-headers path still rejects CR/LF by design; per-position payloads bypass that guard.

Response

Field Type Description
total_variants integer Total variant count from the cartesian product
completed_variants integer Variants actually executed before completion or stop
stopped_reason string Empty when all variants ran; "stop_on_5xx: ..." or "ctx cancelled: ..." otherwise
variants array Per-variant result rows (see below)
duration_ms integer Total run duration in milliseconds
tag string Echo of the supplied tag (when set)

Each variant row:

Field Type Description
index integer Variant index (zero-based, in execution order)
stream_id string New stream record id under which RecordStep persisted the variant's flows
status_code integer HTTP response status code (0 if the variant errored)
body_size integer Response body byte length
payloads object Map of position path -> decoded payload string for this variant
error string Error message when the variant failed (network, timeout, SafetyFilter)
duration_ms integer Per-variant duration

Full response payloads are not stored on the row. Retrieve them via the query tool keyed by stream_id.

Pipeline placement

Each variant traverses the same self-contained PluginStepPost -> RecordStep pipeline as resend_http (PluginStepPre is bypassed per RFC-001 §9.3).

Job and result persistence

Synchronous fuzz runs persist a row to fuzz_jobs (status "running") and one row per variant to fuzz_results, so query with resource = "fuzz_jobs" and resource = "fuzz_results" can list and aggregate variants (status-code distribution, outliers, body filters) after the call returns. Per-variant flows carry origin = "fuzz" so analyses can exclude them from live capture via query filter.origin = "proxy".

Examples

Fuzz a path segment

// fuzz_http
{
  "flow_id": "abc-123",
  "positions": [
    {
      "path": "path",
      "payloads": ["/admin", "/admin/", "/Admin", "/.git/config"]
    }
  ]
}

Two-position cartesian product

// fuzz_http
{
  "flow_id": "abc-123",
  "positions": [
    {"path": "headers[0].value", "payloads": ["Bearer A", "Bearer B"]},
    {"path": "body", "payloads": ["{\"role\":\"user\"}", "{\"role\":\"admin\"}"]}
  ],
  "stop_on_5xx": true
}

CRLF smuggling fuzz

// fuzz_http
{
  "flow_id": "abc-123",
  "positions": [
    {
      "path": "raw_query",
      "payloads": [
        "x=1\r\nX-Forwarded-For: 127.0.0.1",
        "x=1\r\nTransfer-Encoding: chunked"
      ]
    }
  ]
}