CVE-2026-115895: CVE-2026-115895: Code Injection via Unsanitized Import Alias in Happy DOM ECMAScript Module Compiler
CVE-2026-115895: Code Injection via Unsanitized Import Alias in Happy DOM ECMAScript Module Compiler Vulnerability ID: CVE-2026-115895 CVSS Score: 8.8 Published: 2026-10-23 CVE-2026-115895 is a high-severity code in
CVE-2026-115895: Code Injection via Unsanitized Import Alias in Happy DOM ECMAScript Module Compiler
Vulnerability ID: CVE-2026-115895
CVSS Score: 8.8
Published: 2026-10-23
CVE-2026-115895 is a high-severity code injection vulnerability (CWE-94) in the happy-dom npm package prior to version 21.0.4. The vulnerability exists within the ECMAScriptModuleCompiler component, which transforms ECMAScript module syntax into executable Node.js functions when JavaScript evaluation is enabled. Due to an incomplete fix for CVE-2026-33943, the compiler failed to validate local named import aliases against legal JavaScript identifier rules. Attackers supplying crafted module importsβspecifically utilizing destructuring default initializers alongside JSON module attributesβcan inject arbitrary JavaScript expressions directly into the host Node.js runtime context.
TL;DR
An incomplete fix for CVE-2026-33943 in happy-dom versions 17.0.0 through 21.0.3 allows arbitrary code execution on the host Node.js server when JavaScript evaluation is enabled. By crafting an ECMAScript module import with an unsanitized alias containing a destructuring default value and a JSON import attribute, an attacker can execute arbitrary Node.js code during module compilation and instantiation.
β οΈ Exploit Status: POC
Technical Details
- CVE ID: CVE-2026-115895 (GHSA-834v-8h66-3h79)
- Vulnerability Class: CWE-94: Improper Control of Generation of Code (Code Injection)
- CVSS v3.1 Score: 8.8 High (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)
- Affected Component: happy-dom (ECMAScriptModuleCompiler.ts)
- Affected Versions: >= 17.0.0, < 21.0.4
- Patched Version: 21.0.4
- EPSS Score: 0.56% (45.78th Percentile)
- CISA KEV Status: Not Listed
Affected Systems
- happy-dom npm package (>= 17.0.0, < 21.0.4)
-
happy-dom: >= 17.0.0, < 21.0.4 (Fixed in:
21.0.4)
Code Analysis
Commit: fd16352
Validate local binding identifiers in ECMAScriptModuleCompiler and sanitize imported property names (#2537)
diff --git a/packages/happy-dom/src/module/ECMAScriptModuleCompiler.ts b/packages/happy-dom/src/module/ECMAScriptModuleCompiler.ts
index c6b9e28..a40bf5e 100644
--- a/packages/happy-dom/src/module/ECMAScriptModuleCompiler.ts
+++ b/packages/happy-dom/src/module/ECMAScriptModuleCompiler.ts
@@ -61,6 +61,11 @@ const IMPORT_REGEXP = /{([^}]+)}|\*\s+as\s+([a-zA-Z0-9-_$]+)|([a-zA-Z0-9-_$]+)/g
*/
const VALID_VARIABLE_NAME_REGEXP = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
+/**
+ * Valid local binding identifier regexp (supports Unicode identifiers).
+ */
+const VALID_BINDING_NAME_REGEXP = /^[\p{ID_Start}_$][\p{ID_Continue}$\u200c\u200d]*$/u;
+
/**
* Valid preceding token before a statement.
*/
@@ -274,8 +279,8 @@ export default class ECMAScriptModuleCompiler {
for (const part of parts) {
const nameParts = part.trim().split(/\s+as\s+/);
const alias = (nameParts[1] || nameParts[0]).replace(/["']/g, '');
- const name = nameParts[0].replace(/["']/g, '');
- if (alias && name) {
+ const name = nameParts[0].replace(/["'\\\r\n\u2028\u2029]/g, '');
+ if (alias && name && VALID_BINDING_NAME_REGEXP.test(alias)) {
if (name === alias) {
properties.push({ name });
} else {
@@ -286,7 +291,7 @@ export default class ECMAScriptModuleCompiler {
if (!match[7] || match[7] === 'esm') {
resolvableCircularImports.push({ url, properties });
}
- newCodeStart += `let {${properties.map((property) => (property.alias ? `"${property.name}": ${property.alias}` : property.name)).join(', ')}} = $happy_dom.imports.get('${url}')${match[8]}`;
+ newCodeStart += `let {${properties.map((property) => (property.alias ? `${JSON.stringify(property.name)}: ${property.alias}` : property.name)).join(', ')}} = $happy_dom.imports.get('${url}')${match[8]}`;
} else if (importMatch[2]) {
// Import all as
newCodeStart += `const ${importMatch[2]} = $happy_dom.imports.get('${url}')${match[8]}`;
Mitigation Strategies
- Upgrade happy-dom to version 21.0.4 or later to enforce strict identifier validation on ECMAScript module import aliases.
- Disable JavaScript evaluation in happy-dom configuration settings (enableJavaScriptEvaluation: false) when parsing untrusted HTML or when script execution is not required.
- Isolate happy-dom execution within dedicated, least-privilege containers or sandboxes when evaluating untrusted third-party scripts or markup.
Remediation Steps:
- Check the installed version of happy-dom in your project using 'npm ls happy-dom'.
- Update package.json to require 'happy-dom': '^21.0.4' and run 'npm install' or 'npm update happy-dom'.
- Audit application code for instances of 'new Window()' or 'new Browser()' and ensure 'settings.enableJavaScriptEvaluation' is set to 'false' unless explicitly required for trusted code.
- Verify the fix by running your test suite and confirming lockfile resolution points to happy-dom >= 21.0.4.
References
- CVE-2026-115895 Official Record
- NVD Advisory for CVE-2026-115895
- GitHub Security Advisory GHSA-834v-8h66-3h79
- GitHub Pull Request #2537
- GitHub Fix Commit fd163520b74d9fa146be91f7b4e4f46d6cccbe13
- Happy DOM Release v21.0.4
- CVE List V5 JSON Record
Read the full report for CVE-2026-115895 on our website for more details including interactive diagrams and full exploit analysis.
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.