GHSA-x7mm-9vvv-64w8: unhead Streaming SSR `streamKey` Injected Into Vulnerability

LOW
CWE-79
Published
Advisory Summary

GHSA-x7mm-9vvv-64w8 is a LOW streaming ssr `streamkey` injected into vulnerability (CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')) affecting unhead libraries in the npm ecosystem. The issue involves streaming ssr `streamkey` injected into inline script without identifier validation. Remediation is available by upgrading affected packages to version 3.0.1.

GHSA-x7mm-9vvv-64w8 at a Glance

CVE Identifier N/A
GHSA Identifier GHSA-x7mm-9vvv-64w8
Severity LOW
CVSS v3.1 Base Score N/A
CWE Classification CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Affected Product unhead
Package Ecosystem npm
Published Date
Last Updated

How to Fix GHSA-x7mm-9vvv-64w8

To remediate this vulnerability, upgrade all affected unhead dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

unhead fixed: 3.0.1
npm install unhead@3.0.1
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

npm ls unhead

How to Check if You Are Affected

To determine whether your Node.js application is affected by GHSA-x7mm-9vvv-64w8, inspect your project dependencies using npm:

npm ls unhead

Analyze the terminal output to locate any version of unhead in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 3.0.1), your application is affected.

Note: The npm ls unhead command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting'), where the product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users. In unhead, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Summary `createStreamableHead({ streamKey })` interpolated its `streamKey` argument directly into the streaming SSR bootstrap and suspense-chunk inline scripts without identifier validation or escaping. If an application forwards untrusted data into that configuration value, the rendered scripts become a script-injection sink. ### Details `streamKey` was embedded into JavaScript source via dot notation in two public helpers: * `createBootstrapScript()` returned `<script>window.${streamKey}={...}</script>` * `renderSSRHeadSuspenseChunk()` returned `window.${streamKey}.push(...)` No escaping, quoting, or identifier validation was applied before these strings were embedded into HTML. A `streamKey` such as `__unhead__;globalThis.PWNED=1;//` broke out of the intended property access and injected arbitrary JavaScript into the page. The JSON escaping used for streamed head entries did not protect `streamKey` because `streamKey` was inserted as raw code rather than as serialized data. ### Impact `streamKey` is a developer-chosen configuration value rather than a data field — the intended usage is a hardcoded identifier-shaped constant (default `__unhead__`). Exploitation therefore requires an application to explicitly route untrusted input into a configuration sink, which is not a documented or recommended pattern. We have no reports of any downstream project sourcing `streamKey` from request data. Applications using the default `streamKey`, or any hardcoded custom key, are **not affected**. ### PoC ```ts import { createStreamableHead, renderSSRHeadShell } from 'unhead/stream/server' const { head } = createStreamableHead({ streamKey: '__unhead__;globalThis.PWNED=1;//', }) const html = renderSSRHeadShell( head, '<!doctype html><html><head></head><body></body></html>', ) // <!doctype html><html><head><script>window.__unhead__;globalThis.PWNED=1;//={_q:[],push(e){this._q.push(e)}}</script>… ``` ### Patch Fixed on `main` in [`64b5ac0`](https://github.com/unjs/unhead/commit/64b5ac0aa30cc256ea6677ce3dc4f132f81b2ff6). The fix will ship in the next patch release of `unhead`. `streamKey` is now validated against a conservative ASCII JavaScript-identifier pattern (`/^[$_a-z][$\w]*$/i`) at every sink — `createStreamableHead`, `createBootstrapScript`, and the internal stream-key resolver. Invalid values throw immediately instead of being emitted into script output. ### Workarounds Do not pass untrusted data into `createStreamableHead({ streamKey })` or `createBootstrapScript(key)`. If per-tenant keys are required, whitelist them against an identifier-safe pattern before constructing the head instance. ### Credit Thanks to @Jvr2022 for the report.

GHSA-x7mm-9vvv-64w8 Affected unhead Versions

1 component(s)
Fixed Versions:
3.0.1
Product / Package Ecosystem Affected Versions Fixed Version
unhead
npm
≥ 3.0.0-beta.5
< 3.0.1
3.0.1

References

Frequently Asked Questions

