KEVWire

Security intelligence, with context.

Response snapshot Nov 4, 2026, 04:56 UTC

Back to the wire
Permalink
VulnerabilityCVE-2026-49293

js-toml vulnerable to CPU exhaustion via O(n^2) BigInt construction on radix-prefixed integer literals

js-toml versions up to and including 1.1.0 parse hexadecimal / octal / binary integer literals via a hand-written parseBigInt loop that multiplies a BigInt accumulator by the radix once per input digit.

At a glance

Exploited
Not known
Severity
7.5 High (CVSS 3.1)
Chance of exploitation
Not estimated
Sources
2 independent sources

What to do

GitHub lists first patched versions: js-toml: 1.1.2. Confirm the affected range and upgrade guidance in the exact advisory.

Read GitHub-reviewed advisory GHSA-wp3c-266w-4qfq (opens a new tab)

What happened

Summary

js-toml versions up to and including 1.1.0 parse hexadecimal / octal / binary integer literals via a hand-written parseBigInt loop that multiplies a BigInt accumulator by the radix once per input digit. Each iteration performs a BigInt * BigInt operation on an accumulator that grows linearly with the number of digits already consumed, so the whole loop is O(n²) in the literal length.

The lexer regex places no upper bound on the literal length, so a single TOML document containing one ~500 kB hex literal pins one CPU core for ~40 seconds on a modern laptop (Apple M-series, Node v22). Memory amplification is bounded but CPU amplification is severe and grows quadratically: doubling the literal length quadruples the work.

A caller that invokes load() on attacker-controlled TOML (configuration upload endpoints, CI/CD systems ingesting third-party *.toml, IDE plugins, build tools) is exposed to a single-request CPU exhaustion DoS.

Continue reading

