Skip to content
Threat Feed
high advisory

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., &#38;#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

  1. Attacker crafts a malicious SpreadsheetML XML file containing double-encoded entities (e.g., &#38;#60; for <).
  2. The Reader\Xml component passes the raw file content to XmlScanner::scan().
  3. XmlScanner::scan() performs a pattern match on the raw input; the malicious <!DOCTYPE remains hidden.
  4. The unentity() callback executes html_entity_decode(), converting the double-encoded entity to a single-encoded entity.
  5. The partially decoded XML is stored in Xml::$fileContents.
  6. The Xml reader initiates a second scan pass, which also fails to match the pattern because the entity is only partially decoded.
  7. The unentity() callback executes again, converting the single-encoded entity into the raw < character.
  8. 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_NOENT is enabled.

Recommendation

  • Upgrade PhpSpreadsheet to a patched version once available from PHPOffice.
  • Audit applications that use PhpOffice\PhpSpreadsheet\Reader\Xml to identify intake points for user-supplied SpreadsheetML files.
  • Implement file-type validation and strictly forbid LIBXML_NOENT if using older PHP environments.

Immediate actions

Identify applications in the environment leveraging the PhpSpreadsheet library to process untrusted XML uploads.

SOC 48h

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 &#38;#60; or &#38;#x3C;.

T1190 high medium confidence hunt now

Data: Web server access logs (POST body/request content)

Mitigations

Upgrade PhpSpreadsheet to 8.0 or later

immediate IT Operations

CVE-2026-108357