CVE-2026-107378: CairoSVG: Quadratic-time DoS parsing a crafted SVG <path>
Summary
Rendering an untrusted SVG whose <path d="..."> contains many segments is O(n²) CPU. A single <path> under 1 MiB burns tens of seconds. Two independent O(n²) sites in cairosvg/path.py:
1. Tokenizer — the path-data parser consumes the d string with a while string: loop that repeatedly slices/re-scans the remaining string (each step is O(len remaining)), giving O(n²) over the whole attribute. 2. drawmarkers — marker handling drains node.vertices with while node.vertices: ... node.vertices.pop(0); list.pop(0) is O(n), so draining n vertices is O(n²).
Both are hit on a normal render path (svg2png/svg2pdf), attacker controls only the SVG document.
PoC (installed cairosvg 2.9.0)
python import cairosvg d = "M0 0 " + "L1 1 " 100000 svg = f'<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10"><path d="{d}"/></svg>' cairosvg.svg2png(bytestring=svg.encode()) # ~4.4 s for a 488 KB doc
| path segments | SVG size | time | |---|---|---| | 50,000 | 244 KB | 1.14 s | | 100,000 | 488 KB | 4.36 s | | 200,000 | ~960 KB | ~18 s |
Doubling segments ≈ 4× time ⇒ quadratic. Sub-MiB input ⇒ ~18 s CPU; any service rendering user-supplied SVG (thumbnails, avatars, PDF export) is a DoS target.
Reachability
Public API svg2png / svg2pdf / svg2ps on an untrusted SVG string.
Suggested fix
Tokenize with a single forward scan / index (or re.finditer) instead of re-slicing the remainder; drain vertices with an index or collections.deque.popleft instead of list.pop(0). Optionally cap path-segment count.
Other sources
CairoSVG is an SVG converter based on Cairo, a 2D graphics library. Prior to 2.9.1, rendering an attacker-controlled SVG with a path containing many segments can cause quadratic CPU consumption in cairosvg/path.py. The path tokenizer repeatedly slices and rescans the remaining path data, while drawmarkers drains node.vertices with node.vertices.pop(0), causing repeated linear-time work. The svg2png, svg2pdf, and svg2ps APIs reach these operations during ordinary rendering, allowing a sub-megabyte SVG to consume substantial CPU and deny service to a rendering application. This issue is fixed in version 2.9.1.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/cairosvgto a version that resolves this vulnerability.Fixed in 2.9.1 - Upgrade
Upgrade
cairosvgto a version that resolves this vulnerability.Fixed in 2.9.1 - Compensating control
Optionally cap the number of path segments accepted when rendering untrusted SVG documents.
Event History
Frequently Asked Questions
What deployments are realistically exposed?
Services that render user-supplied or otherwise untrusted SVG documents with CairoSVG are exposed, including use through svg2png or svg2pdf. The vulnerable processing occurs on the normal rendering path.
What does an attacker need to trigger the issue?
An attacker only needs to supply an SVG containing a path with a d attribute containing many segments. The supplied CVSS vector indicates network reachability, low attack complexity, no privileges, and no user interaction.
How can I recognize exploitation or validate exposure?
Look for SVG inputs with a single path containing unusually large numbers of path segments and rendering jobs with disproportionate CPU time. The provided measurements show approximately quadratic growth: a 488 KB SVG with 100,000 segments took about 4.36 seconds, while roughly 960 KB with 200,000 segments took about 18 seconds.