GHSA-gcq2-9pq2-cxqm http-proxy-middleware: multipart/form-data field injection via unescaped CRLF in `fixRequestBody`
Summary`fixRequestBody()` is the library's documented helper for re-emitting a request body that was already consumed by a body parser. When the **outgoing** `Content-Type` is `multipart/form-data`, it rebuilds the body with `handlerFormDataBodyData()`, which interpolates each `req.body` key and value directly into the multipart wire format **without neutralizing CR/LF**:A `\r\n` inside a value (or key) lets an attacker close the current part and inject an **entirely new form part**. Because the proxy's own body parser saw a single opaque value, any gateway-side policy or validation performed on `req.body` is evaluated against a different set of fields than the upstream backend ultimately parses a request/parameter desynchronization across the trust boundary.By contrast, the sibling output branches are safe: `application/json` uses `JSON.stringify` (escapes control chars) and `application/x-www-form-urlencoded` uses `querystring.stringify` (percent-encodes). Only the multipart branch lacks escaping.PreconditionsAll three must hold; this narrows real-world exposure and is the basis for `AC:H`:The proxy app populates `req.body` with a **non-multipart** parser (`express.urlencoded`, `express.json`, or text) so an injected boundary in a value is **not** split on input.The proxied (outgoing) request is sent as **`multipart/form-data`** (e.g. an adaptation layer, or any flow that sets the upstream content-type to multipart), so the vulnerable branch runs.The app calls `fixRequestBody` (the documented pattern for "I body-parsed, now re-stream"), and an attacker controls at least one body field value or key.Note: a pure multipart-in → multipart-out flow (e.g. `multer`) is generally **not** exploitable for a *new-field* injection, because the proxy's multipart parser already splits the injected boundary, so `req.body` and the backend agree. The desync specifically requires a non-multipart input parser.ImpactWhen the preconditions hold, an attacker injects/overrides multipart fields seen only by the backend:**Validation / access-control bypass** bypass gateway-side field checks (demonstrated below: a gateway that forbids `role=admin` is bypassed; backend grants admin).**Parameter tampering** add or overwrite fields the backend trusts (IDs, flags, prices).**File-part injection** inject a `filename="..."` part into the upstream multipart stream.Proof of ConceptOutput: one input field becomes **two** parts; `role=admin` was injected via the unescaped CRLF:`req.body` had a single key (`user`), so any gateway policy checking `req.body.role` passes, yet the backend's multipart parser receives `role=admin`. On the wire the attacker simply sends, as `application/x-www-form-urlencoded`: `user=alice%0D%0A--BB%0D%0AContent-Disposition:%20form-data;%20name="role"%0D%0A%0D%0Aadmin%0D%0A--BB--`RemediationNeutralize CR/LF (and `"`) in keys/values before interpolation, or build the body with a real multipart encoder (e.g. `FormData` / `form-data`) instead of string concatenation. Minimal fix:(Reject is preferable to silent stripping, to avoid masking malicious input.)
CVSS v3.1 score: 7.5