Severity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
AC:H reflects that exploitation success depends on the host application using falsy TOML booleans for security gates, a condition outside attacker control.
Primary rating from Vendor (https://github.com/sunnyadn/js-toml).
CVSS VectorVendor: https://github.com/sunnyadn/js-toml
Lifecycle Timeline
2DescriptionCVE.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
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
if (object[first] && !Array.isArray(object[first])) { // same flaw
throw new DuplicateKeyError();
}
object[first] = object[first] || []; // overwrites the prior falsy valueBoth 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 inkey = valuecreateTable-[stdTable]headersgetOrCreateArray-[[arrayOfTables]]headers
PoC
isAdmin = false
[isAdmin]
forced = "yes"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
export class Interpreter extends BaseCstVisitor {
ignoreImplicitDeclared,
ignoreExplicitDeclared
) {
- if (object[key]) {
+ if (key in object) {
if (
!isPlainObject(object[key]) ||
(!ignoreExplicitDeclared &&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.
Same weakness CWE-697 – Incorrect Comparison
View allSame technique Authentication Bypass
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-58791
GHSA-m34p-749j-x6m6