Skip to main content

HTTP Request Smuggling (desync shapes)

First-party proxy, forwarding, or hand-rolled HTTP parsing code lets a front-end and a back-end disagree about where one request ends and the next begins. An attacker uses that disagreement to prepend bytes to somebody else's request, which is how a desync turns into credential theft or cache poisoning.

What Vulkro detects

Two deterministic shape rules, both Medium, over the project's own source. Neither is a taint proof and neither is a live desync test.

SMUGGLE-001 (Medium) fires when a reverse-proxy or forwarding path copies a client-supplied Transfer-Encoding header onto the outbound upstream request, for example inside a httputil.ReverseProxy Director or a manual passthrough loop. The message calls out the higher-risk case where both Transfer-Encoding and Content-Length are forwarded. A proxy that strips hop-by-hop headers (Header.Del("Transfer-Encoding")) never matches, and a proxy context is required so an ordinary Content-Length write is not flagged.

SMUGGLE-002 (Medium, heuristic) fires on a hand-rolled HTTP parser that reads Content-Length off a raw connection (bufio.NewReader, ReadString, a manual header loop) and parses it to an integer with no visible guard rejecting a duplicate or conflicting Content-Length / Transfer-Encoding. A parser that already mentions a duplicate or ambiguity guard is skipped.

Scope: this detector only reasons about first-party source shapes. The library-version half of the risk (a vulnerable stdlib or proxy dependency) belongs to the dependency scan, not here.

Remediation. Strip hop-by-hop headers before forwarding, and let one component own request framing: never re-send a client Transfer-Encoding. In a hand-rolled parser, reject a request carrying more than one Content-Length, or both Content-Length and Transfer-Encoding, with a 400 rather than picking a winner.

Non-compliant code (examples)

Go - proxy forwards the client's Transfer-Encoding

proxy.Director = func(req *http.Request) {
req.Header.Set("Transfer-Encoding", clientReq.Header.Get("Transfer-Encoding"))
req.Header.Set("Content-Length", clientReq.Header.Get("Content-Length"))
}

Compliant code (examples)

Go - hop-by-hop headers dropped, framing left to the client library

proxy.Director = func(req *http.Request) {
req.Header.Del("Transfer-Encoding")
req.Header.Del("Connection")
// net/http sets the framing headers itself from req.Body / ContentLength
}

See also

  • Confidence model - what High, Medium, and Low mean for findings in this category.
  • Safety - what Vulkro does and does not access on your machine.

References


This page is generated by vulkro rules export <out-dir> from Vulkro's built-in detector catalogue. Edits made by hand are overwritten on the next regeneration.