{"id":"GHSA-m34p-749j-x6m6","summary":"js-toml has silent type confusion via falsy-primitive duplicate-key bypass","details":"### Summary\n\n`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.\n\nThe 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.\n\nThis is **distinct** from [GHSA-65fc-cr5f-v7r2](https://github.com/sunnyadn/js-toml/security/advisories/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.\n\n### Details\n\nTwo truthy checks are wrong:\n\n`src/load/interpreter.ts:214` — `Interpreter.tryCreatingObject`\n\n```js\nif (object[key]) {            // falsy primitives slip through\n    // duplicate-key logic\n} else {\n    object[key] = createSafeObject();   // silently overwrites the prior falsy value\n    ...\n}\n```\n\n`src/load/interpreter.ts:278` — `Interpreter.getOrCreateArray`\n\n```js\nif (object[first] && !Array.isArray(object[first])) {   // same flaw\n    throw new DuplicateKeyError();\n}\nobject[first] = object[first] || [];   // overwrites the prior falsy value\n```\n\nBoth should use the `in` operator. Containers are created via `Object.create(null)`, so `in` is unambiguous (no inherited keys to worry about).\n\nThe bug is reachable through every parent-walking interpreter path:\n\n- `assignValue` — dotted keys in `key = value`\n- `createTable` — `[stdTable]` headers\n- `getOrCreateArray` — `[[arrayOfTables]]` headers\n\n### PoC\n\n```toml\nisAdmin = false\n[isAdmin]\nforced = \"yes\"\n```\n\n```js\nimport { load } from 'js-toml';\n\nconst config = load(`\nisAdmin = false\n[isAdmin]\nforced = \"yes\"\n`);\n\nconsole.log(JSON.stringify(config));\n// {\"isAdmin\":{\"forced\":\"yes\"}}\n\nconsole.log(config.isAdmin ? 'BYPASS' : 'safe');\n// BYPASS\n\nif (config.isAdmin) {\n  // attacker reaches admin-only code\n}\n```\n\n### Impact\n\nSpec-violating input acceptance leading to structural type confusion. (CWE-697)\n\n### Suggested fix\n\nin `src/load/interpreter.ts`\n\n```diff\nexport class Interpreter extends BaseCstVisitor {\n     ignoreImplicitDeclared,\n     ignoreExplicitDeclared\n   ) {\n-    if (object[key]) {\n+    if (key in object) {\n       if (\n         !isPlainObject(object[key]) ||\n         (!ignoreExplicitDeclared &&\n```\n```diff\nexport class Interpreter extends BaseCstVisitor {\n       return this.getOrCreateArray(keys, object[first], idx + 1);\n     }\n\n-    if (object[first] && !Array.isArray(object[first])) {\n+    if (first in object && !Array.isArray(object[first])) {\n       throw new DuplicateKeyError();\n     }\n\n     object[first] = object[first] || [];\n```","aliases":["CVE-2026-50029"],"modified":"2026-07-21T17:30:26.096074019Z","published":"2026-06-26T22:49:28Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2026-06-26T22:49:28Z","nvd_published_at":null,"cwe_ids":["CWE-697"],"severity":"MODERATE"},"references":[{"type":"WEB","url":"https://github.com/sunnyadn/js-toml/security/advisories/GHSA-m34p-749j-x6m6"},{"type":"WEB","url":"https://github.com/sunnyadn/js-toml/commit/e0504fa5d3dcde2d1d588c9001c24b7b700beeeb"},{"type":"PACKAGE","url":"https://github.com/sunnyadn/js-toml"},{"type":"WEB","url":"https://github.com/sunnyadn/js-toml/releases/tag/v1.1.2"}],"affected":[{"package":{"name":"js-toml","ecosystem":"npm","purl":"pkg:npm/js-toml"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"1.1.2"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-m34p-749j-x6m6/GHSA-m34p-749j-x6m6.json","last_known_affected_version_range":"\u003c= 1.1.1"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N"}]}