Sep 3, 2026·6 min read·29 visits
A stack exhaustion vulnerability in toml-node allows remote attackers to crash Node.js application servers by submitting deeply nested arrays or inline tables, triggering a process-terminating RangeError.
An uncontrolled recursion vulnerability (CWE-674) in the toml-node NPM package (published as toml) prior to version 4.2.0 allows unauthenticated remote attackers to trigger process-wide Denial of Service (DoS) crashes. By submitting TOML payloads with deep bracket or brace nesting, attackers exhaust the V8 runtime stack limit.
The toml-node library (published as toml on the NPM registry) is an engine used to parse TOML (Tom's Obvious Minimal Language) configuration files and payloads in Node.js applications. In microservices and web applications, configurations or incoming API requests may be represented in TOML formats. This library acts as the primary deserialization mechanism for such datasets.
Prior to version 4.2.0, the core parser implemented in toml-node is susceptible to uncontrolled recursion when processing deeply nested arrays or inline tables. An attacker who is able to submit crafted inputs to an application using this library can consume all available stack frames, triggering an unhandled exception. This exhaustion happens because the parsing logic performs a sequence of function calls that maps directly to input nesting depth.
Because Node.js operates on a single-threaded event loop by default, an uncaught runtime error of this nature does not merely fail the individual transaction. Instead, it crashes the entire node process. This behavior elevates the impact of a simple parsing exception to an application-wide Denial of Service (DoS) state.
The root cause of CVE-2026-77465 lies in the mutual recursion defined in the parser's PEGjs grammar file (src/toml.pegjs). toml-node utilizes Peggy (specifically version 5.1.0) to generate its parser code. Peggy compiles Parsing Expression Grammars into recursive-descent parsers, where each grammar rule compiles into a JavaScript function.
In the vulnerable grammar structure, the rules governing values, arrays, and inline tables reference each other recursively. Specifically, the value rule can match an array or an inline_table. An array contains nested elements that must be evaluated against the value rule, and an inline_table contains key-value pairs where each value is again parsed using the value rule.
When processing nesting, the generated parser executes a series of nested function calls. This process repeats for every level of nesting in the input string. This pattern forms a direct recursion path: peg$parsevalue to peg$parsearray to peg$parsevalue.
The V8 engine utilized by Node.js maintains a platform-dependent call stack size limit, typically ranging from 10,000 to 104,000 frames. Because there are no limits on the depth of the recursive calls inside the toml-node grammar, a highly nested payload easily exhausts this allocation. This results in a synchronous, uncatchable RangeError exception.
In vulnerable versions of toml-node, the src/toml.pegjs grammar file does not track depth. The rules evaluate child elements recursively without checking how deep the execution flow has descended. The patch introduced in commit 967b8b06754f3ecd9863cea118dc50792a8c353f mitigates this vulnerability by tracking state and establishing a maximum depth limit.
Below is a simplified differential analysis of the grammar modifications implemented to fix this vulnerability:
// --- PATCH ADDITIONS IN INITIALIZATION BLOCK ---
// A maximum depth option is introduced, defaulting to 500
var depth = 0;
var MAX_DEPTH = (options && options.maxDepth != null) ? options.maxDepth : 500;// --- GRAMMAR RULE PATCH ---
// Vulnerable Grammar:
// value = string / number_or_date / boolean / array / inline_table
// Patched Grammar:
// The value rule now uses a semantic predicate to check depth
value
= &{ if (++depth > MAX_DEPTH) { depth--; genError("Maximum nesting depth of " + MAX_DEPTH + " exceeded.", offset()); } return true; }
v:value_choice { return v; }
value_choice
= v:value_body { depth--; return v; }
/ &{ depth--; return false; }
value_body
= string / number_or_date / boolean / array / inline_tableThe implementation uses a semantic predicate &{ ... } to increment depth. If the limit is reached, it decrements the counter to maintain alignment and generates a parse error. The value_choice rule ensures that whether parsing succeeds (via value_body) or fails (triggering backtracking), the depth counter is correctly decremented.
Exploitation of CVE-2026-77465 requires no privileges and can be executed via any interface that accepts TOML payloads and feeds them directly into toml.parse(). Since many microservices accept user-defined config data, settings, or request payloads in TOML format, the attack vector remains highly accessible.
To trigger the crash, an attacker prepares a payload containing thousands of nested brackets or braces. The payload is designed to force the recursive descent parser into thousands of self-referencing loops, quickly exceeding the call stack limit of the target host.
An attacker can construct a payload consisting of a variable containing 10,000 nested arrays:
a = [[[[[[...[1]...]
Alternatively, the attacker can use a payload consisting of nested inline tables:
a = {b={b={b={...{b=1}...}}}}
The execution of toml.parse() on this payload will immediately trigger the uncaught RangeError, resulting in the failure of the application thread. Because Node.js single-threaded applications usually lack automatic recovery wrappers around parse libraries, the entire process terminates, disrupting services for all active users.
The technical impact of CVE-2026-77465 is classified as a High-severity Denial of Service (DoS) vulnerability, holding a CVSS score of 7.5. Because the vulnerability is exploited over the network (AV:N) with low complexity (AC:L) and requires no special privileges (PR:N) or victim interaction (UI:N), it poses a significant threat to internet-exposed Node.js systems processing untrusted TOML data.
Although this vulnerability does not allow for Remote Code Execution (RCE) or information disclosure (C:N/I:N), the ease with which an attacker can disrupt services makes it an attractive target. A single HTTP request with a small payload (less than 50 KB) containing the nested structures is sufficient to take down a backend worker.
In cloud environments where auto-scaling or container orchestrators (such as Kubernetes) are configured, a continuous stream of such payloads can cause a crash-loop backoff state. This exhausts container resources, incurs high cloud-billing costs, and prevents legitimate users from accessing the system.
The fix implemented in toml-node version 4.2.0 is highly robust because of how it handles the parsing state during backtracking. In PEG engines, the parser frequently backtracks when a matched path fails to satisfy a rule, reverting to try a different configuration.
If a naive depth counter had been used (e.g., simply incrementing at the start of a rule and decrementing at the end of a successful match), a backtracking action would have skipped the decrement. This would lead to a "depth leak", where the counter remains elevated despite the parser descending back to a shallow depth, eventually resulting in false-positive blocks on valid, shallow TOML elements.
By structuring the logic with value_choice and implementing a backtrack-reverting alternative predicate (/ &{ depth--; return false; }), the developer ensured that the state tracking is transactionally aligned. Security researchers have evaluated this patch and confirmed that the depth tracking handles backtracking safely, making the fix highly resilient.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
toml-node BinaryMuse | < 4.2.0 | 4.2.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-674 |
| Attack Vector | Network |
| CVSS Score | 7.5 (High) |
| EPSS Score | Not currently assigned |
| Impact | Denial of Service (DoS) |
| Exploit Status | Proof-of-concept |
| KEV Status | Not listed |
The product code contains a recursive function but lacks a structural check to ensure the call stack does not overflow.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.
Contao Open Source CMS versions 4.0.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 contain a Cross-Site Request Forgery (CSRF) vulnerability in backend parameter handling. The `RequestTokenListener` component validates anti-CSRF tokens solely for HTTP POST requests, while GET-based declarative guards run only when an `act` parameter is present in the query string. Consequently, custom backend actions dispatched via alternative parameters such as `key=` can execute without CSRF token verification when triggered by an authenticated user.
Contao CMS versions 4.1.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 fail to validate form submission tokens and enforce rate limiting when processing activation email resend requests via HTTP POST, enabling resource exhaustion and account state enumeration.
An information disclosure vulnerability in Contao CMS allows unauthenticated site visitors to view protected page titles, URLs, and text excerpts through search queries when protected page indexing is disabled after previously being enabled.
In Vikunja prior to version 2.6.0, relation creation via the CalDAV endpoint fails to invoke the TaskRelation.CanCreate authorization check. This missing access control allows an authenticated user to establish unauthorized relationships and perform write operations against any task, provided its unique identifier (UID) is known.
A cross-project information disclosure vulnerability in Vikunja allows authenticated users with read access to one project to view private task details from unauthorized projects via subtask expansion parameters.