{"id":"CVE-2026-107378","aliases":["GHSA-c3jg-qh8m-j3h2","PYSEC-2026-4204"],"url":"https://o3.security/vulnerability/CVE-2026-107378","summary":"CairoSVG: Quadratic-time DoS parsing a crafted SVG <path>","details":"## Summary\n\nRendering 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`:\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'<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\"><path d=\"{d}\"/></svg>'\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.","published":"2026-10-08T17:59:09.505Z","modified":"2026-10-21T02:54:36.729846696Z","cvss":null,"epss":null,"cisaKev":null,"exploitsKnown":null,"affectedPackages":[{"ecosystem":"PyPI","name":"cairosvg","fixedVersion":"2.9.1"}],"fix":{"url":"https://github.com/Kozea/CairoSVG/commit/9d63f049f9988d0ddda3eb94564ac3a50a286523","label":"Kozea/CairoSVG@9d63f04"},"references":[{"type":"WEB","url":"https://github.com/Kozea/CairoSVG/releases/tag/2.9.1"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/107xxx/CVE-2026-107378.json"},{"type":"ADVISORY","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":"FIX","url":"https://github.com/Kozea/CairoSVG/commit/9d63f049f9988d0ddda3eb94564ac3a50a286523"},{"type":"FIX","url":"https://github.com/Kozea/CairoSVG/commit/a4d585eb374724b79676e9cceaa9e9a1a4358565"},{"type":"PACKAGE","url":"https://github.com/Kozea/CairoSVG"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-10-21T02:54:36.729846696Z"}}