Problem/Motivation
This was originally reported as a private security issue but cleared by the security team for a public issue
Drupal core's file upload security mechanism relies on an insecure extension blocklist to prevent the upload of executable server-side scripts. When a file with a dangerous extension is uploaded, Drupal renames it by appending _.txt to neutralize execution.
In Drupal 10.5.6, the insecure extensions list (defined in FileSystemInterface::INSECURE_EXTENSIONS and referenced by FileUploadSanitizeNameEvent) blocks the following extensions:
phar | php | pl | py | cgi | asp | js | phtml
However, this list is incomplete. The following PHP-executable extensions are not blocked and upload without being renamed:
- .php3
- .php4
- .php5
- .php7
- .php8
- .pht
Steps to reproduce
Proposed resolution
Add these to the list
Remaining tasks
User interface changes
Introduced terminology
API changes
Data model changes
Release notes snippet
Issue fork drupal-3593394
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #4
tarawij commentedI've opened an MR !15970 for this issue.
The MR adds php3, php4, php5, php7, php8 and pht to FileSystemInterface::INSECURE_EXTENSIONS and updates the matching insecure extension regex.
It also includes test coverage for filename sanitisation and JSON:API upload rejection for these extensions.
I'd appreciate any feedback or review. Thanks for your time.
Comment #5
smustgrave commentedBased on the feedback from @larowlan
If you are another contributor eager to jump in, please allow the previous poster(s) at least 48 hours to respond to feedback first, so they have the opportunity to finish what they started!
Comment #6
tarawij commentedComment #7
smustgrave commentedBelieve feedback from @larowlan has been addressed
Comment #8
matt-whelan commentedTested on a fresh standard install of 12.x-dev (PHP 8.5), applying the MR over a clean checkout. The before/after is clear.
On plain main the real
FileUploadSanitizeNameEventpath lets these through unneutralised:With the MR applied they are all neutralised:
Coverage looks good. The MR adds the new extensions to the
SecurityFileUploadEventSubscriberTestunit data set and to the jsonapiFileUploadTest, and both passed for me. No concerns on the change itself.One scope question, not a blocker. After the fix a few more extensions still pass through, in the same severity class as the ones the MR adds. None of these execute under a stock php-fpm config. The shipped handler is
.+\.ph(ar|p|tml)$, so by default only phar, php and phtml run. Drupal's own files-directory.htaccessalso neutralises everything viaSetHandlerand engine off. So this is really defence-in-depth for setups where that.htaccessisn't honoured, like nginx orAllowOverrideoff, which is exactly why blocking php3 to php8 is worth doing. On the same logic:phtmexecutes under an older or wildcard handler, the same case aspht. Worth adding..user.iniis a different mechanism, php-fpm readingauto_prepend_fileto chain execution, but a comparable outcome. The stock config does not deny it, so it is worth adding for the nginx / no-htaccess case.shtmlis the SSI equivalent (mod_include), off by default, same misconfig class. Worth a mention at least.For what it's worth I would leave
phpsoff, since it renders source rather than executing and the stock config denies it outright.phptis marginal.php2andphp6are not real vectors, as no handler ever shipped, so leaving them off is correct.None of this blocks the MR, which is a clear improvement on what's there now. It is just whether to round the list out here or in a follow-up.