{"id":"CVE-2026-34715","aliases":["EUVD-2026-18468","GHSA-x2w3-23jr-hrpf"],"status":"published","title":"ewe Has Improper Neutralization of CRLF Sequences in HTTP Headers (HTTP Request/Response Splitting)","description":"ewe is a Gleam web server. Prior to version 3.0.6, the 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. Notably, 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. This issue has been patched in version 3.0.6.","severity":{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-10","score":0.0034,"percentile":0.27739,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-113"],"published":"2026-04-01T22:18:27Z","modified":"2026-10-28T02:30:41Z","fixes":[{"ecosystem":"Hex","package":"ewe","fixed_in":["3.0.6"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Hex","package":"ewe","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3.0.6"}]}]},{"source":"osv","ecosystem":"Hex","package":"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"]}],"products":[{"vendor":"vshakitskiy","product":"ewe"}],"references":[{"url":"https://github.com/vshakitskiy/ewe/security/advisories/GHSA-x2w3-23jr-hrpf","tags":["x_refsource_CONFIRM","exploit","Exploit","Vendor Advisory","advisory","web"]},{"url":"https://github.com/vshakitskiy/ewe/commit/ce4ff214d32626a10fda9398dc94a2d720e17446","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://github.com/vshakitskiy/ewe/releases/tag/v3.0.6","tags":["x_refsource_MISC","Product","Release Notes","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-34715","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-x2w3-23jr-hrpf"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/34xxx/CVE-2026-34715.json","tags":["advisory"]},{"url":"https://github.com/vshakitskiy/ewe","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-34715","title":"ewe Has Improper Neutralization of CRLF Sequences in HTTP Headers (HTTP Request/Response Splitting)","description":"ewe is a Gleam web server. Prior to version 3.0.6, the 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. Notably, 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. This issue has been patched in version 3.0.6.","status":"published","published":"2026-04-02T17:57:00.501Z","modified":"2026-04-03T16:00:41.121Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","level":"medium","assessor":"cna"}],"cwes":["CWE-113"],"updated_at":"2026-11-02T14:20:14.302133Z"}],"euvd":[{"id":"EUVD-2026-18468","description":"ewe is a Gleam web server. Prior to version 3.0.6, the 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. Notably, 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. This issue has been patched in version 3.0.6.","status":"published","published":"2026-04-02T17:57:00Z","modified":"2026-04-03T16:00:41Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","level":"medium"}],"updated_at":"2026-11-02T19:25:16.92155Z"}],"ghsa":[{"id":"GHSA-x2w3-23jr-hrpf","title":"ewe Has Improper Neutralization of CRLF Sequences in HTTP Headers (HTTP Request/Response Splitting)","description":"### 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.","status":"published","published":"2026-04-01T22:18:27Z","modified":"2026-04-06T17:25:11Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","level":"medium"}],"cwes":["CWE-113"],"updated_at":"2026-11-02T14:39:48.966685Z"}],"nvd":[{"id":"CVE-2026-34715","description":"ewe is a Gleam web server. Prior to version 3.0.6, the 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. Notably, 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. This issue has been patched in version 3.0.6.","status":"published","published":"2026-04-02T18:16:32.91Z","modified":"2026-07-24T21:10:00.143Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","level":"medium","assessor":"secondary"},{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","level":"medium","assessor":"primary"}],"cwes":["CWE-113"],"updated_at":"2026-11-02T14:12:12.73929Z"}],"osv":[{"id":"CVE-2026-34715","title":"ewe Has Improper Neutralization of CRLF Sequences in HTTP Headers (HTTP Request/Response Splitting)","description":"ewe is a Gleam web server. Prior to version 3.0.6, the 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. Notably, 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. This issue has been patched in version 3.0.6.","status":"published","published":"2026-04-02T17:57:00.501Z","modified":"2026-10-28T02:30:41.052452636Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","level":"medium"}],"cwes":["CWE-113"],"updated_at":"2026-11-02T15:45:02.247031Z"},{"id":"GHSA-x2w3-23jr-hrpf","title":"ewe Has Improper Neutralization of CRLF Sequences in HTTP Headers (HTTP Request/Response Splitting)","description":"### 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.","status":"published","published":"2026-04-01T22:18:27Z","modified":"2026-04-06T17:37:59.740306Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","level":"medium"}],"cwes":["CWE-113"],"updated_at":"2026-11-02T15:46:59.484835Z"}]}}
