js-toml CVE-2026-50029
MEDIUMSeverity 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 GitHub Advisory.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Lifecycle Timeline
2DescriptionGitHub Advisory
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). …
Unlock full vulnerability intelligence
- Risk assessment & exploitation conditions
- Attack chain visualization
- Remediation with exact patch versions
- Threat intelligence from 22 sources
- Personal watchlist & email alerts
Free forever · No credit card required
Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata
Vulnerability AssessmentAI
| Exploitation | Exploitation requires three concurrent conditions: (1) the attacker can supply or influence the TOML content that is parsed by js-toml - for example, a user-uploaded config file, a network-delivered configuration payload, or a TOML fragment embedded in attacker-controlled data; (2) the host application is running js-toml version 1.1.1 or earlier; (3) the host application gates security-relevant behavior on the truthiness of a TOML-parsed value that could legitimately be false, 0, 0n, -0, 0.0, or an empty string - specifically patterns like if (config.isAdmin), if (!user.banned), if (config.allowDelete), or if (config.publicMode). … Additional conditions and limiting factors are described in the full assessment. |
| Risk Assessment | The NVD-assigned CVSS 3.1 vector (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N, score 5.3 Medium) treats the flaw as low-complexity unauthenticated network exploitation with limited integrity impact. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in. |
| Exploit Scenario | An attacker submits a crafted TOML document to an application that uses js-toml to parse user-supplied or attacker-influenced configuration. The document sets a security flag to false (isAdmin = false) and then defines a sub-table with the same name ([isAdmin] with an arbitrary key-value pair). … |
| Remediation | 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. … Detailed patch versions, workarounds, and compensating controls in full report. |
Threat intelligence, references, and detailed analysis are available after sign-in.
Same weakness CWE-697 – Incorrect Comparison
View allSame technique Authentication Bypass
View allShare
External POC / Exploit Code
Leaving vuln.today
GHSA-m34p-749j-x6m6