CVE-2026-84374: Maatwebsite/excel Laravel Excel Writes Exports Outside Vulnerability

HIGH
Advisory Identifier: GHSA-c7r6-vx3h-w5g2
CVSS 7.5
CWE-73 CWE-22
Published
Advisory Summary

CVE-2026-84374 is a HIGH (CVSS 7.5) laravel excel writes exports outside vulnerability (CWE-73: External Control of File Name or Path) affecting Maatwebsite/excel libraries in the Packagist ecosystem. The issue involves laravel excel writes exports outside the configured filesystem disk when given a caller-controlled path. Remediation is available by upgrading affected packages to version 3.1.70.

CVE-2026-84374 at a Glance

CVE Identifier CVE-2026-84374
GHSA Identifier GHSA-c7r6-vx3h-w5g2
Severity HIGH
CVSS v3.1 Base Score 7.5
CWE Classification CWE-73: External Control of File Name or Path
Affected Product Maatwebsite/excel
Package Ecosystem Packagist
Published Date
Last Updated

Security Impact

CVSS: 7.5

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H).

Attack Vector Network (AV:N)
Attack Complexity High (AC:H)
Privileges Required Low (PR:L)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity High (I:H)
Availability High (A:H)

How to Fix CVE-2026-84374

To remediate this vulnerability, upgrade all affected Maatwebsite/excel dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

maatwebsite/excel fixed: 3.1.70
Upgrade maatwebsite/excel to 3.1.70
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for maatwebsite/excel

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-84374, inspect your project dependencies for Maatwebsite/excel:

inspect dependencies for maatwebsite/excel

Analyze the terminal output to locate any version of Maatwebsite/excel in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 3.1.70), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-73: External Control of File Name or Path, where the product allows user input to control or influence paths or file names that are used in filesystem operations. In Maatwebsite/excel, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Summary `Excel::store()` resolved the destination path against the process working directory rather than the configured filesystem disk. When that path resolved to an existing file, the export was written straight to it with `fopen()`, bypassing the disk entirely. An application that passes a user-controlled value as the export path could therefore be made to overwrite an arbitrary existing file that the PHP process can write to, with content the user controls. ### Details `Maatwebsite\Excel\Files\Disk::copy()` contained two paths: ```php if (realpath($destination)) { $tempStream = fopen($destination, 'rb+'); $success = stream_copy_to_stream($readStream, $tempStream) !== false; } else { $success = $this->put($destination, $readStream); } ``` `$destination` is the `$filePath` argument given to `Excel::store()`, `$export->store()` or `->storeExcel()`. `realpath()` resolves it against the **current working directory** — `public/` for a typical web request — not against the disk root. On a hit, the write went directly to the filesystem and never reached Flysystem, which would otherwise have rejected `../` traversal and confined absolute paths to the disk root. The disk argument was effectively ignored for those paths, including for remote disks such as S3. Two consequences follow: * the destination could be any existing file the PHP process can write, in or out of the disk root; * the stream was opened `'rb+'`, which does not truncate, so a shorter export left trailing bytes of the previous file behind. Because the file must already exist, the primitive is an **overwrite** rather than an arbitrary file creation. Overwriting a PHP file that is reachable by the web server (for example a front controller or a cached view) turns attacker-controlled row content into code execution, since CSV and HTML writers emit cell values verbatim. Passing an explicit writer type to `store()` bypasses the extension-based type detection that would otherwise reject a `.php` target. Exploitation requires the **application** to pass an unsanitized, user-controlled value as the export path. Applications that pass a fixed or server-derived path are not affected. ### Impact Arbitrary overwrite of existing files writable by the PHP process, with partially attacker-controlled content, leading to remote code execution where the overwritten file is executed by the web server. ### Patches Fixed in **3.1.70**. `Disk::copy()` now always writes through the configured filesystem disk, so Flysystem enforces the disk root for every export. Note the behaviour change: passing an absolute path to `store()` previously wrote to that path once the file existed. Paths now always resolve relative to the disk root. Applications that relied on that should configure a disk rooted at the target location. ### Workarounds For anyone unable to upgrade, validate the path before passing it to `store()` — reject absolute paths and any `..` segment, or derive the filename server-side and never build it from request input: ```php $name = basename($request->input('filename')); // strips any directory part Excel::store($export, 'exports/' . $name, 'local'); ``` ### Credit Reported responsibly by @seck19 via the contact address in `SECURITY.md`.

CVE-2026-84374 Affected Maatwebsite/excel Versions

1 component(s)
Fixed Versions:
3.1.70
Product / Package Ecosystem Affected Versions Fixed Version
maatwebsite/excel
Packagist
≥ 3.1.8
< 3.1.70
3.1.70

References

Frequently Asked Questions

