PT-2026-115374
تاريخ النشر
2026-10-05
·
تاريخ التحديث
2026-10-05
الوصف من
CVSS 3.1
5.3
متوسطةالمقاييسAV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
Summary
parse() has a quadratic-time path in parseKey, reachable on default options with ordinary valid input. For every key line and table-header line, parseKey (dist/struct.js, lines 58 and 86) finds the dotted-key separator with ctx.s.indexOf('.', ctx.p), where ctx.s is the whole document. When a key has no . ahead of it, that search runs all the way to the end of the input, and the result is then clamped back to the line terminator endPtr - so everything scanned past the current line is wasted. parseKey runs once per line, so a document of N dot-free keys costs O(n^2).The most ordinary TOML shape triggers it: a flat list of
key = value lines, or a repeated [[a]] table. No dotted keys, no special options, valid input throughout.Proof of concept
js
import { parse } from 'smol-toml'
let doc = ''
for (let i = 0; i < 256000; i++) doc += 'k' + i + ' = 1
'
console.time('parse')
parse(doc) // ~2.8 MB of valid TOML, default options
console.timeEnd('parse')Doubling the line count roughly quadruples the time:
| lines | size | parse() |
|---|---|---|
| 32k | 0.3 MB | 0.3 s |
| 64k | 0.7 MB | 1.0 s |
| 128k | 1.4 MB | 3.5 s |
| 256k | 2.8 MB | 14 s |
Impact
Any service that runs
parse() on attacker-supplied TOML can be stalled. The work is synchronous, so it blocks the whole event loop, and the quadratic is unbounded: a ~7 MB body pins a core for about a minute, larger bodies for several.Patches
Version 1.9.0 uses a different implementation for parsing keys which is strictly linear.
Workarounds
Limit the maximum document size accepted when parsing arbitrary documents.
وجدت خطأً في الوصف؟ لديك ما تضيفه؟ لا تتردد في مراسلتنا 👾