CWE-1333 (Inefficient Regular Expression Complexity → here, inefficient parser complexity), CWE-400 (Uncontrolled Resource Consumption), CWE-407 (Inefficient Algorithmic Complexity).

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H = 7.5 (HIGH) when the parser is invoked on attacker-controllable input; LOW when the calling application restricts TOML input size to small documents ( = 0.0.0, { let result = BigInt(0); for (let i = 0; i { const intString = raw.replace(/_/g, ''); const digits = intString.slice(2); const radix = getRadix(raw);

const int = parseInt(digits, radix);

if (Number.isSafeInteger(int)) { return int; }

return parseBigInt(digits, radix); });


Two compounding problems:

1. **Algorithmic**: the loop performs `result * BigInt(radix) + BigInt(digit)` once per input digit. After `i` iterations `result` has `O(i)` limbs, so the multiply costs `O(i)`. Summed over `n` digits the total cost is `O(n²)`.

2. **No length guard**: the lexer regex at [`src/load/tokens/NonDecimalInteger.ts#L14-L46`](https://github.com/sunnyadn/js-toml/blob/2470ebf2e9009096aa4cbd1a15e574c54cc36b1a/src/load/tokens/NonDecimalInteger.ts#L14-L46) is `0x ( |_ )*` (likewise for `0o` / `0b`). The literal length is bounded only by the input document size. There is no `maxNumberLength` / `maxLiteralLength` option, no `chevrotain`-level cutoff, and no validation at the interpreter callsite.

By contrast, the `DecimalInteger` token interpreter at [`src/load/tokens/DecimalInteger.ts#L12-L19`](https://github.com/sunnyadn/js-toml/blob/2470ebf2e9009096aa4cbd1a15e574c54cc36b1a/src/load/tokens/DecimalInteger.ts#L12-L19) uses the V8 native `BigInt(intString)` constructor, which is `O(n)` and runs in single-digit milliseconds for inputs that take 40 seconds via the hand-written radix loop.

## Impact

A single attacker-supplied TOML document containing one ~500 kB radix-prefixed integer literal pins one CPU core for ~40 seconds on a modern laptop. Doubling the literal length quadruples the work. With `8 MB` of input the parse would block the event loop for many minutes of CPU. In a typical Node.js single-thread process this blocks all concurrent request handling for the duration. The defect is exploitable on any code path that calls `load()` (the only documented entry point) on attacker-controlled or third-party TOML.

## Reachability

The vulnerable path is the default code path for `load()`. No options or configuration are required to trigger it. Any caller that exposes `load()` to attacker-controlled or third-party TOML input reaches it on the first hex / octal / binary literal whose value exceeds `Number.MAX_SAFE_INTEGER` (i.e. more than 13 hex digits, 18 octal digits, or 53 binary digits).

Realistic exposure surfaces:

- Web service that accepts a user-supplied TOML configuration (settings import, theme upload, deployment manifest).
- CI / CD or build tool that runs `js-toml` on TOML in third-party repositories or pull requests.
- IDE / language-server plugin that re-parses a TOML buffer on every keystroke.
- Multi-tenant SaaS that lets one tenant submit TOML processed by a shared worker.

## PoC (End-to-end reproduction)

### Environment

- Node.js `v22.x` (tested on `v22.0.0` and Node `v26.0.0`)
- macOS arm64 / Linux x86_64 (CPU exhaustion is hardware-independent; absolute timings will scale by CPU clock)

### Install

bash mkdir js-toml-cve && cd js-toml-cve npm init -y npm install js-toml@1.1.0 @iarna/toml


### `poc_full_e2e.mjs`

js import { load } from 'js-toml'; import iarna from '@iarna/toml';

function timeIt(label, fn) { const t0 = process.hrtime.bigint(); let result, err; try { result = fn(); } catch (e) { err = e; } const t1 = process.hrtime.bigint(); const ms = (Number(t1 - t0) / 1e6).toFixed(1); if (err) console.log(${label}: ERROR ${err.message} after ${ms}ms); else console.log(${label}: ${ms}ms${result ? ' ' + result : ''}); }

console.log('--- Sanity baseline (small inputs) ---'); timeIt('decimal int 1', () => { load('x = 1'); return ''; }); timeIt('hex 0x10', () => { load('x = 0x10'); return ''; }); timeIt('hex 0xffff', () => { load('x = 0xffff'); return ''; });

console.log('\n--- Amplification curve: js-toml.load() with 0x ---'); for (const n of [10_000, 20_000, 50_000, 100_000, 200_000, 500_000]) { const hexDigits = 'f'.repeat(n); const tomlText = x = 0x${hexDigits}; timeIt(hex ${n.toLocaleString()} digits (${tomlText.length} bytes input), () => { const r = load(tomlText); return bits=${r.x.toString(2).length}; }); }

console.log('\n--- Negative control: same input via @iarna/toml ---'); for (const n of [10_000, 50_000, 100_000, 200_000]) { const hexDigits = 'f'.repeat(n); const tomlText = x = 0x${hexDigits}; timeIt(@iarna/toml hex ${n.toLocaleString()} digits, () => { const r = iarna.parse(tomlText); return type=${typeof r.x}; }); }

console.log('\n--- Octal / binary share the same code path ---'); for (const n of [50_000, 100_000]) { const octDigits = '7'.repeat(n);

Affected package ranges reported by GitHub: js-toml: <= 1.1.1

Scores and how they were measured

CVSS base severity

7.5

Version 3.1As of

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Measurement source (opens a new tab)

How bad it is if exploited. Not a prediction of exploitation or proof you are exposed.

EPSS probability

Not available

A model's estimate of exploitation in the next 30 days, not certainty or your own risk.

Related technology

Sources

  1. Primary source

    GitHub-reviewed advisory GHSA-wp3c-266w-4qfq (opens a new tab)

    The public advisory supplies the description, affected package/version ranges, and any listed CVSS metric. GitHub review is not local review.

    Published Checked

  2. Primary source

    GitHub public advisory API page (opens a new tab)

    The API page supplied GHSA-wp3c-266w-4qfq, its actual identifiers, source dates, and structured metrics.

    Published Date not suppliedChecked

  3. Primary source

    NVD CVE-2026-49293 (opens a new tab)

    NVD record: description, CVSS (the CNA score is preferred), affected products, and publication date. Not evidence of exploitation.

    Published Checked

  4. Primary source

    Vendor advisory (via NVD references) (opens a new tab)

    The vendor advisory referenced by the CVE record, for affected versions and fixes.

    Published Date not suppliedChecked

  5. Primary source

    NVD CVE API 2.0 (opens a new tab)

    The NVD API page that supplied this CVE record.

    Published Date not suppliedChecked

  6. Primary source

    NVD CVE API 2.0 (opens a new tab)

    The NVD API page that supplied this CVE record.

    Published Date not suppliedChecked

Cite this record

For factual claims, cite the primary sources above; cite KEVWire for its compilation, dates, and classifications.

APA

KEVWire. (2026, November 4). js-toml vulnerable to CPU exhaustion via O(n^2) BigInt construction on radix-prefixed integer literals (CVE-2026-49293). https://kevwire.com/record/CVE-2026-49293

MLA

"js-toml vulnerable to CPU exhaustion via O(n^2) BigInt construction on radix-prefixed integer literals (CVE-2026-49293)." KEVWire, 4 Nov. 2026, kevwire.com/record/CVE-2026-49293.

Chicago

KEVWire. "js-toml vulnerable to CPU exhaustion via O(n^2) BigInt construction on radix-prefixed integer literals (CVE-2026-49293)." Last modified November 4, 2026. https://kevwire.com/record/CVE-2026-49293.

Evidence summary (plain text)

js-toml vulnerable to CPU exhaustion via O(n^2) BigInt construction on radix-prefixed integer literals (Jun 26, 2026).
js-toml versions up to and including 1.1.0 parse hexadecimal / octal / binary integer literals via a hand-written parseBigInt loop that multiplies a BigInt accumulator by the radix once per input digit. Each iteration performs a BigInt * BigInt operation on an accumulator that grows linearly with the number of digits already consumed, so the whole loop is O(n²) in the literal length. The lexer regex places no upper bound on the literal length, so a single TOML document containing one ~500 kB hex literal pins one CPU core for ~40 seconds on a modern laptop (Apple M-series, Node v22).
CVSS 7.5 (version 3.1; evidence as of Nov 4, 2026; https://nvd.nist.gov/vuln/detail/CVE-2026-49293).
Sources:
GitHub-reviewed advisory GHSA-wp3c-266w-4qfq: https://github.com/advisories/GHSA-wp3c-266w-4qfq
GitHub public advisory API page: https://api.github.com/advisories?type=reviewed&per_page=100&sort=updated&direction=desc
NVD CVE-2026-49293: https://nvd.nist.gov/vuln/detail/CVE-2026-49293
Vendor advisory (via NVD references): https://github.com/sunnyadn/js-toml/security/advisories/GHSA-wp3c-266w-4qfq
NVD CVE API 2.0: https://services.nvd.nist.gov/rest/json/cves/2.0?lastModStartDate=2026-11-04T03:21:01.644Z&lastModEndDate=2026-11-04T04:55:55.399Z&resultsPerPage=500&startIndex=0
NVD CVE API 2.0: https://services.nvd.nist.gov/rest/json/cves/2.0?lastModStartDate=2026-11-04T02:50:58.496Z&lastModEndDate=2026-11-04T04:20:57.738Z&resultsPerPage=500&startIndex=0
Record ID: CVE-2026-49293.
Record origin: Ingested record.
AI evidence: Not assessed.
Known exploitation: Not assessed.
Zero-day status: Not assessed. KEV membership alone does not establish zero-day status.
About this data

This record was ingested from a data source. Retrieved: Nov 4, 2026, 04:55 UTC. Ingestion is not an independent editorial investigation.

A CISA KEV listing documents known exploitation, not necessarily a zero-day; absence from the catalog does not prove a vulnerability has never been exploited.

Technology tags indicate possible relevance, not verified exposure. Confirm the affected product, version, and configuration against your own inventory; KEVWire does not scan your systems.

A personal reading checklist on this device, not verified remediation.

Record JSON

Your account

Email alerts

Email alerts are coming as part of KEVWire Premium: join the waitlist. To follow your stack today, use its RSS feed, which honors your filters, or connect an AI agent through the API.

Suggest an improvement

Ideas, missing sources, corrections, and bugs are all welcome. No account needed. Suggestions are reviewed by a person before anything changes.

Record details

Record detail