Node.js Security Fix Silently Broke node-fetch, which broke other tools
On June 18, 2026, Node.js released updates for its active release lines, including Node 22.23.0 (LTS) and Node 24.17.0. These releases contained security patches, notably a fix for a Response Queue Poisoning vulnerability in http.Agent.
After that, our development pipeline began failing. We detected it first thanks to our End-To-End tests. The error looked like this:
FetchError: Invalid response body while trying to fetch https://...: Premature close
code: 'FetchError',
type: 'system',
errno: 'ERR_STREAM_PREMATURE_CLOSE'It first looked like a transient network issue, so we debugged it by starting various connectivity checks. Turns out, a security patch in the Node.js core triggered a latent false-positive guard in a widely used, legacy HTTP wrapper.
Here is a short “What happend”, since it starts to gain traction in the community.
Root Cause Chain
1. Node.js Socket Retention
To patch a security vulnerability related to request smuggling and response queue poisoning, Node.js core modified the behavior of http.Agent (specifically this commit).
Historically, when an HTTP response completed, certain internal socket data listeners were detached. The security fix altered this lifecycle: a socket data listener now remains attached after the response completes to ensure the socket state is cleanly managed and tracked. From a pure HTTP networking perspective, this behavior is valid.
2. Downstream Trigger: node-fetch@2 False Positive
node-fetch@2 (and libraries wrapping it, like cross-fetch@4 or Google’s gaxios) contains a safety check designed to catch incomplete streams.
The library inspects the underlying socket to see if any data listeners are still attached after the response stream signals completion.
Before Node 22.23.0: No listeners remained →
node-fetchassumed the stream completed successfully.After Node 22.23.0: The socket listener is still present →
node-fetchmistakenly interprets this as an aborted or interrupted stream, aborts the operation, and throwsERR_STREAM_PREMATURE_CLOSE.
3. How the bug is triggered
Currently it looks like it is not triggered on every HTTP call, but when you meet this conditions:
HTTPS/TLS Connection
Chunked Transfer Encoding
Compression enabled
HTTP Keep-Alive keeping the socket open for reuse
If this happens, the problem should occur.
This bug breaks, even if you haven’t change a single line of code
A pipeline that passed cleanly on June 17 was broken on June 19.
# DOCKERFILE
FROM node:22-alpineBecause you often rely on floating tags (like node:24-alpine or lts/jod in .nvmrc), automatic CI/CD environments pull a fresh NodeJs image, containing the security fix but triggering the bug.
Impact
NodeJs Issue
See this GitHub Issue for more details in the NodeJs repository.
Firebase CLI (firebase-tools)
See this GitHub Issue for more details in the Firebase-Tools repository.
About node-fetch@2
node-fetch@2 is effectively unmaintained and will not receive a patch for this modern socket behavior. If your application relies on older SDKs that bundle it, the cleanest path forward is to bypass the polyfill layer entirely and adopt Node's native fetch global (built on undici), which does not rely on the legacy http.Agent infrastructure

