How To Stop PHP in Uploads With BetterShield?
Add an .htaccess rule so a PHP file in the uploads folder answers 404 instead of running, see which servers support it, and remove it cleanly.
With BetterShield, add an .htaccess rule so a PHP file in the uploads folder answers 404 instead of running, see which servers support it, and remove it cleanly.
What it does
In BetterShield, Uploads code block makes sure a PHP file in your uploads folder cannot be run by requesting its address. In the plugin’s words, that is the most common way an uploaded file becomes a way in. It is under Code and settings changes on BetterShield › Protection › Hardening, it starts off, and it needs a web server that reads its kind of .htaccess rule: Apache, or LiteSpeed’s paid edition.
- Writes one marked block into the .htaccess file in your uploads folder (wp-content/uploads on most sites), creating the file if there is none. Nothing else in the file is touched.
- Answers 404 for PHP-like files. Any request under uploads for a name ending in .php, .phar, .pht, .phtm, .phtml, .phps, or .php and a digit (such as .php7) is answered 404 before it reaches PHP, in any mix of capitals, and also with something added after the name (image.php.jpg, file.php/extra).
- Leaves every other file alone. Images and documents are served as before.
The block it adds:
# BEGIN BetterShield uploads-php-execution
RedirectMatch 404 "(?i)\.(php|phar|pht|phtm|phtml|phps|php[0-9])(\.|/|$)"
# END BetterShield uploads-php-execution
Your web server applies the rule, not WordPress, so it stays in force during safe mode and while BetterShield is deactivated.
| Server | On the row |
|---|---|
| Apache | Available. |
| LiteSpeed | Available. The note says LiteSpeed’s paid edition reads the rule and the free OpenLiteSpeed skips it, so BetterShield could not confirm it is enforced. |
| OpenLiteSpeed | Not available here: it “reads only rewrite rules from .htaccess files and skips the kind this fix writes”; your host can set the same protection in the server configuration. |
| nginx, IIS | Not available here. The note says the server does not read .htaccess files, and that your host can set the same rule in the server configuration. |
| Not identified | Available. The note says the rule will be written but BetterShield could not confirm it is enforced. |
Step 1: Open BetterShield › Protection › Hardening
Open BetterShield › Protection › Hardening and find Uploads code block under Code and settings changes.
Step 2: Stop PHP running in the uploads folder
- Read any note under the description, about your server or about rules another plugin already keeps in the uploads .htaccess.
- Press Preview the change. Nothing is written.
- Turn the switch on. The row shows On since and Undo never expires, and lists anything BetterShield could not confirm.
- Open an image from your Media Library in a new tab, to confirm uploads still load.
The fix has no options. Monitor first cannot watch this fix in advance; its panel points you back to the preview.
From the terminal, wp bettershield harden uploads_php --dry-run previews it and wp bettershield harden uploads_php --user=<login> applies it (WP-CLI commands). An AI assistant can neither apply nor remove this fix: it writes to a file, so it stays your switch.
Recommended settings
We recommend it on every site whose server reads .htaccess: uploads hold files people gave the site, and none need to run as code. BetterShield’s file check never looks inside uploads, so this rule is what covers that folder. On nginx, IIS or OpenLiteSpeed, ask your host to refuse PHP files under uploads in the server configuration.
If Non-admin users can upload files that can run code names a PHP type (it is then High), its note asks you to switch this on too. Do that, and change the plugin or theme setting that allows the type: this fix does not close that finding.
| Site | What we recommend |
|---|---|
| Agency or many sites | On a multisite network, apply it once from the main site (see below). |
What it can break, and how to undo
- Code meant to run from uploads. Anything that opens a PHP file in uploads by its web address stops, and that address answers 404. Code that loads such a file from inside PHP is not affected.
- Unusual file names. A download named with .php followed by a dot, such as notes.php.txt, answers 404 too. Rename it.
- A server that refuses the rule. Where a server does not allow this kind of rule in .htaccess, files in uploads can fail with a server error; the dashboard and sign-in are not affected. The image check below verifies this: if the image fails, turn the switch off and ask your host.
- A file it cannot write. Nothing changes, the message says why (for example “The change was not applied: the file is not writable.”), and the activity log records “Hardening could not be applied”.
- Rules already there. If another plugin keeps rules in the uploads .htaccess, the row names them: “This item adds its own marked block and never touches theirs; if both refuse the same request, the earlier rule answers.”
To undo, turn the switch off. BetterShield removes exactly its block, and deletes the .htaccess file too if it created it and nothing else is in it. That needs a signed-in browser session (not an application password), and your password if Ask for my password before removing a protection is on under Settings › General. From the terminal: wp bettershield harden uploads_php --undo --user=<login>.
If anyone has edited inside the block since, undo leaves the file alone and the row says the last undo did not complete. Keep anything that was added, delete the block by hand from its BEGIN line to its END line, then turn the switch off again.
The rule also stays if you delete BetterShield with Keep everything, the default under If this plugin is ever deleted. Undo it first if you do not want to keep it. See General settings.
Final Outcome
From outside. Over SFTP or your host’s file manager, put an empty file named test.php in your uploads folder and open yoursite.com/wp-content/uploads/test.php. With the rule working you get a “not found” page; a blank page means PHP ran the file. Delete the test file afterwards.
- The row. On since and Undo never expires, with “This one has no effect a page view can check, so it is reported from your settings.”
- The activity log. “Hardening applied” and “Hardening undone” (or “Hardening could not be undone”).
- Findings. This fix has no finding of its own, so applying it does not change your score. While it is on, Some protections that are switched on are not working (Medium) names it if its block in the uploads .htaccess is missing or was edited.
On multisite
- From the main site it covers every site, because each site’s uploads folder sits inside the main site’s. The preview says so.
- From any other site it covers that site’s uploads only.
- Undoing it on the main site removes it for every site that has not applied it on its own.
See Multisite networks.
Related
- Hardening
- Stop uploads listings
- Hide sensitive files
- Disable the file editor
- Server compatibility
- Multisite networks
This is how you can stop PHP in uploads with BetterShield.
Getting Stuck? Feel free to contact our Dedicated Support Team.