Sep 4, 2026·6 min read·1 visit
Improper key verification and unrestricted recursive object traversal in toml-node's compiler logic allow remote attackers to poison Object.prototype via crafted TOML input, enabling prototype pollution.
A prototype pollution vulnerability exists in the toml-node library (by BinaryMuse) in versions prior to 4.1.2. The flaw arises from inconsistent internal tracking of parsed paths (comma-joined vs. dot-joined serialization) combined with lack of object ownership validation during recursive dictionary descent (scalar descent). This allows unauthenticated remote attackers to modify base object structures by crafting malicious TOML documents containing conflicting duplicate table paths or nested references.
The toml-node library is a standard package used to parse TOML configuration data in Node.js environments. The core vulnerability is categorized under CWE-1321 (Improperly Controlled Modification of Object Prototype Attributes, or 'Prototype Pollution'). By feeding a specifically structured input to toml.parse(), an attacker can bypass duplicate-key detection mechanisms and force the engine to write properties onto the global Object.prototype dictionary.
In standard applications, configuration files are often treated as trusted inputs. However, in scenarios where users can supply configurations dynamically, such as API configurations, dashboard layouts, or serverless configuration payloads, this parser vulnerability opens up a significant unauthenticated remote execution attack vector.
Because most JavaScript objects inherit directly from Object.prototype, any successful injection of key-value pairs becomes immediately visible to all objects across the active Node.js application process. This global state mutation can lead to downstream property injection attacks, process crashes, or arbitrary command execution depending on the existence of vulnerable gadget paths within other loaded dependencies.
The compiler within lib/compiler.js tracks traversed table pathways to ensure they are not declared more than once, as dictated by the TOML specification. Two main data structures are tasked with this state tracking: assignedPaths and valueAssignments. When evaluating and enforcing duplicate boundaries, the library relies on exact string matching of serialized path segments.
However, a path serialization desynchronization occurs because the engine records values inside the track sets using inconsistent formats. Value assignments generate implicit or comma-separated representations such as a,b.y, while the internal lookup function deepRef() formats keys using a standard dot-separated representation like a.b.y. Because of this structural mismatch, validation queries against the tracking sets fail to find existing records, silently bypassing duplicate-key detection checks.
Furthermore, when a table definition specifies a nested path (for instance, [a.b.y.__proto__.__proto__]), the loop resolves the prefix a.b.y. If a.b.y was previously defined as a scalar value (like a Number 1), resolving the field __proto__ returns the native prototype of that scalar (e.g., Number.prototype). The subsequent resolution of __proto__ accesses Object.prototype, where the compiler then writes arbitrary properties without verifying ownership of the destination dictionary. This behavior is termed Scalar Descent.
The patch implemented in version 4.1.2 mitigates this flaw by introducing a strict ownership mechanism and unifying path serialization helpers. Below is a structured analysis of the code-level modifications in lib/compiler.js.
// BEFORE THE PATCH:
var currentPath = "";
// AFTER THE PATCH:
var currentPath = [];
var ownedContainers = new WeakSet();
var data = createTable();By tracking the current path as an array rather than an inline flat string, the compiler avoids the serialization desynchronization. The addition of the ownedContainers WeakSet provides a robust mechanism to differentiate between compiled TOML dictionaries and native JavaScript prototypes.
During traversal inside deepRef(), the patched code enforces strict object-ownership checks:
// Post-patch recursive lookup safety check:
if (i < keys.length - 1) {
if (!isOwnedContainer(ctx)) {
genError("Cannot redefine existing key '" + traversedPath + "'.", off);
}
if (ctx instanceof Array) {
if (!ctx.length) {
genError("Cannot redefine existing key '" + traversedPath + "'.", off);
}
ctx = ctx[ctx.length - 1];
if (!isOwnedContainer(ctx)) {
genError("Cannot redefine existing key '" + traversedPath + "'.", off);
}
}
}These modifications successfully halt the traversal process if the parser descends into any object reference that is not explicitly registered within the ownedContainers set. Any attempt to access native prototypes will trigger a validation error, preventing modifications to parent object structures.
An attacker can exploit this flaw through two primary vectors. The first vector is through direct scalar descent, where a scalar value is declared and subsequently leveraged to reference ancestral prototypes. The second vector utilizes table arrays to bypass the parser's nesting constraints.
Consider the scalar descent exploit vector below. The payload first instantiates a scalar key y containing an integer, then immediately redefines a table using that key to walk back through the prototype chains:
[a.b]
y = 1
[a.b.y.__proto__.__proto__]
polluted = "yes"When toml.parse() processes this payload, it creates the scalar y. Upon processing the subsequent table definition, deepRef() crawls into a.b.y, accesses (1).__proto__ to reach Number.prototype, and crawls again to reach Object.prototype. Finally, it sets Object.prototype.polluted = "yes", executing a successful system-wide modification.
The impact of prototype pollution in Node.js depends heavily on other active libraries and application logic. If downstream code uses uninitialized objects or conducts unsafe merges of configuration hashes, an attacker can manipulate program flow control.
For example, if the application invokes subprocesses via child_process.spawn or child_process.fork, the runtime looks up properties on the options parameter. An attacker who has successfully polluted properties such as shell or env can force the application to execute arbitrary binary payloads. This transitions prototype pollution from a passive property injection directly into an unauthenticated remote execution scenario.
Additionally, polluting properties like toString, valueOf, or basic loop attributes can disrupt standard system functionality, leading to persistent denial of service (DoS) conditions where the entire Node.js server crashes upon loading.
The recommended approach to address this vulnerability is upgrading toml-node to version 4.1.2 or later. This version contains the complete rewrite of the path serialization engine and introduces runtime WeakSet ownership validation.
In scenarios where dependency upgrades are blocked, application operators can use CLI flags to secure the runtime environment. Running Node.js with the --disable-proto flag disables the __proto__ property completely across all native contexts:
node --disable-proto=delete app.jsAlternatively, developers can execute Object.freeze(Object.prototype) inside the main application entry point. This locks down the base dictionary against runtime modification, though it may trigger errors in legacy libraries that dynamically extend global prototypes. A mitigation function can also be used to filter incoming configuration streams for dangerous object keywords like __proto__ and constructor before forwarding the payload to the parser.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
toml-node BinaryMuse | < 4.1.2 | 4.1.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1321 |
| Attack Vector | Network (Unauthenticated) |
| CVSS v3.1 Score | 8.2 (High) |
| Exploit Status | Proof of Concept (PoC) available |
| KEV Status | Not Listed |
| EPSS Score | 0.00383 |
| Impact Category | Integrity (High), Availability (Low) |
The software receives input from an upstream component, but does not neutralize or incorrectly neutralizes special elements that could modify the system-wide prototype structure, enabling attackers to inject properties that alter base object structures.
An improper link resolution vulnerability (CWE-59) in the image_analyze tool of CodeWhale allows remote attackers to traverse directories (CWE-22) and leak sensitive local files via symlink manipulation.
An unauthenticated SQL injection and SQL execution vulnerability in SiYuan allows remote attackers to compromise the integrity and confidentiality of the asset database. The flaw exists due to string concatenation in regular expression searches and a complete lack of authorization checks on raw SQL querying pathways under default configurations. Attackers can leverage this vulnerability to exfiltrate database contents, manipulate index records, or access cross-notebook contents without any valid credentials.
CVE-2026-68587 is a critical authorization bypass vulnerability in SiYuan, an open-source personal knowledge management workspace. When deployed in publish mode, specific transaction endpoints fail to perform administrative role validation. This omission enables unauthenticated remote readers to retrieve the rendered Document Object Model (DOM) of publish-disabled (private) documents by supplying a target heading block identifier. Upgrading to version v3.7.3 or later resolves this issue by applying appropriate routing middleware constraints.
SiYuan is a privacy-first personal knowledge management system. In versions prior to v3.7.3, the application fails to apply publish-access filters to the getBacklinkDoc and getBackmentionDoc content endpoints (/api/ref/getBacklinkDoc and /api/ref/getBackmentionDoc). While the corresponding backlink list endpoints correctly filter out publish-forbidden documents, the content endpoints, which are only gated by high-level route authorization checks via CheckAuth, do not. Consequently, a user with low-privilege read access, or an anonymous reader when publish Basic Auth is disabled, can directly invoke these endpoints using a known publish-forbidden document's ID to retrieve its rendered DOM content or determine whether it references a specific target block.
A metadata disclosure vulnerability exists in SiYuan prior to version v3.7.3. The /api/block/getBlockInfo endpoint fails to validate authorization boundaries in publish mode, allowing anonymous readers to access private document metadata.
A critical authorization bypass vulnerability exists in SiYuan personal knowledge management system before v3.7.4. The /api/ref/refreshBacklink endpoint lacks administrative role verification, enabling unauthenticated users to initiate database transactions and disk operations. When combined with an unsafe SQL generation pattern in nested backlink queries, an attacker can exploit a secondary SQL injection vulnerability to compromise local databases or cause denial-of-service conditions.