What is CVE-2026-84374?
CVE-2026-84374 is a security vulnerability in Maatwebsite/excel involving Laravel Excel writes exports outside the configured filesystem disk when given a caller-controlled path under CWE-73: External Control of File Name or Path.
Which Maatwebsite/excel versions are affected?
Affected versions include releases prior to 3.1.70 across affected packages: maatwebsite/excel.
What version fixes CVE-2026-84374?
Upgrading to 3.1.70 (or the latest patched release for your respective branch) resolves the vulnerability.
Is maatwebsite/excel affected?
Yes, maatwebsite/excel is affected in releases prior to 3.1.70. Upgrade your dependency to 3.1.70 or later.
What is the CVSS score of CVE-2026-84374?
CVE-2026-84374 has a CVSS v3.1 base score of 7.5 (HIGH) with vector string CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H.
What CWE is associated with CVE-2026-84374?
CVE-2026-84374 is classified under CWE-73: External Control of File Name or Path (The product allows user input to control or influence paths or file names that are used in filesystem operations.).
How can I check Packagist dependencies for CVE-2026-84374?
Run the dependency tree command: 'inspect dependencies for maatwebsite/excel'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-c7r6-vx3h-w5g2",
  "modified" : "2026-09-08T20:40:47Z",
  "published" : "2026-09-08T20:40:47Z",
  "aliases" : [ "CVE-2026-84374" ],
  "summary" : "Laravel Excel writes exports outside the configured filesystem disk when given a caller-controlled path",
  "details" : "### Summary\n\n`Excel::store()` resolved the destination path against the process working\ndirectory rather than the configured filesystem disk. When that path resolved to\nan existing file, the export was written straight to it with `fopen()`,\nbypassing the disk entirely. An application that passes a user-controlled value\nas the export path could therefore be made to overwrite an arbitrary existing\nfile that the PHP process can write to, with content the user controls.\n\n### Details\n\n`Maatwebsite\\Excel\\Files\\Disk::copy()` contained two paths:\n\n```php\nif (realpath($destination)) {\n    $tempStream = fopen($destination, 'rb+');\n    $success    = stream_copy_to_stream($readStream, $tempStream) !== false;\n} else {\n    $success = $this->put($destination, $readStream);\n}\n```\n\n`$destination` is the `$filePath` argument given to `Excel::store()`,\n`$export->store()` or `->storeExcel()`. `realpath()` resolves it against the\n**current working directory** — `public/` for a typical web request — not\nagainst the disk root. On a hit, the write went directly to the filesystem and\nnever reached Flysystem, which would otherwise have rejected `../` traversal and\nconfined absolute paths to the disk root. The disk argument was effectively\nignored for those paths, including for remote disks such as S3.\n\nTwo consequences follow:\n\n* the destination could be any existing file the PHP process can write, in or\n  out of the disk root;\n* the stream was opened `'rb+'`, which does not truncate, so a shorter export\n  left trailing bytes of the previous file behind.\n\nBecause the file must already exist, the primitive is an **overwrite** rather\nthan an arbitrary file creation. Overwriting a PHP file that is reachable by the\nweb server (for example a front controller or a cached view) turns\nattacker-controlled row content into code execution, since CSV and HTML writers\nemit cell values verbatim. Passing an explicit writer type to `store()` bypasses\nthe extension-based type detection that would otherwise reject a `.php` target.\n\nExploitation requires the **application** to pass an unsanitized, user-controlled\nvalue as the export path. Applications that pass a fixed or server-derived path\nare not affected.\n\n### Impact\n\nArbitrary overwrite of existing files writable by the PHP process, with\npartially attacker-controlled content, leading to remote code execution where\nthe overwritten file is executed by the web server.\n\n### Patches\n\nFixed in **3.1.70**. `Disk::copy()` now always writes through the configured\nfilesystem disk, so Flysystem enforces the disk root for every export.\n\nNote the behaviour change: passing an absolute path to `store()` previously\nwrote to that path once the file existed. Paths now always resolve relative to\nthe disk root. Applications that relied on that should configure a disk rooted\nat the target location.\n\n### Workarounds\n\nFor anyone unable to upgrade, validate the path before passing it to `store()` —\nreject absolute paths and any `..` segment, or derive the filename server-side\nand never build it from request input:\n\n```php\n$name = basename($request->input('filename'));   // strips any directory part\nExcel::store($export, 'exports/' . $name, 'local');\n```\n\n### Credit\n\nReported responsibly by @seck19 via the contact address in `SECURITY.md`.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "maatwebsite/excel"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "3.1.8"
      }, {
        "fixed" : "3.1.70"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/SpartnerNL/Laravel-Excel/security/advisories/GHSA-c7r6-vx3h-w5g2"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-84374"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/SpartnerNL/Laravel-Excel/commit/b5cafdfcf7ec63924e83303763be8fcae340f70b"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/SpartnerNL/Laravel-Excel"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/SpartnerNL/Laravel-Excel/releases/tag/3.1.70"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-22", "CWE-73" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-09-08T20:40:47Z",
    "nvd_published_at" : "2026-09-01T22:17:19Z"
  }
}