
Happier DOMs: The perils of running untrusted JavaScript code outside of a web browser | Blog | Endor Labs
Endor Labs explains CVE-2025-61927, an RCE in the happy-dom headless browser caused by relying on Node.js's vm module, which is not a security boundary. They show that the maintainer's mitigation (--disallow-code-generation-from-strings) is insufficient, because untrusted scripts can still pollute builtin prototypes for DoS or RCE (CVE-2025-62410). The fix adds --frozen-intrinsics. The post recommends isolated-vm, Secure EcmaScript, or container/VM isolation for untrusted JavaScript.
What it is
CVE-2025-61927 is a remote code execution flaw in happy-dom, a headless browser for Node.js used for crawling and server-side rendering. CVE-2025-62410 is a follow-up advisory showing that the maintainer's first mitigation still leaves a prototype-pollution route to DoS and RCE. The root cause is that happy-dom runs page scripts in Node's vm module, which Node documents as "not a security mechanism."
How it works
Initial escape. Script in the page reaches the host Function constructor through this, builds a function outside the vm, and grabs process:
const process = this.constructor.constructor('return process')();
const require = process.mainModule.require;From there it can call require('fs') and other Node APIs.
Pollution escape. The --disallow-code-generation-from-strings flag blocks the payload above, but this.constructor.constructor.__proto__.__proto__ still resolves to the host's root prototype. Script can overwrite builtins there:
this.constructor.constructor.__proto__.__proto__.toString = () => {};The page's PoC for this causes DoS. The CVE-2025-62410 advisory has a more sophisticated payload that reaches arbitrary code execution. The page does not reproduce that payload.
flowchart TD
A[Untrusted page script in vm] --> B{Mitigation applied?}
B -->|None| C[Function constructor escape: RCE]
B -->|disallow-code-generation-from-strings| D[Prototype pollution: DoS or RCE]
B -->|frozen-intrinsics| E[Pollution blocked]
E --> F[Global reads and side-channels may remain]
F --> G[Add container or VM isolation]Preconditions / Affected
- You feed happy-dom pages or scripts you do not fully trust (crawlers, scrapers, SSR of partially trusted React components).
- JavaScript evaluation is on. After the first advisory the maintainer disabled it by default. The pollution PoC explicitly sets
enableJavaScriptEvaluation: true. - The page gives no affected or fixed version numbers. Check the two advisories for those.
What to do
- Avoid running untrusted JavaScript in happy-dom at all, if you can.
- If you must run it, start Node with the maintainer's recommended flags. The page names
--frozen-intrinsicsas the addition from CVE-2025-62410, alongside--disallow-code-generation-from-stringsfrom the first advisory:
node --disallow-code-generation-from-strings --frozen-intrinsicsThe page does not show the two flags combined in one command line. The command above is assembled from the flags it names.
- Wrap happy-dom in a Docker container or VM when scraping untrusted content. Endor Labs recommends this as extra protection.
- For any use of
vmon untrusted code, migrate to a real sandbox: - isolated-vm exposes V8 Isolates and gives stronger isolation, but struggles with arbitrary open-source libraries.
- Secure EcmaScript (Agoric's implementation of a Stage 1 proposal) freezes intrinsics and disallows dangerous constructs. It integrates third-party code well but isolation is more fragile.
Caveats
- Endor Labs believes
--frozen-intrinsicsstops pollution but that malicious code may still read global values from the host context or use side-channels. - The maintainer declined Endor Labs' suggestion to move to a secure sandbox because of the refactoring required, so the architecture remains
vm-based. - The same class of
vmescape led to the deprecation of vm2 (for example CVE-2021-23555) and realms-shim.
Organisations named here
- Agoric
- Secure EcmaScript
CVEs named here
- CVE-2025-61927
- CVE-2025-62410
- CVE-2021-23555
Technologies named here
- happy-dom - vulnerable to CVE-2025-61927 and CVE-2025-62410
- happy-dom
- Node.js vm module
- vm2
- Node.js flag --disallow-code-generation-from-strings
- realms-shim
- Node.js flag --frozen-intrinsics
- Docker container or virtual machine
- Node.js
- JavaScript
- isolated-vm
- Endor Labs
Techniques named here
- Prototype pollution gadgets leading to remote code execution
- Exception object references used to escape vm
- Prototype Pollution
- Sandbox escape
Related in AppSec
Flowise MCP Security Bypass Enables RCE
Inside an Oracle Database SQL Injection Attack | Huntress
OASIS
