{"id":"GHSA-c3jg-qh8m-j3h2","summary":"CairoSVG: Quadratic-time DoS parsing a crafted SVG \u003cpath\u003e","details":"## Summary\n\nRendering an untrusted SVG whose `\u003cpath d=\"...\"\u003e` contains many segments is O(n²) CPU. A single `\u003cpath\u003e` under 1 MiB burns tens of seconds. Two independent O(n²) sites in `cairosvg/path.py`:\n\n1. **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.\n2. **draw_markers** — 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²).\n\nBoth are hit on a normal render path (`svg2png`/`svg2pdf`), attacker controls only the SVG document.\n\n## PoC (installed cairosvg 2.9.0)\n\n```python\nimport cairosvg\nd = \"M0 0 \" + \"L1 1 \" * 100000\nsvg = f'\u003csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\"\u003e\u003cpath d=\"{d}\"/\u003e\u003c/svg\u003e'\ncairosvg.svg2png(bytestring=svg.encode())   # ~4.4 s for a 488 KB doc\n```\n\n| path segments | SVG size | time |\n|---|---|---|\n| 50,000 | 244 KB | 1.14 s |\n| 100,000 | 488 KB | 4.36 s |\n| 200,000 | ~960 KB | ~18 s |\n\nDoubling segments ≈ 4× time ⇒ quadratic. Sub-MiB input ⇒ ~18 s CPU; any service rendering user-supplied SVG (thumbnails, avatars, PDF export) is a DoS target.\n\n## Reachability\n\nPublic API `svg2png` / `svg2pdf` / `svg2ps` on an untrusted SVG string.\n\n## Suggested fix\n\nTokenize 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.","aliases":["CVE-2026-107378"],"modified":"2026-10-08T20:00:05.951212528Z","published":"2026-10-08T19:41:22Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2026-10-08T19:41:22Z","nvd_published_at":"2026-10-08T18:17:23Z","cwe_ids":["CWE-407"],"severity":"HIGH"},"references":[{"type":"WEB","url":"https://github.com/Kozea/CairoSVG/security/advisories/GHSA-c3jg-qh8m-j3h2"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-107378"},{"type":"WEB","url":"https://github.com/Kozea/CairoSVG/commit/9d63f049f9988d0ddda3eb94564ac3a50a286523"},{"type":"WEB","url":"https://github.com/Kozea/CairoSVG/commit/a4d585eb374724b79676e9cceaa9e9a1a4358565"},{"type":"PACKAGE","url":"https://github.com/Kozea/CairoSVG"},{"type":"WEB","url":"https://github.com/Kozea/CairoSVG/releases/tag/2.9.1"}],"affected":[{"package":{"name":"cairosvg","ecosystem":"PyPI","purl":"pkg:pypi/cairosvg"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.9.1"}]}],"versions":["0.1","0.1.1","0.1.2","0.2","0.3","0.3.1","0.4","0.4.1","0.4.2","0.4.3","0.4.4","0.5","1.0","1.0.1","1.0.10","1.0.11","1.0.12","1.0.13","1.0.14","1.0.15","1.0.16","1.0.17","1.0.18","1.0.19","1.0.2","1.0.20","1.0.21","1.0.22","1.0.3","1.0.4","1.0.5","1.0.6","1.0.7","1.0.8","1.0.9","2.0.0","2.0.0rc1","2.0.0rc2","2.0.0rc3","2.0.0rc4","2.0.0rc5","2.0.0rc6","2.0.1","2.0.2","2.0.3","2.1.0","2.1.1","2.1.2","2.1.3","2.2.0","2.2.1","2.3.0","2.3.1","2.4.0","2.4.1","2.4.2","2.5.0","2.5.1","2.5.2","2.6.0","2.7.0","2.7.1","2.8.0","2.8.1","2.8.2","2.9.0"],"database_specific":{"last_known_affected_version_range":"\u003c= 2.9.0","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-c3jg-qh8m-j3h2/GHSA-c3jg-qh8m-j3h2.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N"}]}