Skip to main content

js-toml CVE-2026-50029

| EUVDEUVD-2026-58791 MEDIUM
Incorrect Comparison (CWE-697)
2026-06-26 https://github.com/sunnyadn/js-toml GHSA-m34p-749j-x6m6
5.3
CVSS 3.1 · Vendor: https://github.com/sunnyadn/js-toml
Share

Severity by source

Vendor (https://github.com/sunnyadn/js-toml) PRIMARY
5.3 MEDIUM
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
vuln.today AI
3.7 LOW

AC:H reflects that exploitation success depends on the host application using falsy TOML booleans for security gates, a condition outside attacker control.

3.1 AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N
4.0 AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N

Primary rating from Vendor (https://github.com/sunnyadn/js-toml).

CVSS VectorVendor: https://github.com/sunnyadn/js-toml

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
Low
Availability
None

Lifecycle Timeline

2
Source Code Evidence Fetched
Jun 26, 2026 - 23:16 vuln.today
Analysis Generated
Jun 26, 2026 - 23:16 vuln.today

DescriptionCVE.org

Summary

js-toml's interpreter checks whether a key already exists in a parser-built container with if (object[key]) instead of if (key in object). When the prior value is a falsy primitive - false, 0, 0n, 0.0, -0, or "" - the duplicate-key branch is skipped and the value is silently overwritten by a later sub-table, dotted-key sub-table, or array-of-tables sharing the same name. Per the TOML 1.0.0 spec ("Defining a key multiple times is invalid"; "You cannot define any key or table more than once"), this should be a parse error.

The result is structural type confusion of attacker-named keys in the value returned by load(). A boolean-typed false (or numeric 0) becomes a truthy object. Host applications that gate behavior on if (config.flag), if (!user.banned), if (config.allowDelete), or if (config.publicMode) will silently take the truthy branch.

This is distinct from GHSA-65fc-cr5f-v7r2 (the 1.0.2 prototype-pollution fix). Object.prototype is not polluted. The Object.create(null) mitigation from 1.0.2 is intact; the bug here is in the duplicate-key state machine, not in container construction.

Details

Two truthy checks are wrong:

src/load/interpreter.ts:214 - Interpreter.tryCreatingObject

js
if (object[key]) {            // falsy primitives slip through
    // duplicate-key logic
} else {
    object[key] = createSafeObject();   // silently overwrites the prior falsy value
    ...
}

src/load/interpreter.ts:278 - Interpreter.getOrCreateArray

js
if (object[first] && !Array.isArray(object[first])) {   // same flaw
    throw new DuplicateKeyError();
}
object[first] = object[first] || [];   // overwrites the prior falsy value

Both should use the in operator. Containers are created via Object.create(null), so in is unambiguous (no inherited keys to worry about).

The bug is reachable through every parent-walking interpreter path:

  • assignValue - dotted keys in key = value
  • createTable - [stdTable] headers
  • getOrCreateArray - [[arrayOfTables]] headers

PoC

toml
isAdmin = false
[isAdmin]
forced = "yes"
js
import { load } from 'js-toml';

const config = load(`
isAdmin = false
[isAdmin]
forced = "yes"
`);

console.log(JSON.stringify(config));
// {"isAdmin":{"forced":"yes"}}

console.log(config.isAdmin ? 'BYPASS' : 'safe');
// BYPASS

if (config.isAdmin) {
  // attacker reaches admin-only code
}

Impact

Spec-violating input acceptance leading to structural type confusion. (CWE-697)

Suggested fix

in src/load/interpreter.ts

diff
export class Interpreter extends BaseCstVisitor {
     ignoreImplicitDeclared,
     ignoreExplicitDeclared
   ) {
-    if (object[key]) {
+    if (key in object) {
       if (
         !isPlainObject(object[key]) ||
         (!ignoreExplicitDeclared &&
diff
export class Interpreter extends BaseCstVisitor {
       return this.getOrCreateArray(keys, object[first], idx + 1);
     }

-    if (object[first] && !Array.isArray(object[first])) {
+    if (first in object && !Array.isArray(object[first])) {
       throw new DuplicateKeyError();
     }

     object[first] = object[first] || [];

AnalysisAI

Silent type confusion in js-toml's TOML interpreter allows attacker-controlled input to overwrite falsy primitive values (false, 0, empty string) with truthy objects, defeating duplicate-key enforcement required by TOML 1.0.0 spec. All versions of js-toml up to and including 1.1.1 are affected via the npm package (pkg:npm/js-toml). Attackers who can supply TOML input to an application using this parser can cause security-gated boolean checks such as if (config.isAdmin) or if (!user.banned) to silently evaluate as truthy, enabling authentication bypass. A working proof-of-concept is publicly available in the GitHub security advisory GHSA-m34p-749j-x6m6; no confirmed active exploitation (CISA KEV) has been identified at time of analysis.

Technical ContextAI

js-toml is an npm library that parses TOML configuration files into JavaScript objects. The root cause is CWE-697 (Incorrect Comparison): two locations in src/load/interpreter.ts use JavaScript truthy checks (if (object[key])) rather than the semantically correct membership test (if (key in object)) to detect whether a key already exists in a parser-built container. Because JavaScript's truthiness coerces false, 0, 0n, -0, 0.0, and '' to boolean false, the duplicate-key detection branch is skipped when the existing value is any of these falsy primitives. A later sub-table header ([key]), dotted-key sub-table, or array-of-tables ([[key]]) sharing the same name then silently overwrites the falsy scalar with a truthy object. The affected paths are Interpreter.tryCreatingObject (line 214) and Interpreter.getOrCreateArray (line 278). Notably, the Object.create(null) fix introduced in 1.0.2 for GHSA-65fc-cr5f-v7r2 (prototype pollution) is unrelated and does not mitigate this flaw; the bug is in the duplicate-key state machine, not container construction. The CPE is pkg:npm/js-toml with vulnerable range <= 1.1.1.

RemediationAI

Upgrade js-toml to version 1.1.2, which replaces both truthy checks (if (object[key]) and if (object[first] && ...)) with the correct in-operator membership tests in src/load/interpreter.ts. The fix is confirmed per the GitHub advisory at https://github.com/sunnyadn/js-toml/security/advisories/GHSA-m34p-749j-x6m6. If an immediate upgrade is not possible, the most effective compensating control is to validate parsed TOML output before using it in security decisions: explicitly check typeof config.flag = 'boolean' rather than relying on truthiness, e.g., replace if (config.isAdmin) with if (config.isAdmin = true). This validation adds a type assertion layer at zero functional cost but must be applied at every security gate. An additional measure is to reject or sanitize TOML input containing sub-tables whose names shadow previously defined scalar keys, though this requires application-level TOML pre-inspection. Do not treat the Object.create(null) mitigation from 1.0.2 as covering this issue - it does not.

Share

CVE-2026-50029 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy