Releases: nodejs/undici
Releases · nodejs/undici
Release list
v8.10.2
⚠️ Security fixes
High severity
- GHSA-vp8m-p9jh-q5pm: cache and deduplication interceptors could use caller-controlled request metadata instead of the authoritative dispatcher origin, enabling cross-origin cache poisoning and data disclosure. Undici now derives interceptor identities from the dispatcher origin and bypasses origin-dependent interceptors when no authoritative origin exists. Fixed by caf6194d.
- GHSA-w293-vg96-wgc3:
BalancedPoolcould drop function-valued connection options while cloning its configuration, including custom TLS certificate validation callbacks. Undici now preservesconnectand legacytlsoptions when creating upstreams. Fixed by 8f5868fb. - GHSA-rfgv-xxqx-mfg5: a WebSocket server could select a subprotocol when none was requested, causing an uncaught
TypeErrorthat could terminate the process. Undici now rejects the handshake with protocol error 1002. Fixed by 66e12816.
Medium severity
- GHSA-3wwx-pv8p-q78v: a malformed permessage-deflate payload exceeding the configured decompression limit could emit an unhandled zlib error and terminate the process. Undici now destroys the inflater after reaching the limit. Fixed by 4411a238.
- GHSA-rx4f-c7p8-82vq: an unclean
WebSocketStreamclose could create an unobserved rejected promise when its writable stream was locked, potentially terminating the process. Undici now propagates the failure through the retained writable stream controller. Fixed by 662d0ea6. - GHSA-2jfj-6hjv-fm6j: shared caches could store and replay responses containing
Set-Cookie, disclosing one user's cookies to another caller. Undici now excludes these responses from shared caches, including existing entries and revalidation paths. Fixed by cb75bbb3. - GHSA-3xpg-4rpp-hhhm: the decompression interceptor did not bound decoded output, allowing compressed responses to consume excessive memory. Undici now limits every decompression stage to 64 MiB by default and supports a configurable
maxSize. Fixed by 7aac7f12. - GHSA-pmjh-fq2x-6v4x: a terminal retry failure after response headers were exposed could orphan the original response body, causing consumers to hang indefinitely. Undici now propagates the terminal error to the exposed body. Fixed by e905b5b8.
Low severity
- GHSA-8436-99hf-9mmv: cache interceptors could store and replay responses to unsafe HTTP methods such as
POSTorDELETE. Undici now restricts cache reads and writes to safe methods while preserving invalidation by successful unsafe requests. Fixed by 2be07bf9. - GHSA-2gqq-gqf2-x968: the dump interceptor could treat an oversized chunked response as successfully truncated when no
Content-Lengthwas present. Undici now enforcesmaxSizeagainst received bytes and aborts oversized responses. Fixed by 6d583124. - GHSA-r53p-7pc4-xj5r: the retry interceptor could concatenate a resumed response with inconsistent framing into downstream output, enabling response splitting or corruption. Undici now validates
Content-Rangeagainst the original response framing before resuming. Fixed by 0160a719.
What's Changed
- build(deps-dev): bump undici from 6.27.0 to 6.28.0 by @dependabot[bot] in #5653
- build(deps-dev): bump jest from 30.4.2 to 30.5.0 by @dependabot[bot] in #5750
- build(deps): bump github/codeql-action/analyze from 4.37.3 to 4.37.9 by @dependabot[bot] in #5752
- build(deps): bump github/codeql-action/upload-sarif from 4.36.2 to 4.37.9 by @dependabot[bot] in #5754
- test(h2): cover stream reset with NGHTTP2_INTERNAL_ERROR by @zeexzeex in #5725
- fix(retry): reject invalid resumed responses by @mcollina in #5724
- test: make stale-while-revalidate cache update test deterministic by @mcollina in #5722
- fix: avoid unbounded recursion in Set-Cookie attribute parser by @mcollina in #5757
- fix: honor SOCKS5 connection timeout by @mcollina in #5733
- fix(eventsource): validate Last-Event-ID on reconnect by @mcollina in #5746
- fix: avoid duplicate release attempts by @mcollina in #5745
- fix(cache): refetch when 304 adds vary fields by @mcollina in #5732
- types: expose PendingInterceptor and PendingInterceptorsFormatter on the MockAgent namespace by @RaphaelFakhri in #5721
- ci(codeql): align CodeQL action versions to v4.37.9 by @mcollina in #5759
- build(deps-dev): bump @humanfs/node from 0.16.7 to 0.16.8 by @dependabot[bot] in #5760
- fix(proxy-agent): guard Proxy-Authorization in iterable header containers by @mcollina in #5758
- docs: name the parameters these two blocks describe by @darkdi in #5735
- fix(websocket): fail the connection on a non-200 h2 extended CONNECT response by @kjsik11 in #5751
- test(node-fetch): re-enable the set-cookie header combining test by @pacocartones in #5730
- fix(retry): forward rawHeaders writes through RetryController by @official-burak in #5727
- fix(fetch): only send Sec-Fetch-Mode to potentially trustworthy URLs by @kjsik11 in #5738
New Contributors
- @darkdi made their first contribution in #5735
- @kjsik11 made their first contribution in #5751
- @official-burak made their first contribution in #5727
Full Changelog: v8.10.1...v8.10.2
v7.29.1
⚠️ Security fixes
High severity
- GHSA-w293-vg96-wgc3:
BalancedPoolcould drop function-valued connection options while cloning its configuration, including custom TLS certificate validation callbacks. Undici now preservesconnectand legacytlsoptions when creating upstreams. Fixed by f690157d. - GHSA-rfgv-xxqx-mfg5: a WebSocket server could select a subprotocol when none was requested, causing an uncaught
TypeErrorthat could terminate the process. Undici now rejects the handshake with protocol error 1002. Fixed by 6615e017.
Medium severity
- GHSA-3wwx-pv8p-q78v: a malformed permessage-deflate payload exceeding the configured decompression limit could emit an unhandled zlib error and terminate the process. Undici now destroys the inflater after reaching the limit. Fixed by 63cf698b.
- GHSA-rx4f-c7p8-82vq: an unclean
WebSocketStreamclose could create an unobserved rejected promise when its writable stream was locked, potentially terminating the process. Undici now propagates the failure through the retained writable stream controller. Fixed by 1858656e. - GHSA-2jfj-6hjv-fm6j: shared caches could store and replay responses containing
Set-Cookie, disclosing one user's cookies to another caller. Undici now excludes these responses from shared caches, including existing entries and revalidation paths. Fixed by b6c5a002. - GHSA-3xpg-4rpp-hhhm: the decompression interceptor did not bound decoded output, allowing compressed responses to consume excessive memory. Undici now limits every decompression stage to 64 MiB by default and supports a configurable
maxSize. Fixed by 2c7d7e12. - GHSA-pmjh-fq2x-6v4x: a terminal retry failure after response headers were exposed could orphan the original response body, causing consumers to hang indefinitely. Undici now propagates the terminal error to the exposed body. Fixed by 3c672659.
Low severity
- GHSA-8436-99hf-9mmv: cache interceptors could store and replay responses to unsafe HTTP methods such as
POSTorDELETE. Undici now restricts cache reads and writes to safe methods while preserving invalidation by successful unsafe requests. Fixed by b61d9432. - GHSA-2gqq-gqf2-x968: the dump interceptor could treat an oversized chunked response as successfully truncated when no
Content-Lengthwas present. Undici now enforcesmaxSizeagainst received bytes and aborts oversized responses. Fixed by 21693f40. - GHSA-r53p-7pc4-xj5r: the retry interceptor could concatenate a resumed response with inconsistent framing into downstream output, enabling response splitting or corruption. Undici now validates
Content-Rangeagainst the original response framing before resuming. Fixed by cd8af90b.
What's Changed
- [v7.x] drop: remove Node.js 26 from shared-builtin CI build by @mcollina in #5592
- fix(h2): honour headersTimeout by @mcollina in #5604
- fix(h2): keep the connection ref'd while requests are outstanding by @mcollina in #5605
- ci: increase Windows workflow timeout on v7.x by @mcollina in #5621
- fix(h2): retire the request that completed, not the head of the queue by @mcollina in #5618
- fix(h2): settle a request whose stream is cancelled by @mcollina in #5607
- perf: reduce EventSourceStream parser allocations (#5032) by @mcollina in #5646
- fix(h2): handle GOAWAY for CONNECT streams by @mcollina in #5640
- [v7.x] perf(h1): drop idle-socket timer floor with a ref'd setImmediate (#5707) by @mcollina in #5769
Full Changelog: v7.29.0...v7.29.1
v6.28.1
⚠️ Security fixes
High severity
- GHSA-rfgv-xxqx-mfg5: a WebSocket server could select a subprotocol when none was requested, causing an uncaught
TypeErrorthat could terminate the process. Undici now rejects the handshake with protocol error 1002. Fixed by 2af0faf8.
Medium severity
- GHSA-3wwx-pv8p-q78v: a malformed permessage-deflate payload exceeding the configured decompression limit could emit an unhandled zlib error and terminate the process. Undici now destroys the inflater after reaching the limit. Fixed by 07c60d9c.
Low severity
- GHSA-r53p-7pc4-xj5r: the retry interceptor could concatenate a resumed response with inconsistent framing into downstream output, enabling response splitting or corruption. Undici now validates
Content-Rangeagainst the original response framing before resuming. Fixed by ce31bc82.
What's Changed
- perf: reduce EventSourceStream parser allocations (#5032) by @mcollina in #5647
- [v6.x] perf(h1): drop idle-socket timer floor with a ref'd setImmediate (#5707) by @mcollina in #5770
Full Changelog: v6.28.0...v6.28.1
v8.10.1
What's Changed
- fix(mock): re-invoke reply callback for persistent mocks by @mcollina in #5650
- fix: preserve MockAgent interceptors for legacy global fetch by @pacocartones in #5648
- ci: align codeql-action autobuild and analyze with init at v4.37.3 by @ostapondo in #5655
- ci: test against the current Node.js nightly major by @ostapondo in #5654
- ci: only accept a numeric nightly major by @ostapondo in #5657
- test: complete the h2 settings round-trip before asserting single-session multiplexing by @ostapondo in #5656
- fix: propagate dispatcher origin to composed interceptors by @jibin7jose in #5624
- fix: limit EventSource event size by @mcollina in #5552
- build(deps-dev): bump ws from 8.21.1 to 8.21.3 by @dependabot[bot] in #5678
- fix(retry): honor the retryAfter option in the default retry strategy by @codeAnqiang-ma in #5683
- fix(interceptor/dump): reject aborted requests when response is smaller than maxSize by @codeAnqiang-ma in #5685
- test: add unexpected disconnect guards to remaining http2 tests by @zeexzeex in #5686
- test: harden http2-request-never-settles against late session errors by @pacocartones in #5674
- fix(test): skip cache-tests when submodule is missing by @edenbuilds in #5661
- fix(retry): honor the abort signal during the retry backoff by @pacocartones in #5675
- fix(deduplicate): settle the deduplicated request when it is aborted by @pacocartones in #5673
- build(deps-dev): bump esbuild from 0.28.1 to 0.28.2 by @dependabot[bot] in #5698
- build(deps-dev): bump @fastify/busboy from 3.2.0 to 3.2.1 by @dependabot[bot] in #5697
- fix: accept a negative Set-Cookie Max-Age attribute by @arshsmith1 in #5571
- fix(h2): honour maxResponseSize by @ondraulehla in #5676
- test: stabilize HTTP/2 timeout tests by @mcollina in #5689
- fix: forward onBodySent/onRequestSent through interceptor handlers by @adarshx01 in #5696
- perf(h1): drop idle-socket timer floor with a ref'd setImmediate by @anonrig in #5707
- perf(fetch): skip empty RequestInit work by @anonrig in #5701
- fix: propagate dispatcher options to base class by @mcollina in #5687
- fix(env-http-proxy-agent): ignore trailing dots when matching no_proxy by @pacocartones in #5637
- build(deps-dev): bump @fastify/busboy from 3.2.1 to 3.2.2 by @dependabot[bot] in #5718
- build(deps): bump brace-expansion by @dependabot[bot] in #5719
- fix(socks5-proxy-agent): destroy socket when negotiation times out by @abhijeet117 in #5709
- fix(cache): evict entries when a key holds a single entry by @mcollina in #5737
- test: restore /xhr to the WPT filter by @RaphaelFakhri in #5723
- fix(h2): forward 1xx informational responses to onInfo by @pacocartones in #5712
- fix(agent): preserve pools with pending GOAWAY replays by @mcollina in #5740
- test: skip HTTP/2 churn test on Node.js 26 by @mcollina in #5742
New Contributors
- @ostapondo made their first contribution in #5655
- @jibin7jose made their first contribution in #5624
- @codeAnqiang-ma made their first contribution in #5683
- @zeexzeex made their first contribution in #5686
- @edenbuilds made their first contribution in #5661
- @arshsmith1 made their first contribution in #5571
- @ondraulehla made their first contribution in #5676
- @adarshx01 made their first contribution in #5696
- @abhijeet117 made their first contribution in #5709
- @RaphaelFakhri made their first contribution in #5723
Full Changelog: v8.10.0...v8.10.1
v8.10.0
What's Changed
- feat: namespace h2 options by @metcoder95 in #5498
- test: update WPT expectations by @mcollina in #5587
- test: add cache/dedupe + dns re-dispatch integration tests by @GiHoon1123 in #5535
- fix(websocket): support process.unref by @mcollina in #5578
- fix(h2): ensure every request settles by @mcollina in #5603
- fix(readable): consume a body whose end has already been emitted by @marko1olo in #5617
- fix(retry): skip the content-length checkpoint for HEAD and for a 206 without content-range by @marko1olo in #5610
- fix: revert idle socket validation to setTimeout(0) to prevent stall on idle event loop by @marceli1404 in #5606
- fix(env-http-proxy-agent): match bare IPv6 addresses in no_proxy by @marko1olo in #5623
- test: handle aggregate balanced pool errors by @marko1olo in #5377
- fix(readable): keep body bytes that arrive after setEncoding() by @mcollina in #5620
- fix(socks5): evict unused origin pools by @Kkartik14 in #5595
- fix: skip deduplication for upgrade requests by @Ram-blip in #5593
- fix(retry): forward informational responses by @mcollina in #5625
- fix(mock): non-string path matchers under ignoreTrailingSlash, and DataView reply bodies by @marko1olo in #5619
- fix(interceptors): cache() and deduplicate() silently inert on Client/Pool without opts.origin by @marko1olo in #5628
- build(deps): bump ossf/scorecard-action from 2.4.3 to 2.4.4 by @dependabot[bot] in #5633
- build(deps): bump github/codeql-action/init from 4.36.2 to 4.37.3 by @dependabot[bot] in #5634
- build(deps): bump actions/setup-node from 6.4.0 to 7.0.0 by @dependabot[bot] in #5636
- fix(mock): emit request body lifecycle hooks by @marko1olo in #5367
- fix(h2): detach upgrade close handler after GOAWAY by @pacocartones in #5641
- fix: retry refused HTTP/2 streams by @mcollina in #5598
- fix: preserve DNS origin hostname on sockets by @cyphercodes in #5577
New Contributors
- @marceli1404 made their first contribution in #5606
- @Kkartik14 made their first contribution in #5595
- @pacocartones made their first contribution in #5641
- @cyphercodes made their first contribution in #5577
Full Changelog: v8.9.0...v8.10.0
v8.9.0
⚠️ Security fixes
High severity
- GHSA-4cwx-7wf7-3272: malformed qualified
privateCache-Control directives could cause cross-user information disclosure in shared caches or a parse-time crash. The cache parser now treats empty qualified directives conservatively and safely handles mixed qualified and unqualified directives. Fixed by 4fe5bc5f with regression coverage in 9f09b49a.
Medium severity
- GHSA-m8rv-5g2x-5cg5: a malicious
typeproperty on a duck-typed blob-like HTTP/1.1 request body could inject CRLF sequences into the generatedcontent-typeheader. Undici now coerces and validates the value before adding it to the request. Fixed by 7d3cf924. - GHSA-jr45-8vmc-qm54: optional whitespace around
=in qualifiedno-cacheandprivatedirectives could bypass shared-cache restrictions and disclose authenticated data across users. Cache-Control parsing now normalizes these forms and applies conservative cache decisions. Fixed by c601fff1. - GHSA-8xcm-r25x-g524: the retry interceptor could expose a stale
Content-Lengthafter resuming a partial response, potentially causing downstream response desynchronization, hangs, or corruption. Undici now rejects partial responses whoseContent-Lengthis inconsistent withContent-Range. Fixed by e11a68ed, with corrected fixtures in 2b3f7493. - GHSA-v3r7-h72x-cjcm: unsanitized
domainandunparsedvalues passed tosetCookie()could inject cookie attributes. Undici now validates cookie domains, paths, and unparsed attributes more strictly. Fixed by 10d93fc3.
Additional hardening
Undici now validates non-string header values after coercion, including array elements, preventing crafted toString() or Symbol.toPrimitive implementations from introducing CRLF sequences. This defense-in-depth change was made in 354a151f.
What's Changed
- fix(decompress): preserve response trailers by @Ram-blip in #5572
- build(deps-dev): bump ws from 8.21.0 to 8.21.1 by @dependabot[bot] in #5576
- fix: validate coerced header values for CRLF by @mcollina in #5579
- fix: handle frozen globalThis in setGlobalDispatcher by @mhayk in #5574
- Ignore auto-generated .npmrc on Windows by @tsctx in #5583
New Contributors
Full Changelog: v8.8.0...v8.9.0
v7.29.0
⚠️ Security fixes
High severity
- GHSA-4cwx-7wf7-3272: malformed qualified
privateCache-Control directives could cause cross-user information disclosure in shared caches or a parse-time crash. The cache parser now treats empty qualified directives conservatively and safely handles mixed qualified and unqualified directives. Fixed by 9f10f1e9, with regression coverage in 466e99d1.
Medium severity
- GHSA-m8rv-5g2x-5cg5: a malicious
typeproperty on a duck-typed blob-like HTTP/1.1 request body could inject CRLF sequences into the generatedcontent-typeheader. Undici now coerces and validates the value before adding it to the request. Fixed by 33928bc2. - GHSA-jr45-8vmc-qm54: optional whitespace around
=in qualifiedno-cacheandprivatedirectives could bypass shared-cache restrictions and disclose authenticated data across users. Cache-Control parsing now normalizes these forms and applies conservative cache decisions. Fixed by 98011a86. - GHSA-8xcm-r25x-g524: the retry interceptor could expose a stale
Content-Lengthafter resuming a partial response, potentially causing downstream response desynchronization, hangs, or corruption. Undici now rejects partial responses whoseContent-Lengthis inconsistent withContent-Range. Fixed by 1b5a5312, with corrected fixtures in 4a9dafb1. - GHSA-v3r7-h72x-cjcm: unsanitized
domainandunparsedvalues passed tosetCookie()could inject cookie attributes. Undici now validates cookie domains, paths, and unparsed attributes more strictly. Fixed by 3bf91ddb.
Full Changelog: v7.28.0...v7.29.0
v6.28.0
⚠️ Security fixes
- GHSA-m8rv-5g2x-5cg5: a malicious
typeproperty on a duck-typed blob-like HTTP/1.1 request body could inject CRLF sequences into the generatedcontent-typeheader. Undici now coerces and validates the value before adding it to the request. Fixed by 740a0b7c. - GHSA-8xcm-r25x-g524: the retry interceptor could expose a stale
Content-Lengthafter resuming a partial response, potentially causing downstream response desynchronization, hangs, or corruption. Undici now rejects partial responses whoseContent-Lengthis inconsistent withContent-Range. Fixed by cba3a52a, with corrected fixtures in 4fd5a0c6. - GHSA-v3r7-h72x-cjcm: unsanitized
domainandunparsedvalues passed tosetCookie()could inject cookie attributes. Undici now validates cookie domains, paths, and unparsed attributes more strictly. Fixed by af748404.
GHSA-4cwx-7wf7-3272 and GHSA-jr45-8vmc-qm54 affect the cache interceptor in Undici v7 and v8; Undici v6 is not in their affected version ranges.
Full Changelog: v6.27.0...v6.28.0
v8.8.0
What's Changed
- fetch: use ReadableStreamTee for cloning streams by @KhafraDev in #5517
- fix(benchmarks): adjust got after v15 upgrade by @slagiewka in #5526
- feat(mock): support asynchronous reply options callbacks by @Develop-KIM in #5534
- docs: clarify proxy threat model by @mcollina in #5530
- docs: clarify MockAgent pool usage by @vibhor-aggr in #5542
- docs: clarify parser timeout precision by @vibhor-aggr in #5543
- fix: handle flat alternating header arrays in cache normalizeHeaders by @mcollina in #5536
- chore(benchmarks): require(esm) on ESM-only packages by @slagiewka in #5527
- fix: run idle socket validation off setImmediate instead of setTimeout by @carlotestor in #5499
- docs: add custom interceptor example by @vibhor-aggr in #5548
- fix(h1): ignore type of service errors by @mcollina in #5547
- fix(fetch): convert null init in Response.json by @Ram-blip in #5540
- fix(redirect): remove body headers after POST-to-GET by @Ram-blip in #5551
- build(deps-dev): bump fast-check from 4.8.0 to 4.9.0 by @dependabot[bot] in #5556
- fix(h2): allow stream-bodied requests to multiplex on a busy session by @GiHoon1123 in #5538
- fix(h2): destroy aborted stream synchronously instead of via setImmediate by @staylor in #5559
- fix(decompress): skip HEAD responses by @Ram-blip in #5564
- ci: build undici with node.js v26 by @shivarm in #5237
- docs: clarify top-level request option url fields by @vibhor-aggr in #5545
- test: add unexpected disconnect guards to http2 tests by @Develop-KIM in #5533
- fix: track origins by client map key in Agent teardown by @emmayusufu in #5537
- fix: enforce must-revalidate and proxy-revalidate over max-stale and stale-if-error by @jeswr in #5511
- fix(retry): handle Retry-After zero delay by @Ram-blip in #5519
- fix: honor stale-if-error on connection errors during revalidation by @jeswr in #5513
- fix: store revalidation-only responses so etag revalidation can engage by @jeswr in #5515
- fix(h2): prevent uncaughtException from onHttp2SocketError accessing undefined kClient by @mcollina in #5546
- fix(h2): complete request stream on 'end' instead of waiting for 'close' by @staylor in #5560
- fix: invalidate Location and Content-Location URIs on unsafe methods by @jeswr in #5514
- test: deflake invalid websocket close status test by @mcollina in #5550
- refactor: replace tspl with node:test t.plan in connect-timeout tests by @mcollina in #5518
- fix(h2): release completed requests from queue by @staylor in #5569
New Contributors
- @Develop-KIM made their first contribution in #5534
- @carlotestor made their first contribution in #5499
- @GiHoon1123 made their first contribution in #5538
- @emmayusufu made their first contribution in #5537
Full Changelog: v8.7.0...v8.8.0
v8.7.0
What's Changed
- test: guard balanced-pool error port lookup by @mcollina in #5463
- perf: optimize http/2 request hot path by @mcollina in #5483
- fix: do not reject open-ended Range values in simpleRangeHeaderValue by @spokodev in #5490
- fix(eventsource): set use-URL-credentials flag by @Ram-blip in #5489
- test: deflake connect-timeout watchdog by @mcollina in #5197
- docs: correct npm script name and JSON syntax in examples by @lenoxfernando in #5496
- fix: reject non-ascii octets in validateCookiePath by @spokodev in #5452
- fix(readable): ignore late consume chunks by @marko1olo in #5375
- fix(h2): destroy the stream on abort instead of relying on close() by @staylor in #5462
- fix: ignore an unparseable Set-Cookie Expires attribute by @spokodev in #5488
- docs: add reproduction guide and update bug report template by @mcollina in #5451
- fix(h2): guard onResponse against a 'response' event delivered after completion by @staylor in #5440
- fix(h2): requeue request on GOAWAY'd session instead of crashing by @staylor in #5453
- fix: add static buildDispatch method to RedirectHandler type definition by @matthieusieben in #5442
- fix: auto-detect HTTP proxy tunneling by @mcollina in #5116
New Contributors
- @spokodev made their first contribution in #5490
- @lenoxfernando made their first contribution in #5496
- @staylor made their first contribution in #5462
Full Changelog: v8.6.0...v8.7.0