Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

The safest way to secure WordPress uploads is to keep /wp-content/uploads readable for normal media while denying PHP execution in that directory. Apply the denial in the web server (Nginx server configuration or Apache/LiteSpeed configuration), then verify that a harmless PHP test file is blocked while JPG, PNG, PDF and other required media still load.

Do not solve this by making uploads inaccessible or by removing PHP write access that WordPress needs. The objective is delivery of legitimate files without allowing an uploaded script to run.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What the uploads directory needs to do

WordPress normally stores images, documents, audio, video and other user media below /wp-content/uploads. Browsers must be able to request those files over HTTP or HTTPS, and the PHP process used by WordPress must be able to create new files there. A rule that blocks every request, or permissions that prevent WordPress from writing, will break the Media Library and existing content.

The security problem

If an attacker can place a PHP file in a web-accessible directory and the server is configured to execute PHP there, requesting that file can run attacker-controlled code with the privileges of the web process. A compromised plugin, stolen administrator account, vulnerable upload form or incorrectly configured import can all create that opportunity.

#1 Best Overall
wordpress hosting
  • easy to use
  • Free app
  • Compatible with all devices
  • It gives the best comparison between ten different hosts

The control to apply

Deny PHP execution specifically in the uploads path. A request for a PHP file should receive a denial such as HTTP 403, or a non-executing 404, while ordinary media continues to return normally. This is a server-layer control; a WordPress plugin cannot reliably replace it because the web server may process the request before WordPress runs.

Identify the real path and server before editing anything

Do not paste a rule until you know which server handles the request and which directory is actually public.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Confirm the document root and uploads location

  1. Open the hosting control panel or server configuration and identify the site’s document root.
  2. Confirm that the physical uploads directory is inside that root, commonly wp-content/uploads. Some hosts use a symlink, a separate mount or custom media storage.
  3. Check the WordPress Media settings and an existing media URL so you know the URL path that must remain available.
  4. Make a backup of the applicable server configuration and the existing .htaccess file before changing it.

Determine the web server

Apache and LiteSpeed can use per-directory .htaccess rules when the host permits overrides. Nginx does not read .htaccess; its rule belongs in the relevant server configuration. IIS uses its own configuration model. If the host does not disclose the server, ask support before applying a directive, because a syntactically valid rule for one server can be ignored or cause an outage on another.

Check for Multisite and custom storage

Multisite installations can use additional files paths and rewrite behavior. WordPress’s Nginx guidance covers both uploads and files paths for this reason. A blanket rule aimed only at /wp-content/uploads may leave a multisite path unprotected, while a rule aimed at every files path can interfere with a custom setup. Map the actual URLs first.

Nginx: deny PHP in the server configuration

Nginx has no directory-level configuration file equivalent to Apache’s .htaccess or IIS’s web.config, as stated in the WordPress Developer Resources Nginx – Advanced Administration Handbook. The rule must be placed in the applicable Nginx server block (or an included configuration file loaded by that block).

Rule for standard uploads and Multisite files paths

location ~* /(?:uploads|files)/.*.php$ {
    deny all;
}

The expression matches a PHP request below a URL segment named uploads or files, regardless of case, and denies it before PHP handling. Use the exact server configuration structure required by your host; do not create an arbitrary file that Nginx never includes.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Deploy safely

  1. Save a copy of the current Nginx configuration.
  2. Place the location block in the server block that serves the WordPress site, following the host’s include conventions.
  3. Validate the configuration with the host’s Nginx configuration test command or control-panel validator. Do not reload a configuration that fails validation.
  4. Reload Nginx using the host’s approved method so existing connections are handled cleanly.
  5. Run the functional test described below from an external browser or an HTTP client.

Location matching and include order can matter in a complex configuration. If a generic PHP location appears to take precedence, ask the administrator to confirm that the uploads denial is selected for a request such as /wp-content/uploads/security-test.php.

Apache or LiteSpeed: use an uploads-directory rule

