CVE-2026-18503 Overview
CVE-2026-18503 is a regular-expression denial-of-service (ReDoS) vulnerability in CPython's csv.Sniffer.sniff() function. Attacker-controlled CSV samples can trigger super-linear regular-expression work during dialect sniffing. Applications that pass unbounded, untrusted CSV input to the sniffer consume disproportionate CPU time on crafted samples. The root cause is a lazy .*? quantifier inside the quoted-field detection patterns, which the regex engine re-evaluates from every candidate start position, producing quadratic scaling with input size. The weakness is classified as [CWE-1176] Inefficient CPU Computation.
Critical Impact
A local, low-privileged actor supplying a crafted CSV sample to any application calling csv.Sniffer.sniff() can cause sustained CPU exhaustion and degrade service availability.
Affected Products
- CPython 3.12 branch (patched in commit 063d4555)
- CPython 3.14 branch (patched in commit 89f29c76)
- CPython 3.15 development branch (patched in commit 476fb09c)
Discovery Timeline
- 2026-08-10 - CVE-2026-18503 published to NVD
- 2026-08-13 - Last updated in NVD database
Technical Details for CVE-2026-18503
Vulnerability Analysis
The defect lives in Lib/csv.py inside the Sniffer._guess_quote_and_delimiter() method. The function iterates over four regular expressions that each contain a lazy .*? between two backreferenced quote characters. On non-matching or partially matching inputs, the regex engine restarts the lazy scan at every position in the sample. Combined with re.DOTALL | re.MULTILINE, the engine performs O(n²) work relative to sample length.
An attacker supplies a CSV sample containing many quote characters without a valid closing structure. Each candidate start position drives the lazy body to scan toward the end of the sample before failing, and the pattern is re-tried against three additional variants. The result is measurable CPU exhaustion on samples that would otherwise parse in microseconds.
Root Cause
The lazy quantifier .*? bracketed by (?P<quote>["\']) and (?P=quote) is the algorithmic complexity primitive. The regex has no anchor or possessive quantifier bounding the body length, so failed match attempts do not short-circuit. This falls under [CWE-1176] because the inefficiency is functional but computationally excessive.
Attack Vector
Exploitation requires local access and low privileges. The attacker must reach an application entry point that forwards untrusted bytes to csv.Sniffer.sniff() — for example, upload handlers that auto-detect CSV dialect, data-ingest pipelines, or notebook workflows. User interaction is passive: the target application performs the sniff on the attacker-supplied file.
# Vulnerable pattern (pre-patch) in Lib/csv.py
matches = []
for restr in (r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?P=delim)', # ,".*?",
r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?P<delim>[^\w\n"\'])(?P<space> ?)', # ".*?",
r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?:$|\n)', # ,".*?"
r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?:$|\n)'): # ".*?" (no delim, no space)
regexp = re.compile(restr, re.DOTALL | re.MULTILINE)
matches = regexp.findall(data)
if matches:
break
# Source: https://github.com/python/cpython/commit/063d4555c94ef412c731527dbf30193327f2ee82
Detection Methods for CVE-2026-18503
Indicators of Compromise
- Sustained single-core CPU saturation by a Python worker process during CSV ingestion.
- Application request latency spikes correlated with uploads of small (<1 MB) CSV samples containing many unbalanced quote characters.
- Stack traces or profiler samples showing time-in-function concentrated in re module calls originating from csv.py.
Detection Strategies
- Inventory Python applications that call csv.Sniffer().sniff() on user-controlled input and flag them for patching.
- Add wall-clock timeouts or CPU-time budgets around dialect sniffing to surface anomalous processing.
- Log the size and quote-character density of samples passed to csv.Sniffer so outliers can be reviewed retrospectively.
Monitoring Recommendations
- Alert on Python worker processes exceeding baseline CPU time per request in file-processing services.
- Track exception and timeout counts for CSV ingest endpoints; sudden increases correlate with attempted exploitation.
- Correlate upload metadata (source IP, user, file hash) with backend CPU utilization to identify abusive submitters.
How to Mitigate CVE-2026-18503
Immediate Actions Required
- Upgrade to CPython builds containing the fix on the 3.12, 3.14, and 3.15 branches referenced in the Python Security Announcement.
- Bound the sample size passed to csv.Sniffer.sniff() — the documented pattern is to pass only the first few kilobytes.
- Wrap sniffing calls in a timeout or subprocess with a CPU budget when input is untrusted.
Patch Information
The fix replaces the lazy .*? body with a possessive alternation (?:(?P=quote){2}|(?!(?P=quote)).)*+ that consumes doubled quotes or non-quote characters without backtracking. Patches are tracked in gh-98820 and merged via pull request 153694, with branch backports in commits 063d4555, 89f29c76, and 476fb09c.
Workarounds
- Truncate untrusted CSV input to a small fixed prefix (for example, 8–16 KB) before invoking the sniffer.
- Skip csv.Sniffer entirely and require callers to declare the dialect, delimiter, and quote character.
- Run CSV ingestion in an isolated worker with strict CPU-time limits (resource.setrlimit(RLIMIT_CPU, ...)).
# Enforce a per-process CPU budget around CSV sniffing workers
systemd-run --scope -p CPUQuota=25% -p RuntimeMaxSec=5 \
python3 -c 'import csv,sys; csv.Sniffer().sniff(sys.stdin.read(8192))'
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

