Uncleared cookies on cross-host/cross-origin redirect in undici
Description
Authorization headers are cleared on cross-origin redirect. However, cookie headers which are sensitive headers and are official headers found in the spec, remain uncleared. There are active users using cookie headers in undici. This may lead to accidental leakage of cookie to a 3rd-party site or a malicious attacker who can control the redirection target (ie. an open redirector) to leak the cookie to the 3rd party site. This was patched in v5.7.1. By default, this vulnerability is not exploitable. Do not enable redirections, i.e. maxRedirections: 0 (the default).
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
undicinpm | < 5.8.0 | 5.8.0 |
Affected products
1Patches
10a5bee9465e6Merge pull request from GHSA-q768-x9m6-m9qp
4 files changed · +66 −3
lib/handler/redirect.js+2 −1 modified@@ -186,7 +186,8 @@ function shouldRemoveHeader (header, removeContent, unknownOrigin) { return ( (header.length === 4 && header.toString().toLowerCase() === 'host') || (removeContent && header.toString().toLowerCase().indexOf('content-') === 0) || - (unknownOrigin && header.length === 13 && header.toString().toLowerCase() === 'authorization') + (unknownOrigin && header.length === 13 && header.toString().toLowerCase() === 'authorization') || + (unknownOrigin && header.length === 6 && header.toString().toLowerCase() === 'cookie') ) }
test/redirect-request.js+21 −1 modified@@ -7,7 +7,8 @@ const { startRedirectingWithBodyServer, startRedirectingChainServers, startRedirectingWithoutLocationServer, - startRedirectingWithAuthorization + startRedirectingWithAuthorization, + startRedirectingWithCookie } = require('./utils/redirecting-servers') const { createReadable, createReadableStream } = require('./utils/stream') @@ -489,3 +490,22 @@ t.test('removes authorization header on third party origin', async t => { t.equal(body, '') }) + +t.test('removes cookie header on third party origin', async t => { + t.plan(1) + + const [server1] = await startRedirectingWithCookie(t, 'a=b') + const { body: bodyStream } = await undici.request(`http://${server1}`, { + maxRedirections: 10, + headers: { + cookie: 'a=b' + } + }) + + let body = '' + for await (const b of bodyStream) { + body += b + } + + t.equal(body, '') +})
test/redirect-stream.js+19 −1 modified@@ -7,7 +7,8 @@ const { startRedirectingWithBodyServer, startRedirectingChainServers, startRedirectingWithoutLocationServer, - startRedirectingWithAuthorization + startRedirectingWithAuthorization, + startRedirectingWithCookie } = require('./utils/redirecting-servers') const { createReadable, createWritable } = require('./utils/stream') @@ -401,3 +402,20 @@ t.test('removes authorization header on third party origin', async t => { t.equal(body.length, 0) }) + +t.test('removes cookie header on third party origin', async t => { + t.plan(1) + + const body = [] + + const [server1] = await startRedirectingWithCookie(t, 'a=b') + await stream(`http://${server1}`, { + maxRedirections: 10, + opaque: body, + headers: { + cookie: 'a=b' + } + }, ({ statusCode, headers, opaque }) => createWritable(opaque)) + + t.equal(body.length, 0) +})
test/utils/redirecting-servers.js+24 −0 modified@@ -178,6 +178,29 @@ async function startRedirectingWithAuthorization (t, authorization) { return [server1, server2] } +async function startRedirectingWithCookie (t, cookie) { + const server1 = await startServer(t, (req, res) => { + if (req.headers.cookie !== cookie) { + res.statusCode = 403 + res.setHeader('Connection', 'close') + res.end('') + return + } + + res.statusCode = 301 + res.setHeader('Connection', 'close') + + res.setHeader('Location', `http://${server2}`) + res.end('') + }) + + const server2 = await startServer(t, (req, res) => { + res.end(req.headers.cookie || '') + }) + + return [server1, server2] +} + async function startRedirectingWithRelativePath (t) { const server = await startServer(t, (req, res) => { res.setHeader('Connection', 'close') @@ -206,5 +229,6 @@ module.exports = { startRedirectingWithoutLocationServer, startRedirectingChainServers, startRedirectingWithAuthorization, + startRedirectingWithCookie, startRedirectingWithRelativePath }
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
11- github.com/advisories/GHSA-q768-x9m6-m9qpghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2022-31151ghsaADVISORY
- github.com/nodejs/undici/blob/main/lib/handler/redirect.jsghsaWEB
- github.com/nodejs/undici/commit/0a5bee9465e627be36bac88edf7d9bbc9626126dghsaWEB
- github.com/nodejs/undici/issues/872ghsax_refsource_MISCWEB
- github.com/nodejs/undici/pull/1441ghsaWEB
- github.com/nodejs/undici/releases/tag/v5.8.0ghsaWEB
- github.com/nodejs/undici/security/advisories/GHSA-q768-x9m6-m9qpghsax_refsource_CONFIRMWEB
- hackerone.com/reports/1635514ghsax_refsource_MISCWEB
- security.netapp.com/advisory/ntap-20220909-0006ghsaWEB
- security.netapp.com/advisory/ntap-20220909-0006/mitrex_refsource_CONFIRM
News mentions
0No linked articles in our index yet.