Apache supports per-directory .htaccess configuration, and LiteSpeed commonly supports the same syntax. Add the rule in the physical uploads directory when possible, or in the applicable virtual-host configuration when you administer the server directly.

Common Apache rule

<FilesMatch "\.php$">
    Require all denied
</FilesMatch>

This denies requests for files whose names end in .php in the directory where the rule is applied. The host must allow the relevant override class; otherwise Apache will ignore the file or return a server error. Confirm the permitted directives with the host if you do not control the virtual-host configuration.

Where to put the rule

  • Uploads-only .htaccess: place the rule in the uploads directory so its scope is narrow and easy to audit.
  • Site-level .htaccess: place the custom rule outside WordPress’s # BEGIN WordPress and # END WordPress generated block. WordPress may rewrite that block during permalink changes or updates.
  • Virtual-host configuration: use this when you need a centrally managed rule or when .htaccess overrides are disabled.

Do not replace the generated WordPress rewrite section merely to add this control. Keep a copy of the file and check the web server error log if requests begin returning 500 errors.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

LiteSpeed considerations

Use the Apache-compatible rule only where the LiteSpeed host confirms that .htaccess processing and Require authorization directives are enabled. A managed host may require the same rule in its panel or server template instead.

IIS and managed hosting

IIS does not use Apache’s Require all denied syntax. Apply the equivalent request-filtering or handler restriction in the IIS configuration supplied by the host, and ask support to scope it to PHP files below the uploads path. Managed WordPress providers may already enforce this control at the web-server layer; request confirmation of the exact path covered, whether Multisite files URLs are included, and how the setting survives migrations or server changes.

Test the control without risking the site

A configuration is not complete until a real request proves that PHP cannot execute and that media still works. The WordPress Nginx guidance recommends creating a harmless PHP file, requesting it, confirming it cannot execute and deleting it afterward.

  1. Using the same account and deployment method WordPress uses, create a file named security-test.php directly inside the applicable uploads directory.
  2. Put only plain text in the file, for example uploads security test. Do not include PHP code, shell commands or credentials.
  3. Construct its public URL from an existing uploads URL, such as https://example.com/wp-content/uploads/security-test.php. Use your own domain and actual path.
  4. Request the URL in a private browser window or with an HTTP client that does not use a cached response.
  5. Confirm that the response is denied. A 403 or 404 is expected; a page displaying the file’s text is also non-execution, but investigate why the server is serving it as text rather than applying the intended denial.
  6. If the response executes PHP or returns a PHP-generated result, stop and correct the server rule before leaving the file in place.
  7. Request representative JPG, PNG, PDF, audio, video and other media already used by the site. Confirm they remain available and that thumbnails and front-end pages render.
  8. Delete security-test.php and verify that it no longer exists. Never leave even a harmless test file in a public directory.

Test after operational changes

Repeat the two-part test after a host migration, PHP or web-server upgrade, caching change, control-panel restoration or rewrite-rule edit. A previously effective rule can disappear when a provider replaces the server template or restores only the site files.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Permissions and ownership: preserve writing without making uploads writable to everyone

Execution blocking is the primary control, but file permissions determine who can place or alter files. Avoid world-writable 777 permissions. WordPress hardening guidance recommends least privilege because every unnecessary writer increases the attack surface.

  • Give the web process or deployment account only the write access required for uploads.
  • Keep files and directories owned by the intended system account rather than an unrelated shell user or an anonymous account.
  • Use the host’s documented directory and file modes instead of copying a numeric mode from another server with different user and group arrangements.
  • After changing ownership or modes, upload a normal image through the Media Library and confirm that WordPress can create its year/month directory and generate derivatives.
  • Inspect the uploads tree for unexpected executable files and investigate their origin before deleting evidence needed for an incident review.

Do not remove all write access merely to make the directory appear secure. If WordPress cannot write, uploads, image resizing and some plugin features will fail.

