Severity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Remote, unauthenticated, no-interaction file upload triggers unbounded decompression with availability-only impact, so AV:N/AC:L/PR:N/UI:N and C:N/I:N/A:H.
Primary rating from Vendor (https://github.com/PHPOffice/PhpSpreadsheet).
CVSS VectorVendor: https://github.com/PHPOffice/PhpSpreadsheet
Lifecycle Timeline
3DescriptionCVE.org
Summary
PhpSpreadsheet's Gnumeric reader reads attacker-supplied .gnumeric files into memory and, when the file starts with gzip magic bytes, calls gzdecode() on the full compressed contents without enforcing a decompressed-size limit. A very small compressed .gnumeric file can expand to data larger than the PHP memory limit and crash the process during Gnumeric::canRead() before the file is rejected or fully parsed.
This is reachable through normal file-type detection and Gnumeric loading paths, so applications that accept attacker-controlled spreadsheet uploads can suffer denial of service.
Vulnerability details
Gnumeric::canRead() invokes gzfileGetContents() before deciding whether the file is a valid Gnumeric spreadsheet:
src/PhpSpreadsheet/Reader/Gnumeric.php:80-90calls$this->gzfileGetContents($filename)fromcanRead().src/PhpSpreadsheet/Reader/Gnumeric.php:105-115callscanRead()and then reads the expanded contents again for worksheet-name listing.src/PhpSpreadsheet/Reader/Gnumeric.php:253-265callscanRead()and then reads the expanded contents again for full loading.
The vulnerable expansion is in gzfileGetContents():
src/PhpSpreadsheet/Reader/Gnumeric.php:187-190reads the entire input file into$contentswithfile_get_contents().src/PhpSpreadsheet/Reader/Gnumeric.php:192-197detects gzip magic bytes and callsgzdecode($contents)without a decompressed-size cap.src/PhpSpreadsheet/Reader/Gnumeric.php:204-205scans the expanded data only after decompression has already completed.
Because decompression occurs before XML scanning or structural validation, a tiny gzip payload can force large memory allocation even if the resulting XML is meaningless or invalid.
Impact
A small .gnumeric upload can crash a PHP worker during spreadsheet type detection or import. This can cause denial of service in web applications, queue workers, preview services, document converters, or any service that runs PhpSpreadsheet against untrusted spreadsheet files.
In the local reproduction below, a 97,811-byte file expands to about 96 MiB and crashes Gnumeric::canRead() under memory_limit=64M at Reader/Gnumeric.php:195.
Safe local proof of concept
This proof of concept uses only Docker with --network none; it creates the compressed payload inside the container and does not contact external infrastructure.
docker run --rm --network none -i \
-v /home/sondt23/Github/CVE/ares/github-repo/PhpSpreadsheet:/app \
-w /app ghcr.io/typo3/core-testing-php82:1.15 sh <<'SH'
set -eu
php -r '
$prefix = "<?xml version=\"1.0\"?><gnm:Workbook xmlns:gnm=\"http://www.gnumeric.org/v10.dtd\">";
$suffix = "</gnm:Workbook>";
$payload = $prefix . str_repeat("A", 96 * 1024 * 1024) . $suffix;
$gz = gzencode($payload, 9);
file_put_contents("/tmp/bomb.gnumeric", $gz);
printf("compressed_size=%d expanded_size=%d\n", filesize("/tmp/bomb.gnumeric"), strlen($payload));
'
php -d memory_limit=64M -d display_errors=1 -r '
require "/app/vendor/autoload.php";
$r = new PhpOffice\PhpSpreadsheet\Reader\Gnumeric();
var_dump($r->canRead("/tmp/bomb.gnumeric"));
' 2>&1 || true
SHObserved output:
compressed_size=97811 expanded_size=100663390
PHP Fatal error: Allowed memory size of 67108864 bytes exhausted (tried to allocate 50291378 bytes) in /app/src/PhpSpreadsheet/Reader/Gnumeric.php on line 195
PHP Stack trace:
PHP 1. {main}() Command line code:0
PHP 2. PhpOffice\PhpSpreadsheet\Reader\Gnumeric->canRead($filename = '/tmp/bomb.gnumeric') Command line code:4
PHP 3. PhpOffice\PhpSpreadsheet\Reader\Gnumeric->gzfileGetContents($filename = '/tmp/bomb.gnumeric') /app/src/PhpSpreadsheet/Reader/Gnumeric.php:84
PHP 4. gzdecode(...) /app/src/PhpSpreadsheet/Reader/Gnumeric.php:195Suggested remediation
- Do not decompress gzip data with unbounded
gzdecode()for untrusted.gnumericfiles. - Stream decompression with a strict maximum output-size limit before allocating the full expanded XML.
- Enforce a configurable maximum compressed size and maximum decompressed size for Gnumeric files.
- Ensure
canRead(),listWorksheetNames(),listWorksheetInfo(), andload()share bounded decompression logic and avoid decompressing the same file repeatedly. - Fail closed with a recoverable
Reader\Exceptionwhen limits are exceeded, rather than allowing a PHP fatal memory error.
Articles & Coverage 2
AnalysisAI
Denial-of-service in PhpSpreadsheet's Gnumeric reader lets remote attackers crash PHP worker processes by uploading a tiny gzip-compressed .gnumeric file that decompresses to hundreds of megabytes. The reader's Gnumeric::canRead() calls gzdecode() with no decompressed-size cap during routine file-type detection, so a ~98 KB payload expanding to ~96 MiB exhausts a 64M memory limit and triggers a fatal error before validation. No public exploit is identified at time of analysis, but a working proof-of-concept is described in the advisory and the CVSS score is 7.5 (High) with A:H impact.
Technical ContextAI
The affected component is the PHP library PhpSpreadsheet (Composer package phpoffice/phpspreadsheet), specifically the Gnumeric reader that ingests .gnumeric spreadsheet files - an XML format that is commonly gzip-compressed. In src/PhpSpreadsheet/Reader/Gnumeric.php, gzfileGetContents() reads the whole file with file_get_contents(), detects gzip magic bytes, and calls gzdecode($contents) with no output-length argument, so the entire payload is inflated into memory before any XML scanning or structural validation occurs. This is a textbook CWE-400 (Uncontrolled Resource Consumption), realized here as a classic decompression bomb / gzip amplification: the attacker controls the compression ratio, so a small input forces an unbounded allocation. The same unbounded path is reachable from canRead(), listWorksheetNames(), listWorksheetInfo(), and load(), and some call sites decompress the file more than once, compounding the cost.
RemediationAI
Upgrade to a patched release for your branch: Vendor-released patch versions are 5.8.1, 3.10.7, 2.4.7, 2.1.18 (and 1.30.6), delivered via commit 85f2556b0bf5269061bf45932ecda8a128d81750. The fix computes a maxLength from the PHP memory_limit (one quarter of it) and passes it to gzdecode($contents, $this->maxLength), and exposes a setMaxLength() method so applications can tighten the cap; run composer update phpoffice/phpspreadsheet to the fixed version for your major line. If you cannot patch immediately, apply compensating controls: reject or do not auto-process files with a .gnumeric extension or gzip magic bytes on untrusted upload paths (trade-off: legitimate Gnumeric imports break); enforce a strict maximum compressed upload size and run spreadsheet parsing in an isolated worker with a conservative memory_limit and process/time limits so a crash is contained and recoverable rather than taking down the main application; and avoid calling canRead()/auto-detection on untrusted files where the format is not expected. See the advisory at https://github.com/PHPOffice/PhpSpreadsheet/security/advisories/GHSA-2mrg-gjxq-2gvr and the patch commit at https://github.com/PHPOffice/PhpSpreadsheet/commit/85f2556b0bf5269061bf45932ecda8a128d81750.
In PHP versions 7.1.x below 7.1.33, 7.2.x below 7.2.24 and 7.3.x below 7.3.11 in certain configurations of FPM setup it
sapi/cgi/cgi_main.c in PHP before 5.3.12 and 5.4.x before 5.4.2, when configured as a CGI script (aka php-cgi), does not
(1) boardData102.php, (2) boardData103.php, (3) boardDataJP.php, (4) boardDataNA.php, and (5) boardDataWW.php in Netgear
The '/common/download_agent_installer.php' script in the Quest KACE System Management Appliance 8.0.318 is accessible by
ProjectSend versions prior to r1720 are affected by an improper authentication vulnerability. Rated critical severity (C
Roundcube Webmail contains a critical PHP object deserialization vulnerability (CVE-2025-49113, CVSS 9.9) that allows au
Util/PHP/eval-stdin.php in PHPUnit before 4.8.28 and 5.x before 5.6.3 allows remote attackers to execute arbitrary PHP c
Palo Alto Networks PAN-OS management web interface contains an authentication bypass allowing unauthenticated attackers
Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re
Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re
The get_referers function in /opt/ws/bin/sblistpack in Sophos Web Appliance before 3.7.9.1 and 3.8 before 3.8.1.1 allows
The Backup Migration plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 1
Same weakness CWE-400 – Uncontrolled Resource Consumption
View allSame technique Denial Of Service
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-49952
GHSA-2mrg-gjxq-2gvr