Vulnerability DatabaseGHSA-gc9w-7pvq-86rr

GHSA-gc9w-7pvq-86rr: 
JavaScript vulnerability analysis and mitigation

Summary

When proxy-chain forwards a plain-HTTP request (every non-CONNECT proxy request goes through forward(), or forwardSocks() when the upstream is SOCKS), it fetches the origin response with Node's HTTP client explicitly set to lenient parsing (insecureHTTPParser: true), then rebuilds the downstream response: it strips the Transfer-Encoding header (hop-by-hop filter) while keeping the origin's Content-Length header verbatim, and pipes the full dechunked body into the client-facing response. A malicious origin (any http:// URL the proxy client requests — the core use case of a crawling proxy) that sends a response carrying both Transfer-Encoding: chunked and a smaller Content-Length: N gets:

  1. accepted by the lenient parser (Node's default strict parser rejects this with HPE_INVALID_TRANSFER_ENCODING — the insecureHTTPParser: true flag is what disarms that protection),
  2. re-serialized to the proxy's downstream client as Content-Length: N + the entire dechunked body (which exceeds N), on a keep-alive connection. The bytes beyond position N are attacker-chosen and are parsed by the downstream client's HTTP stack as the response to its next request on that proxied connection. Because proxied HTTP/1.1 connections are per-proxy (requests use absolute-form and target arbitrary origins over one socket), the forged response can be served for a request to any origin, not just the attacker's — cross-origin response forgery / response splitting. Verified locally with Node 22 (same llhttp family as the supported Node >= 20.11):
  • lenient client: accepts TE+CL response, rawHeaders keep both headers, body delivered = full dechunked length;
  • downstream composition used by forward() (writeHead with array headers incl. stale content-length, then pipeline(body, response)): all body bytes reach the wire despite the smaller declared Content-Length, connection stays keep-alive, and the smuggled HTTP/1.1 200 OK ... bytes answered a subsequent request sent on the same connection.

Details

  • Package: proxy-chain (npm), Apache-2.0, by Apify — used by Apify Proxy, Crawlee, and anyone routing Puppeteer/Playwright through an authenticated proxy.
  • Affected versions: all 2.x and 3.x releases before 3.0.3. Fixed in 3.0.3 (#744): the upstream Content-Length is no longer forwarded when the response carried a Transfer-Encoding header (RFC 9112 §6.3), so the client response is framed as chunked.
  • Class: HTTP response splitting / smuggling (CWE-444 — Improper Neutralization of HTTP Wrapper; specifically Inconsistent Interpretation of HTTP Requests/Responses).
  • CVSS 3.1: 8.2 HIGH — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N (crawler/server-side deployment, the library's flagship use). A browser-user deployment scores the same 8.2 with UI:R/S:C.

Proof of concept

Attacker input: the HTTP response returned by an origin server / upstream proxy for a plain-HTTP request the proxy client made (attacker = controls any http:// origin the client is directed to; no auth against the attacker is needed — proxy auth, if any, is against the client).

  1. src/server.ts:363 — onRequest() handles every non-CONNECT proxy request.
  2. src/server.ts:382-383 — no SOCKS upstream → await forward(request, response, handlerOpts) (SOCKS upstream → forwardSocks() at src/server.ts:376-379, same pattern, see step 8).
  3. src/forward.ts:59-66 — outbound request built; src/forward.ts:62 insecureHTTPParser: true → response parsing is lenient; TE+CL responses are accepted instead of rejected (strict Node rejects: HPE_INVALID_TRANSFER_ENCODING).
  4. src/forward.ts:116-126 — http.request(origin, options, requestCallback); origin response (clientResponse) carries rawHeaders = [..., 'Transfer-Encoding', 'chunked', 'Content-Length', N] and a dechunked stream longer than N.
  5. src/forward.ts:82 — requestCallback(clientResponse) invoked with the attacker-controlled response.
  6. src/forward.ts:96-100 — response.writeHead(statusCode, statusMessage, validHeadersOnly(clientResponse.rawHeaders)).
  7. src/utils/valid_headers_only.ts:24-26 (with src/utils/is_hop_by_hop_header.ts:8) — the hop-by-hop filter drops Transfer-Encoding and keeps Content-Length: N; no code reconciles N with the actual body length, and nothing forces Connection: close on framing mismatch.
  8. src/forward.ts:103-106 — await pipeline(clientResponse, response) streams the entire dechunked body under the stale Content-Length: N onto the downstream keep-alive socket. Bytes past N are the attacker's smuggled response. (Identical sink in src/forward_socks.ts:48 lenient flag, :69-73 writeHead, :76-79 pipeline.) Sink: the proxy's client-facing socket (response / srcResponse) — the smuggled bytes are parsed by the downstream client as the response to its next pipelined request on that connection.

Impact

Boundary crossed: origin-server → proxy-client response integrity. A malicious web server reached through the proxy can forge the HTTP response the proxy's client receives for a later request to any origin routed over the same proxied connection: content spoofing/injection for arbitrary origins, poisoning of client-side HTTP caches, cookie/session injection (Set-Cookie for other origins), XSS via crafted HTML, and deceptive data fed to crawlers. For Apify/Crawlee-style shared-proxy deployments this silently corrupts the integrity guarantee the proxy exists to provide.


Source: NVD

Related JavaScript vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-mw6w-2fmv-pvw3MEDIUM5.9
  • JavaScript logoJavaScript
  • @sveltejs/kit
NoYesNov 13, 2026
GHSA-jf9x-2fg2-hx4wMEDIUM5.9
  • JavaScript logoJavaScript
  • @sveltejs/adapter-static
NoYesNov 13, 2026
GHSA-5wg4-q3ww-283hMEDIUM5.9
  • JavaScript logoJavaScript
  • @sveltejs/adapter-cloudflare
NoYesNov 13, 2026
GHSA-rqw3-x7hx-mm3pMEDIUM5.9
  • JavaScript logoJavaScript
  • @sveltejs/adapter-node
NoYesNov 13, 2026
CVE-2026-128123MEDIUM5.9
  • JavaScript logoJavaScript
  • @sveltejs/adapter-node
NoYesNov 13, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Additional Wiz resources

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management