Best Value
WordPress Hosting Guide
  • Free WordPress Hosting Guide Android Application. It Contains: A Brief Overview of WordPress Hosting, 9 Major Benefits of Managed WordPress Hosting.
  • 5 Simple Steps to Choose WordPress Hosting, How to Maximize Your WordPress Hosting and Blogging Success, How to Choose the Best WordPress Hosting Provider, Optimize Your Blog with VIP Word.
  • Press Hosting, What You Should Know to Choose the Best WordPress Hosting and Much More.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Defense in depth around the uploads control

Keep the application current

Update WordPress core, themes and plugins, and remove components that are no longer used. An execution-denial rule limits one attack path but does not fix a vulnerable plugin, stolen credentials or malicious administrator action.

Disable dashboard file editing when appropriate

For sites whose operators do not need in-dashboard theme or plugin editing, set DISALLOW_FILE_EDIT in wp-config.php. This removes a high-impact editing capability from the dashboard; it does not replace the uploads rule or secure a compromised server account.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use additional filtering and monitoring

A security plugin, reverse-proxy WAF or hosting firewall can add request filtering, rate controls and alerting. Treat these as additional layers. They do not replace the web-server rule that prevents a PHP file in uploads from executing even when another layer is misconfigured or unavailable.

Run with limited privileges

Run the site and web server as non-privileged users where the operating model allows it. Limiting the process account reduces the damage an attacker can do if another vulnerability is exploited, although it does not remove the need to deny PHP execution in uploads.

Troubleshooting common failures

Symptom Likely cause Action
PHP test file executes The rule is in the wrong server configuration, is not loaded, or a more specific handler takes precedence. Check the active server block or virtual host, validate and reload the configuration, then retest with a newly named file.
.htaccess causes HTTP 500 An unsupported directive, malformed syntax or disallowed override is being used. Read the web-server error log, restore the backup, and ask the host which authorization directives are permitted.
Images return 403 or 404 The rule was applied to all uploads requests instead of only PHP, or file permissions/ownership are wrong. Limit the match to PHP, verify the directory path, and test permissions with an existing image.
Rule has no effect on Nginx The change was made only in .htaccess, which Nginx does not read. Move the denial into the active Nginx server configuration and reload after validation.
Single-site test passes but Multisite remains exposed The site uses a files URL or rewrite path not covered by the rule. Map the Multisite media URL and include the required path in the server-level control without blocking legitimate file delivery.
WordPress cannot upload after hardening PHP lost write access, ownership changed, or permissions were set too restrictively. Restore the documented least-privilege ownership and write mode, then test an upload and derivative generation.

Change checklist for production

  1. Record the document root, physical uploads path, public media URL and whether the site is Multisite.
  2. Identify Apache/LiteSpeed, Nginx or IIS and obtain the required configuration access.
  3. Back up the current configuration and confirm a rollback method.
  4. Add a PHP-execution denial scoped to uploads and any required Multisite files path.
  5. Validate syntax before reloading or restarting the web server.
  6. Create the plain-text security-test.php file and verify that its request is denied.
  7. Load representative media and perform a normal WordPress upload.
  8. Delete the test file, inspect for unexpected executables, and review ownership and permissions.
  9. Document the rule location so it is restored during migrations and rechecked after infrastructure changes.

The practical standard

A secure WordPress uploads directory is not an inaccessible directory. It is a directory where browsers can retrieve legitimate media and WordPress can write through the intended account, while the web server refuses to execute PHP files placed there. Implement that rule at the correct server layer, account for Multisite or custom storage, verify both denial and media delivery, and maintain least-privilege permissions and current software.

Quick Recap

Bestseller No. 1
wordpress hosting
wordpress hosting
easy to use; Free app; Compatible with all devices; It gives the best comparison between ten different hosts
Bestseller No. 5
WordPress Hosting Guide
WordPress Hosting Guide
Press Hosting, What You Should Know to Choose the Best WordPress Hosting and Much More.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.