{"id":"GHSA-x2w3-23jr-hrpf","summary":"ewe Has Improper Neutralization of CRLF Sequences in HTTP Headers (HTTP Request/Response Splitting)","details":"### Summary\n\nThe `encode_headers` function in `src/ewe/internal/encoder.gleam` directly interpolates response header keys and values into raw HTTP bytes without validating or stripping CRLF (`\\r\\n`) sequences. An application that passes user-controlled data into response headers (e.g., setting a `Location` redirect header from a request parameter) allows an attacker to inject arbitrary HTTP response content, leading to response splitting, cache poisoning, and possible cross-site scripting.\n\nNotably, ewe *does* validate CRLF in **incoming** request headers via `validate_field_value()` in the HTTP/1.1 parser — but provides no equivalent protection for **outgoing** response headers in the encoder.\n\n### Details\n\n**File:** `src/ewe/internal/encoder.gleam`\n\n**Vulnerable code:**\n```gleam\nfn encode_headers(headers: List(#(String, String))) -\u003e BitArray {\n  let headers =\n    list.fold(headers, \u003c\u003c\u003e\u003e, fn(acc, headers) {\n      let #(key, value) = headers\n      \u003c\u003cacc:bits, key:utf8, \": \", value:utf8, \"\\r\\n\"\u003e\u003e\n    })\n\n  \u003c\u003cheaders:bits, \"\\r\\n\"\u003e\u003e\n}\n```\n\nBoth `key` and `value` are embedded directly into the `BitArray` output. If either contains `\\r\\n`, the resulting bytes become a structurally valid but attacker-controlled HTTP response, terminating the current header early and injecting new headers or a second HTTP response.\n\n**Contrast with request parsing** (`src/ewe/internal/http1.gleam`): incoming header values are protected:\n```gleam\nuse value \u003c- try(\n  validate_field_value(value) |\u003e replace_error(InvalidHeaders)\n)\n```\n\nNo analogous validation exists for outgoing header values in the encoder. The solution is to strip or reject `\\r` (0x0D) and `\\n` (0x0A) from all header key and value strings in `encode_headers` before encoding, mirroring the validation already applied to incoming request headers via `validate_field_value()`\n\n### PoC\n\nAn ewe application echoes a user-supplied redirect URL into a `Location` header:\n\n```gleam\nfn handle_request(req: Request) -\u003e Response {\n  let redirect_url =\n    request.get_query(req)\n    |\u003e result.try(list.key_find(_, \"next\"))\n    |\u003e result.unwrap(\"/home\")\n\n  response.new(302)\n  |\u003e response.set_header(\"location\", redirect_url)\n  |\u003e response.set_body(ewe.Empty)\n}\n```\n\nAttacker request:\n```bash\nprintf 'GET /?next=https://example.com%%0d%%0aX-Injected:%%20true HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n' | nc -w 2 localhost 8080\n```\n\nResulting response:\n```\nHTTP/1.1 302 Found\nlocation: https://example.com\nX-Injected: true\ncontent-length: 0\ndate: Tue, 24 Mar 2026 07:53:00 GMT\nconnection: keep-alive\n\n\n```\n\nThe `X-Injected: true` header appears as a separate response header, confirming that CRLF sequences in user input are not sanitized by the encoder.","aliases":["CVE-2026-34715"],"modified":"2026-04-06T17:37:59.740306Z","published":"2026-04-01T22:18:27Z","database_specific":{"severity":"MODERATE","nvd_published_at":"2026-04-02T18:16:32Z","github_reviewed_at":"2026-04-01T22:18:27Z","github_reviewed":true,"cwe_ids":["CWE-113"]},"references":[{"type":"WEB","url":"https://github.com/vshakitskiy/ewe/security/advisories/GHSA-x2w3-23jr-hrpf"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-34715"},{"type":"WEB","url":"https://github.com/vshakitskiy/ewe/commit/ce4ff214d32626a10fda9398dc94a2d720e17446"},{"type":"PACKAGE","url":"https://github.com/vshakitskiy/ewe"},{"type":"WEB","url":"https://github.com/vshakitskiy/ewe/releases/tag/v3.0.6"}],"affected":[{"package":{"name":"ewe","ecosystem":"Hex","purl":"pkg:hex/ewe"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"3.0.6"}]}],"versions":["0.0.1","0.0.2","0.1.0","0.10.0","0.2.0","0.3.0","0.4.0","0.5.0","0.6.0","0.7.0","0.8.0","0.8.1","0.9.0","1.0.0","1.0.0-rc1","1.0.0-rc2","1.0.1","2.0.0","2.0.1","2.0.2","2.0.3","2.1.0","2.1.1","2.1.2","2.1.3","3.0.0","3.0.1","3.0.2","3.0.3","3.0.4","3.0.5"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-x2w3-23jr-hrpf/GHSA-x2w3-23jr-hrpf.json"}}],"schema_version":"1.7.5","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N"}]}