{"id":"CVE-2026-49756","aliases":["GHSA-px9f-whj3-246m"],"title":"Req vulnerable to multipart form-data header injection via unescaped name/filename/content_type","summary":"Req vulnerable to multipart form-data header injection via unescaped name/filename/content_type","severity":"medium","cwe":["CWE-93"],"vendor":"req","product":"req","ecosystem":"erlang","affected":["req >= 0.5.3, < 0.6.0"],"patched":["req 0.6.0"],"published":"2026-07-29","updated":"2026-07-29","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-px9f-whj3-246m","references":[{"url":"https://github.com/wojtekmach/req/security/advisories/GHSA-px9f-whj3-246m"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-49756"},{"url":"https://github.com/wojtekmach/req/commit/74506ff2c5addf74df85d79dc726e9b2e264a8ba"},{"url":"https://cna.erlef.org/cves/CVE-2026-49756.html"},{"url":"https://github.com/wojtekmach/req/releases/tag/v0.6.0"},{"url":"https://osv.dev/vulnerability/EEF-CVE-2026-49756"},{"url":"https://github.com/advisories/GHSA-px9f-whj3-246m"}],"tags":["ghsa","erlang"],"epss":0.00207,"epssPercentile":0.11148,"ingestedAt":"2026-07-29T15:48:25.869Z","slug":"CVE-2026-49756","body":"## Overview\n\n### Summary\n\nReq's multipart form encoder interpolates the per-part `name`, `filename`, and `content_type` directly into the part headers without escaping. An attacker who can influence any of those values can inject CRLF-separated header lines, smuggle additional form fields, or prepend a whole extra part into the request the victim service sends downstream.\n\n### Details\n\n`Req.Utils.encode_form_part/2` in `lib/req/utils.ex` builds the per-part header iodata by concatenating the three caller-supplied strings verbatim into `content-disposition: form-data; name=\"<name>\"; filename=\"<filename>\"` and `content-type: <content_type>`. There is no CRLF stripping, no quote escaping, and no validation. A value containing `\"\\r\\n` closes the surrounding quoted value and starts a new header line; an additional `\\r\\n--<boundary>` terminates the current part and lets the attacker prepend a smuggled part.\n\nThe flaw is reachable through every supported way of supplying a part. It is especially easy to hit when `value` is a `%File.Stream{}`, because `filename` then defaults to `Path.basename(stream.path)` and POSIX filenames may legitimately contain `\\r` and `\\n`. RFC 7578 / WHATWG form-data requires percent-encoding `\"`, CR, and LF in these fields; the fix adopts that behavior.\n\n### PoC\n\n1. Construct a malicious `filename` such as `harmless.txt\"\\r\\nX-Smuggled: marker\\r\\nContent-Disposition: form-data; name=\"pwned`.\n2. Call `Req.post!(url, form_multipart: [upload: {\"benign body\", filename: <malicious>, content_type: \"text/plain\"}])`.\n3. The emitted multipart body contains a real `X-Smuggled:` header line and an extra `Content-Disposition` for `name=\"pwned\"`, alongside Req's legitimate headers.\n\n### Impact\n\nHTTP request smuggling / multipart parameter smuggling in the HTTP client. Any application using Req to send `form_multipart` requests where any of `name`, `filename`, or `content_type` can be influenced by an untrusted source is affected, most commonly upload proxies and re-uploaders that derive `filename` from `Path.basename/1` on a user-controlled path.\n\n## Affected packages\n\n- `req >= 0.5.3, < 0.6.0`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `req 0.6.0`","depth":"sunlit","depthScore":28,"depthScoreParts":{"impact":27.5,"likelihood":0,"exploitation":0,"ransomware":0},"changes":[]}