Skip to content

Protecting attachments under nginx

The plugin drops an .htaccess into wp-content/uploads/solis-forms-uploads/ that forbids the execution of any script found there.

nginx does not read .htaccess files. No plugin can write to its configuration, which requires a server reload: the rule has to be put in place by hand. Without it the folder stays protected from listing, but nothing would stop a script that managed to land there from running.

The rule

To be added to the site’s server block:

location ~* /wp-content/uploads/solis-forms-uploads/.*\.(php|phtml|php[0-9]|pl|py|jsp|asp|sh|cgi)$ {
    deny all;
    return 403;
}

Then reload: nginx -t && systemctl reload nginx.

Checking it

Drop a test.php file into the folder and call it from a browser. The expected answer is 403. If the file runs, the rule is not active — check that it comes before the location that hands .php to PHP-FPM, nginx keeping the first match among regular expressions.

Remember to delete the test file.

Why this protection exists

Accepted types are checked against the file’s actual content, and the stored name is rebuilt from the extension that was kept: a document.php.jpg becomes {token}.jpg, and the double extension does not survive the upload.

The rule is necessary all the same. Defence in depth does not assume an upstream check is infallible, and the list of accepted types may one day be widened, by an add-on or by the plugin itself.

Managed hosting

Some hosts (WP Engine, Kinsta, Pressable, o2switch and others) already forbid PHP execution inside wp-content/uploads. The rule is then redundant, but harmless: adding it costs nothing and protects you from a change of policy.