Hi,
The following vulnerabilities were published for node-undici.
CVE-2026-18149[0]:
| undici's retry handler can leave an already-exposed response body
| pending forever. When a server returns a successful response that
| declares a Content-Length, sends only part of the body, and closes
| the connection, the retry handler retries the request. If the retry
| returns a non-retryable status such as 400, the handler forwards
| that new response downstream and replaces its internal response
| stream, but the original response body that the application still
| holds is never ended or destroyed. As a result calls that read that
| body never settle, and the configured body timeout does not fire
| because its timer is tied to the connection parser rather than the
| orphaned body. An attacker-controlled server can trigger this with
| two short responses without keeping a connection open, and repeated
| requests accumulate pending promises and streams that can exhaust
| application concurrency or memory. This affects undici versions from
| 7.11.0 up to 7.29.1 and from 8.0.0 up to 8.10.2. Users should
| upgrade to undici 7.29.1 or 8.10.2.
CVE-2026-18540[1]:
| undici's retry interceptor can append the body of a ranged retry
| response to bytes already delivered from an earlier partial response
| while still presenting the original response's status and headers.
| This happens when an upstream server delivers part of a body without
| a trustworthy resume checkpoint, for example a non-success response
| whose headers were already sent or a partial-content response with
| an unusable content range, then closes the connection and answers
| the resumed range request with more bytes. As a result the response
| body can be longer than the Content-Length that the application
| observes. An application that relays such a response to a downstream
| HTTP/1.1 peer without normalizing the framing can emit a body that
| exceeds the forwarded Content-Length, and the excess bytes can be
| interpreted as the start of a following response, which enables
| downstream response splitting or desynchronization. Exploitation
| requires an attacker-controlled upstream server and an application
| that forwards the response through a framing-sensitive path. This
| affects undici versions before 6.28.1, from 7.0.0 up to 7.29.1, and
| from 8.0.0 up to 8.10.2. Users should upgrade to undici 6.28.1,
| 7.29.1, or 8.10.2.
CVE-2026-19534[2]:
| undici's WebSocket client crashes the whole Node.js process during
| the opening handshake when a server responds with a subprotocol that
| the client never requested. A default WebSocket connection sends no
| subprotocol, but if the server's 101 response includes a Sec-
| WebSocket-Protocol header, undici dereferences a null value while
| checking it against the requested list and throws an uncaught
| TypeError. Because that code runs inside a microtask with no
| surrounding error handling, the exception propagates and terminates
| the process under Node's default behavior, instead of gracefully
| failing the connection as required by the WebSocket protocol. Any
| application that opens a WebSocket to an attacker-controlled or
| compromised server, or over a plaintext connection subject to a
| machine-in-the-middle, can be crashed remotely without
| authentication in the default configuration. This affects undici
| versions from 6.7.0 up to 6.28.1, from 7.0.0 up to 7.29.1, and from
| 8.0.0 up to 8.10.2. Users should upgrade to undici 6.28.1, 7.29.1,
| or 8.10.2.
CVE-2026-84890[3]:
| undici's decompress interceptor decompresses response bodies
| according to the untrusted Content-Encoding header. While the number
| of content-encoding layers is capped, the total decompressed output
| size is unbounded and there is no configuration option to limit it.
| A malicious or faulty upstream can therefore return a small
| compressed payload, a compression bomb, that expands to hundreds of
| megabytes or more in client memory, an asymmetric resource
| consumption that can exhaust memory and crash the process. This
| affects undici versions from 7.15.0 up to 7.29.1 and from 8.0.0 up
| to 8.10.2. Users should upgrade to undici 7.29.1 or 8.10.2.
CVE-2026-84933[4]:
| undici's cache interceptor does not handle the Set-Cookie response
| header anywhere in its cache path, so it neither refuses to store
| nor strips that header. In shared cache mode, which is the default,
| an otherwise cacheable response that carries a Set-Cookie header,
| for example one marked with a public and max-age directive, is
| stored and then re-served to a later caller that matches the same
| cache key. As a result one caller's cookie is disclosed to a
| different caller, and an untrusted server can inject cookies into
| cached responses served to all subsequent callers. This violates the
| requirement that a shared cache must not store cookies. This affects
| undici versions from 7.0.0 up to 7.29.1 and from 8.0.0 up to 8.10.2.
| Users should upgrade to undici 7.29.1 or 8.10.2.
CVE-2026-84947[5]:
| undici's dump interceptor reads and discards a response body up to a
| configurable maximum size. When a response declares a Content-Length
| that exceeds the maximum, the interceptor aborts cleanly, but when a
| response has no Content-Length and is chunked, the interceptor
| instead signals completion early once the accumulated size reaches
| the maximum, without pausing or aborting the request. Because the
| underlying parser keeps delivering body bytes, a second completion
| signal fires and trips an internal assertion, which aborts the
| request and tears down the connection. The application is left
| observing a misleading successful status with an empty or truncated
| body while the connection has actually been disconnected. This
| affects undici versions from 7.1.0 up to 7.29.1 and from 8.0.0 up to
| 8.10.2. Users should upgrade to undici 7.29.1 or 8.10.2.
CVE-2026-84961[6]:
| undici's BalancedPool constructor passes its entire options object
| through an internal deep-clone that serializes and reparses the
| value as JSON. Because JSON cannot represent functions, any
| function-valued TLS option, such as a caller-supplied
| checkServerIdentity callback or a custom connector inside the
| connect option, is silently discarded before it reaches the TLS
| layer. As a result a peer whose certificate the application's custom
| checkServerIdentity was written to reject, but which still passes
| Node's default hostname and chain checks, is accepted when reached
| through BalancedPool. The Client, Pool, and Agent dispatchers are
| not affected because they extract the connect and tls options before
| cloning. This affects undici versions from 7.24.1 up to 7.29.1 and
| from 8.0.0 up to 8.10.2, and only when the application supplies a
| function-valued connect or tls option to BalancedPool. Users should
| upgrade to undici 7.29.1 or 8.10.2.
CVE-2026-85008[7]:
| undici's cache interceptor documents that only safe HTTP methods are
| cached, but its logic to skip caching is built by subtracting the
| configured methods from the set of safe methods, so an unsafe method
| such as POST, PUT, or DELETE is never placed in the skip list and
| instead falls through to the full cache-read path. The response-
| storage gate also lacked a method check, so a response to an unsafe
| request that is heuristically cacheable or carries an explicit
| Cache-Control directive is stored and later replayed from cache.
| Because response headers from a remote origin are untrusted, an
| origin can answer once with a cacheable status and then have the
| client's own subsequent state-changing requests to that path served
| from the stale cache entry without ever reaching the origin, an
| integrity failure that occurs under the interceptor's default
| configuration. This affects undici versions from 7.0.0 up to 7.29.1
| and from 8.0.0 up to 8.10.2. Users should upgrade to undici 7.29.1
| or 8.10.2.
CVE-2026-85014[8]:
| undici's experimental WebSocketStream client crashes the whole
| Node.js process when a remote peer closes the TCP connection without
| a WebSocket close handshake. On an unclean close the internal
| socket-close handler calls abort on the writable stream
| unconditionally and discards the returned promise, but per the
| WHATWG Streams standard aborting a locked writable returns a promise
| that rejects with a TypeError. Because the application holds a
| writer on that writable, which is the only way to write, the
| rejection is never observed and Node's default unhandled-rejection
| behavior terminates the process. An untrusted server can therefore
| crash a client with a single abrupt disconnect, with no
| authentication and no application mistake. This affects undici
| versions from 7.0.0 up to 7.29.1 and from 8.0.0 up to 8.10.2. Users
| should upgrade to undici 7.29.1 or 8.10.2.
CVE-2026-85024[9]:
| undici bundles a WebSocket client whose permessage-deflate size-
| limit cleanup removes all listeners from the internal zlib inflate
| stream, including its error listener, while that stream can still
| emit. When a remote peer sends a compressed payload that crosses the
| built-in 128 MiB decompressed-payload limit and then contains a
| malformed DEFLATE byte, the inflate stream emits a data error with
| no listener attached, which Node.js treats as a fatal unhandled
| error and terminates the entire process. Exploitation is remote and
| unauthenticated, requires no application mistake, and is asymmetric,
| since roughly 130 KB on the wire expands past the limit and crashes
| the process, and reconnecting can repeat the crash. This affects
| undici versions from 6.25.0 up to 6.28.1, from 7.28.0 up to 7.29.1,
| and from 8.1.0 up to 8.10.2. Users should upgrade to undici 6.28.1,
| 7.29.1, or 8.10.2.
CVE-2026-85152[10]:
| undici 8.10.0 omits the destination origin from the cache and
| request-deduplication keys when the cache or deduplicate interceptor
| is composed directly onto a Client or Pool. Because the internal
| cache key falls back to an empty origin string, a cacheable or in-
| flight response from one upstream origin is returned for a request
| to a different, trusted origin whenever the method, path, and
| relevant headers match, which permits cross-origin information
| disclosure and persistent cache poisoning. The reporter demonstrated
| a full authentication bypass in which a JWT signed with an attacker-
| controlled key was accepted as belonging to a trusted issuer, and
| the trusted origin was never contacted. This is a regression
| introduced in 8.10.0 and affects undici versions from 8.10.0 up to
| 8.10.2. Applications using an Agent, which carries the origin in its
| dispatch options, are not affected. Users should upgrade to undici
| 8.10.2.
If you fix the vulnerabilities please also make sure to include the
CVE (Common Vulnerabilities & Exposures) ids in your changelog entry.
For further information see:
[0] https://security-tracker.debian.org/tracker/CVE-2026-18149
https://www.cve.org/CVERecord?id=CVE-2026-18149
[1] https://security-tracker.debian.org/tracker/CVE-2026-18540
https://www.cve.org/CVERecord?id=CVE-2026-18540
[2] https://security-tracker.debian.org/tracker/CVE-2026-19534
https://www.cve.org/CVERecord?id=CVE-2026-19534
[3] https://security-tracker.debian.org/tracker/CVE-2026-84890
https://www.cve.org/CVERecord?id=CVE-2026-84890
[4] https://security-tracker.debian.org/tracker/CVE-2026-84933
https://www.cve.org/CVERecord?id=CVE-2026-84933
[5] https://security-tracker.debian.org/tracker/CVE-2026-84947
https://www.cve.org/CVERecord?id=CVE-2026-84947
[6] https://security-tracker.debian.org/tracker/CVE-2026-84961
https://www.cve.org/CVERecord?id=CVE-2026-84961
[7] https://security-tracker.debian.org/tracker/CVE-2026-85008
https://www.cve.org/CVERecord?id=CVE-2026-85008
[8] https://security-tracker.debian.org/tracker/CVE-2026-85014
https://www.cve.org/CVERecord?id=CVE-2026-85014
[9] https://security-tracker.debian.org/tracker/CVE-2026-85024
https://www.cve.org/CVERecord?id=CVE-2026-85024
[10] https://security-tracker.debian.org/tracker/CVE-2026-85152
https://www.cve.org/CVERecord?id=CVE-2026-85152
Regards,
Salvatore