CVE-2026-54177 Overview
CVE-2026-54177 is an unrestricted file upload vulnerability in backpack/crud, a package that provides Create, Read, Update, and Delete functions for Backpack, a collection of Laravel packages for building administration panels. The flaw affects versions 6.0.0 through 6.8.13 and versions 7.0.0 through 7.0.37. The HasUploadFields methods uploadFileToDisk and uploadMultipleFilesToDisk, along with the withFiles() path through FileNameGenerator, do not internally reject server-executable file types. An authenticated administrator can achieve remote code execution when the public disk is web-accessible through php artisan storage:link and the web server executes the stored file extension.
Critical Impact
Authenticated administrators can upload PHP or other server-executable files to a web-accessible disk, resulting in remote code execution on the underlying host.
Affected Products
- backpack/crud versions 6.0.0 through 6.8.13
- backpack/crud versions 7.0.0 through 7.0.37
- Laravel applications using Backpack CRUD with storage:link and upload-enabled CRUD fields
Discovery Timeline
- 2026-09-14 - CVE-2026-54177 published to the National Vulnerability Database (NVD)
- 2026-09-16 - Last updated in NVD database
Technical Details for CVE-2026-54177
Vulnerability Analysis
The vulnerability is classified as [CWE-434] Unrestricted Upload of File with Dangerous Type. Backpack CRUD exposes upload-enabled fields through the CrudTrait, which relies on HasUploadFields methods uploadFileToDisk and uploadMultipleFilesToDisk as well as the newer withFiles() upload flow that routes through FileNameGenerator. Neither path enforces a package-level deny list for server-executable extensions.
When an application configures a CRUD upload field without mimes: or mimetypes: validation rules, the package accepts any uploaded extension. If the target disk is public and has been exposed through php artisan storage:link, the uploaded file becomes reachable under the web root. A web server configured to hand .php, .phtml, .phar, or similar extensions to PHP-FPM will then execute the attacker-supplied payload on request.
Root Cause
The legacy HasUploadFields code preserves the extension provided by the uploader without filtering. The newer FileNameGenerator derives an extension from the uploaded file or a data URI, again without blocking dangerous types. Application-level validation was assumed to gate uploads, but the package documentation did not require it as a security control, leaving misconfigured installations exposed to code execution.
Attack Vector
Exploitation requires authentication as an administrator with access to a CRUD panel that includes an upload field. The attacker submits a PHP payload with an executable extension through the CRUD form. The file is written to the configured public disk under its original extension, and the attacker requests the URL to trigger execution.
// Security patch in FileNameGenerator.php introduces a dangerous-extension deny list
// Source: https://github.com/Laravel-Backpack/CRUD/commit/5c5de0af242619d0653c7c70c900cd15b1a197c5
public static function getDangerousExtensions(): array
{
return [
'php', 'php3', 'php4', 'php5', 'php7', 'php8',
'phtml', 'phar', 'phps', 'shtml',
'pl', 'py', 'rb', 'jsp', 'cgi',
'asp', 'aspx',
'sh', 'bash', 'bat', 'cmd', 'exe',
'htaccess',
];
}
private function getExtensionFromFile(string|UploadedFile $file): string
{
if (is_a($file, UploadedFile::class, true)) {
$ext = $file->extension();
} elseif (Str::startsWith($file, 'data:')) {
preg_match('#^data:([^;]+);#', $file, $m);
$ext = Str::after($m[1] ?? '', '/');
} else {
$mime = mime_content_type($file);
// ...
}
}
Stop Remote Code Execution Before It Runs
Singularity™ Endpoint detects and blocks exploit attempts at machine speed, including zero-days and novel attack techniques.
Stop Exploit AttemptsDetection Methods for CVE-2026-54177
Indicators of Compromise
- Files with extensions such as .php, .phtml, .phar, .jsp, .aspx, or .sh in directories under storage/app/public or the symlinked public/storage path.
- CRUD upload requests followed shortly by GET requests to the same file path under /storage/.
- New or modified .htaccess files inside publicly served upload directories.
Detection Strategies
- Audit installed backpack/crud versions using composer show backpack/crud and flag any release below 6.8.14 or 7.0.38.
- Review CRUD field definitions for upload, upload_multiple, and withFiles() usage that omits mimes: or mimetypes: validation.
- Inspect web server access logs for POST requests to CRUD endpoints followed by GET requests returning 200 for scripts in upload directories.
Monitoring Recommendations
- Enable file integrity monitoring on storage/app/public and any symlinked web root to detect new executable files.
- Log PHP-FPM execution events and alert when interpreters serve requests from user upload directories.
- Correlate administrator authentication events with subsequent file writes to upload paths to surface abuse of legitimate accounts.
How to Mitigate CVE-2026-54177
Immediate Actions Required
- Upgrade backpack/crud to version 6.8.14 or 7.0.38 using composer update backpack/crud.
- Add mimes: and mimetypes: validation rules to every CRUD upload field at the application layer.
- Review existing upload directories for server-executable files and remove any that were not placed there by a trusted process.
Patch Information
The issue is resolved in Backpack CRUD 6.8.14 and 7.0.38. Pull request #5993 introduces the getDangerousExtensions() deny list in FileNameGenerator and enforces it inside HasUploadFields. Pull request #5994 hardens related request handling. See the GitHub Security Advisory GHSA-8q2w-pv9p-mjvc for the full advisory.
Workarounds
- Configure the web server to refuse execution of PHP and other interpreter extensions inside upload directories.
- Store uploads on a private disk and stream files through a controller instead of exposing them through php artisan storage:link.
- Restrict administrator access to CRUD panels with upload fields until the package is upgraded.
# Nginx: deny script execution inside the public storage directory
location ^~ /storage/ {
location ~ \.(php|phtml|phar|phps|pl|py|rb|jsp|cgi|asp|aspx|sh|bash|bat|cmd|exe)$ {
deny all;
return 403;
}
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

