Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions deps/undici/src/changelogs/v7.30.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# undici 7.30.2 security fixes

This release fixes six vulnerabilities.

## CVE-2026-116592 / GHSA-mqg3-3v4r-cm32 (high)

Undici 7.30.1 could cache the final response from a redirect chain under the original request key without applying the origin, cache policy, freshness, or `Vary` requirements of every intermediate hop. This could poison a cache or expose one user's response to another user. The fix validates every redirect hop, combines their `Vary` fields, limits freshness and stale serving to the most restrictive hop, and invalidates persistent SQLite entries written by vulnerable releases.

## CVE-2026-120474 / GHSA-7xg3-fphp-28hg (medium)

In Undici 7.x, a shared cache used with `compose(redirect(), cache())` could store a credential-dependent response from a same-origin redirect under the original URL. A later authenticated or unauthenticated request could then receive another user's response. Redirected requests carrying `Authorization`, `Cookie`, or `Proxy-Authorization` are no longer stored under the original alias key.

## CVE-2026-116630 / GHSA-5rm8-gv32-r954 (medium)

In Undici 7.x, a cross-origin redirect during cache revalidation could let a `304 Not Modified` response from the redirect target validate a cached response from the original origin. Undici now checks that the revalidation target matches the cached URL and that any returned validator matches the stored representation before replaying the cached body.

## CVE-2026-120415 / GHSA-9v6h-8rgp-m69f (medium)

In Undici 7.x, the redirect interceptor did not strip credentials correctly when request headers were supplied as an array of `[name, value]` pairs. With a header-normalizing interceptor outside `redirect()`, credentials could be sent to a cross-origin redirect target. Undici now handles both tuple arrays and flat header arrays when removing sensitive headers.

## CVE-2026-120222 / GHSA-3g9m-rv3r-w5w2 (medium)

In Undici 7.x, a downstream handler exception during cache replay could escape as an uncaught exception or unhandled promise rejection and terminate the process. This included `dump` size-limit failures, excessive `Content-Encoding` values in `decompress`, asynchronous cache-store failures, and cached-body replay after a `304`. These failures are now reported as request errors.

## CVE-2026-120423 / GHSA-r4pc-4jcp-7pqc (medium)

Undici 7.15.0 through 7.30.1 could skip Subresource Integrity verification when valid integrity metadata was separated or surrounded by ASCII whitespace other than a space, including a horizontal tab. Integrity metadata is now split on all ASCII whitespace before SHA-256, SHA-384, or SHA-512 verification.
4 changes: 3 additions & 1 deletion deps/undici/src/lib/cache/sqlite-cache-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ const { assertCacheKey, assertCacheValue } = require('../util/cache.js')

let DatabaseSync

const VERSION = 3
// Bump when entries written by an older cache policy are unsafe to reuse.
// Version 4 invalidates entries that may have been poisoned through redirects.
const VERSION = 4

// 2gb
const MAX_ENTRY_SIZE = 2 * 1000 * 1000 * 1000
Expand Down
2 changes: 1 addition & 1 deletion deps/undici/src/lib/core/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class Request {

this.method = method

this.typeOfService = typeOfService ?? 0
this.typeOfService = typeOfService

this.abort = null

Expand Down
21 changes: 21 additions & 0 deletions deps/undici/src/lib/core/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,26 @@ function parseRawHeaders (headers) {
return ret
}

/**
* @param {Record<string, string | string[]>} headers
* @returns {Buffer[]}
*/
function toRawHeaders (headers) {
const rawHeaders = []

for (const [name, value] of Object.entries(headers)) {
if (Array.isArray(value)) {
for (const entry of value) {
rawHeaders.push(Buffer.from(name, 'latin1'), Buffer.from(`${entry}`, 'latin1'))
}
} else {
rawHeaders.push(Buffer.from(name, 'latin1'), Buffer.from(`${value}`, 'latin1'))
}
}

return rawHeaders
}

/**
* @param {string[]} headers
* @param {Buffer[]} headers
Expand Down Expand Up @@ -961,6 +981,7 @@ module.exports = {
removeAllListeners,
errorRequest,
parseRawHeaders,
toRawHeaders,
encodeRawHeaders,
parseHeaders,
parseKeepAliveTimeout,
Expand Down
31 changes: 28 additions & 3 deletions deps/undici/src/lib/dispatcher/client-h1.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const removeAllListeners = util.removeAllListeners
const kIdleSocketValidation = Symbol('kIdleSocketValidation')
const kIdleSocketValidationTimeout = Symbol('kIdleSocketValidationTimeout')
const kSocketUsed = Symbol('kSocketUsed')
const kTypeOfService = Symbol('kTypeOfService')

let extractBody

Expand Down Expand Up @@ -1109,6 +1110,32 @@ function shouldSendContentLength (method) {
return method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS' && method !== 'TRACE' && method !== 'CONNECT'
}

function setTypeOfService (socket, request) {
if (typeof socket.setTypeOfService !== 'function') {
return
}

const typeOfService = request.typeOfService

if (typeOfService === undefined) {
return
}

const currentTypeOfService = socket[kTypeOfService]

if (currentTypeOfService === typeOfService) {
return
}

try {
socket.setTypeOfService(typeOfService)
socket[kTypeOfService] = typeOfService
} catch {
// QoS marking is best-effort. setTypeOfService() can throw synchronously on
// some platforms depending on socket state, but that must not abort the request.
}
}

/**
* @param {import('./client.js')} client
* @param {import('../core/request.js')} request
Expand Down Expand Up @@ -1248,9 +1275,7 @@ function writeH1 (client, request) {
socket[kBlocking] = true
}

if (socket.setTypeOfService) {
socket.setTypeOfService(request.typeOfService)
}
setTypeOfService(socket, request)

let header = `${method} ${path} HTTP/1.1\r\n`

Expand Down
Loading
Loading