PhpSpreadsheet: XmlScanner TOCTOU bypass leading to XXE and DoS (CVE-2026-108357)
A TOCTOU vulnerability in PhpSpreadsheet allows attackers to bypass XML security filters via double-encoded numeric entities, enabling XXE and Denial of Service attacks.
CVE search metadata
CVE search record: CVE-2026-108357. EPSS: 0.46%. KEV: no. Product: PhpSpreadsheet (>= 4.0.0, <= 5.9.0), PhpSpreadsheet (>= 3.3.0, <= 3.10.7). Brief: PhpSpreadsheet: XmlScanner TOCTOU bypass leading to XXE and DoS (CVE-2026-108357). Brief link: https://feed.craftedsignal.io/briefs/2026-11-phpspreadsheet-xxe-dos/
Triage facts
Revision 1- Applicability
- PhpSpreadsheet (>= 4.0.0, <= 5.9.0), PhpSpreadsheet (>= 3.3.0, <= 3.10.7)
- Evidence
- Unknown
- Severity
- High
- Action
- Elevated
- Sources
- 2 public sources
- Freshness
- Revision 1Nov 1, 20:48 UTC
- Vulnerabilities
- 1 CVE
- Source quality
- A1Likely
PhpSpreadsheet contains a Time-of-Check Time-of-Use (TOCTOU) vulnerability (CVE-2026-108357) in its XmlScanner::scan() method. The scanner performs two sequential passes over input data, but the unentity() callback - which decodes HTML entities - executes after the security pattern check in both passes. By using double-encoded numeric entities (e.g., &#60;), an attacker can hide <!DOCTYPE declarations from the security filter. The first pass decodes the entity into a single-encoded format, and the second pass completes the decoding, resulting in a malicious <!DOCTYPE payload that the XML parser then executes.
Attack Chain
- Attacker crafts a malicious SpreadsheetML XML file containing double-encoded entities (e.g.,
&#60;for<). - The
Reader\Xmlcomponent passes the raw file content toXmlScanner::scan(). XmlScanner::scan()performs a pattern match on the raw input; the malicious<!DOCTYPEremains hidden.- The
unentity()callback executeshtml_entity_decode(), converting the double-encoded entity to a single-encoded entity. - The partially decoded XML is stored in
Xml::$fileContents. - The
Xmlreader initiates a second scan pass, which also fails to match the pattern because the entity is only partially decoded. - The
unentity()callback executes again, converting the single-encoded entity into the raw<character. simplexml_load_string()processes the final, now-malicious XML, triggering entity expansion (DoS) or XXE.
Impact
- Denial of Service: Exploitation causes quadratic memory blowup via entity expansion.
- Information Disclosure: XXE/SSRF allows unauthorized reading of local files or internal network resources, specifically on PHP versions < 8.0 or when
LIBXML_NOENTis enabled.
Recommendation
- Upgrade PhpSpreadsheet to a patched version once available from PHPOffice.
- Audit applications that use
PhpOffice\PhpSpreadsheet\Reader\Xmlto identify intake points for user-supplied SpreadsheetML files. - Implement file-type validation and strictly forbid
LIBXML_NOENTif using older PHP environments.
Immediate actions
Identify applications in the environment leveraging the PhpSpreadsheet library to process untrusted XML uploads.
Threat Hunt
Search web server logs for HTTP POST requests to endpoints that handle file uploads, specifically looking for XML or Spreadsheet file extensions alongside requests that contain unusual numeric entity patterns like &#60; or &#x3C;.
Data: Web server access logs (POST body/request content)
Mitigations
Upgrade PhpSpreadsheet to 8.0 or later
CVE-2026-108357