Repository navigation
Conversation
Uploads were stored under the client's original extension, while UploadFileRequest validates only the type detected from the contents. A file whose contents pass that check could therefore be stored as .php or .phtml, for example a PNG with PHP appended. Add File::storageExtensionForUpload(). It keeps the client's extension when it matches the detected type or is a plain data format that detection reports loosely (CSV, XLSX, JSON, certificates and so on), otherwise takes the extension of the detected type, falling back to "bin", and never returns an extension a web server may execute. Use it for multipart uploads (randomFileNameFromRequest) and for FileResolverService uploads. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #320 +/- ##
===========================================
Coverage 100.00% 100.00%
- Complexity 8935 8941 +6
===========================================
Files 473 473
Lines 28067 28075 +8
===========================================
+ Hits 28067 28075 +8
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
FileController::upload(internal and v1) names stored files throughFile::randomFileNameFromRequest(), which keepsgetClientOriginalExtension().UploadFileRequestchecks only the type detected from the file's contents, and its allowed list includesapplication/octet-stream,text/plain,text/javascriptand the image types. So a file whose contents pass that check can still be stored as.php,.phtmland so on, for example a valid PNG with extra bytes appended and a.phpname.The default Docker image does not link
public/storage, so it is not exposed. On installs that have runphp artisan storage:link, or that serve the upload disk from a PHP-enabled web root, a file stored with a script extension could be executed by the web server. This PR is hardening so the stored name never depends on that deployment detail.Change
New
File::storageExtensionForUpload(UploadedFile $file):MimeTypes), or when it is a plain data format that detection often reports loosely:csv,tsv,txt,json,xls(x),doc(x),ppt(x),pdf, archives, certificate formats. This keeps imports working, e.g. a CSV detected astext/plainor an XLSX detected asapplication/zip.guessExtension()(from the detected type), falling back tobin.php,php3–php8,phtml,phar,pht,phps,shtml,htaccessorcgi; those becomebin.It is used by
randomFileNameFromRequest()(when no explicit extension is passed) and byFileResolverService::resolveFromUpload(), which had the same pattern. Ordinary uploads keep their names:photo.pngstays.png,orders.csvstays.csv. A PNG uploaded asphoto.jpgis now stored as.png.original_filenameis unchanged.Not changed here: SVG uploads are still stored as
.svgbecause that is their real type. Thediskandpathinputs are still taken from the request; restrictingdiskto configured disks could be a follow-up if you want it.Tests
FileModelTest: new case covering:photo.PNG→png;.jpg→png;shell.php→png;shell.phtml→png;png;orders.csv→csv;config.json→json;.phar→txt;.php5→bin;randomFileNameFromRequest()still wins.FileControllerTest: an upload namedshell.phpwith PNG contents is stored under.png. Thefile_controller_upload_request()helper gains an optional original-name argument (the default is unchanged).I ran these on PHP 8.2 with bcmath and gd:
FileControllerTest: 19/19 pass.FileResolverServiceTest: 7/7 pass.FileModelTest: 12/13 pass. The failure isit exposes file uploader relationship metadata(no DB connection when the file runs on its own), which fails the same way onmain.Both new cases fail on
main.php-cs-fixer --dry-runis clean on the four changed files.phpstanonFile.phpandFileResolverService.phpgives the same count asmain. The one existing finding about$request->file()possibly being an array now points at the new call instead ofgetClientOriginalExtension().This PR was prepared with an AI coding tool (Claude Code) and reviewed by Shiv. Found by Mindcat (mindcat.ai).
Generated by Claude Code