Protocol parsers

Engines live

Detection engines should never have to know whether a value arrived as JSON, a form field or a SOAP node. The parsers make that true: each one understands a single wire format and flattens it into the same canonical Params, tagged with a Source.

One surface, many formats

Whatever the content type, the output is a flat list of {Source, Name, Raw} parameters. A deeply nested JSON body and a query string become the same shape of detection surface — so an SQLi engine written once works against every input location.

Parser Source tag Trigger
Query Query URL query string (always)
Form Form application/x-www-form-urlencoded body
Headers & cookies Header / Cookie allowlisted headers + cookies (gated by -scan-headers)
JSON JSON JSON body — recursive flatten with dotted / [i] paths
Multipart Multipart multipart/form-data parts
GraphQL GraphQL GraphQL query + variables
XML XML XML body — elements and attributes
SOAP SOAP SOAP envelope (always attempted)
JWT JWT bearer / JWT — decoded claims (always attempted)
WebSocket WebSocket handshake headers; frames relayed post-101

Content-type gating

The engine picks the body parser from the content type (isJSONBody, isFormBody, isMultipartBody, isGraphQLBody, isXMLBody), while a few parsers run unconditionally because their input can hide anywhere: SOAP (envelope detection) and JWT (any bearer token) are always attempted, and the query and allowlisted headers are always parsed. The JWT parser also feeds the auth engine — an alg: none token becomes a finding.

Flattening, with structure preserved

Nested structures are flattened with their path encoded in the parameter name, so structure is not lost — it becomes queryable. A JSON body

{ "user": { "roles": ["admin", "editor"] } }

flattens to params named user.roles[0], user.roles[1]. The API engine uses this to catch deep-nesting denial-of-service and mass-assignment of privilege-flag fields.

WebSocket

The WebSocket path is special: the handshake headers are parsed like any request, and if it is a genuine upgrade the connection switches to frame relay, where post-101 frames are still inspected rather than blindly tunnelled.

Built for hostile input

Every parser is zero-allocation on the hot path and fuzzed. They are written to never panic on malformed, truncated or adversarial input, and to bound their work so a pathological body cannot exhaust CPU or memory. The parser output is written into a per-request arena that is reset and reused between requests.

Status

All seven structured parsers plus urlencoded forms are built and fuzzed; the protocol-parser milestone is complete. Each parser has its own contract spec backed by test vectors.