What is GHSA-x7mm-9vvv-64w8?
GHSA-x7mm-9vvv-64w8 is a security vulnerability in unhead involving Streaming SSR `streamKey` injected into inline script without identifier validation under CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting').
Which unhead versions are affected?
Affected versions include releases prior to 3.0.1 across affected packages: unhead.
What version fixes GHSA-x7mm-9vvv-64w8?
Upgrading to 3.0.1 (or the latest patched release for your respective branch) resolves the vulnerability.
Is unhead affected?
Yes, unhead is affected in releases prior to 3.0.1. Upgrade your dependency to 3.0.1 or later.
What CWE is associated with GHSA-x7mm-9vvv-64w8?
GHSA-x7mm-9vvv-64w8 is classified under CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.).
How can I check npm dependencies for GHSA-x7mm-9vvv-64w8?
Run the dependency tree command: 'npm ls unhead'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-x7mm-9vvv-64w8",
  "modified" : "2026-04-10T22:09:39Z",
  "published" : "2026-04-10T22:09:39Z",
  "aliases" : [ ],
  "summary" : "unhead: Streaming SSR `streamKey` injected into inline script without identifier validation",
  "details" : "### Summary\n\n`createStreamableHead({ streamKey })` interpolated its `streamKey` argument directly into the streaming SSR bootstrap and suspense-chunk inline scripts without identifier validation or escaping. If an application forwards untrusted data into that configuration value, the rendered scripts become a script-injection sink.\n\n### Details\n\n`streamKey` was embedded into JavaScript source via dot notation in two public helpers:\n\n* `createBootstrapScript()` returned `<script>window.${streamKey}={...}</script>`\n* `renderSSRHeadSuspenseChunk()` returned `window.${streamKey}.push(...)`\n\nNo escaping, quoting, or identifier validation was applied before these strings were embedded into HTML. A `streamKey` such as `__unhead__;globalThis.PWNED=1;//` broke out of the intended property access and injected arbitrary JavaScript into the page. The JSON escaping used for streamed head entries did not protect `streamKey` because `streamKey` was inserted as raw code rather than as serialized data.\n\n### Impact\n\n`streamKey` is a developer-chosen configuration value rather than a data field — the intended usage is a hardcoded identifier-shaped constant (default `__unhead__`). Exploitation therefore requires an application to explicitly route untrusted input into a configuration sink, which is not a documented or recommended pattern. We have no reports of any downstream project sourcing `streamKey` from request data.\n\nApplications using the default `streamKey`, or any hardcoded custom key, are **not affected**.\n\n### PoC\n\n```ts\nimport { createStreamableHead, renderSSRHeadShell } from 'unhead/stream/server'\n\nconst { head } = createStreamableHead({\n  streamKey: '__unhead__;globalThis.PWNED=1;//',\n})\n\nconst html = renderSSRHeadShell(\n  head,\n  '<!doctype html><html><head></head><body></body></html>',\n)\n\n// <!doctype html><html><head><script>window.__unhead__;globalThis.PWNED=1;//={_q:[],push(e){this._q.push(e)}}</script>…\n```\n\n### Patch\n\nFixed on `main` in [`64b5ac0`](https://github.com/unjs/unhead/commit/64b5ac0aa30cc256ea6677ce3dc4f132f81b2ff6). The fix will ship in the next patch release of `unhead`.\n\n`streamKey` is now validated against a conservative ASCII JavaScript-identifier pattern (`/^[$_a-z][$\\w]*$/i`) at every sink — `createStreamableHead`, `createBootstrapScript`, and the internal stream-key resolver. Invalid values throw immediately instead of being emitted into script output.\n\n### Workarounds\n\nDo not pass untrusted data into `createStreamableHead({ streamKey })` or `createBootstrapScript(key)`. If per-tenant keys are required, whitelist them against an identifier-safe pattern before constructing the head instance.\n\n### Credit\n\nThanks to @Jvr2022 for the report.",
  "severity" : [ {
    "type" : "CVSS_V4",
    "score" : "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "unhead"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "3.0.0-beta.5"
      }, {
        "fixed" : "3.0.1"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 3.0.0"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/unjs/unhead/security/advisories/GHSA-x7mm-9vvv-64w8"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/unjs/unhead/commit/64b5ac0aa30cc256ea6677ce3dc4f132f81b2ff6"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/unjs/unhead"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-79" ],
    "severity" : "LOW",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-04-10T22:09:39Z",
    "nvd_published_at" : null
  }
}