URL to Drupal.org article Preventing execution of untrusted PHP

By default .htaccess inside sites/default/files contains:

<IfModule mod_php5.c>
  php_flag engine off

Adding mod_php7.c version doesn't fix.

Temporary solutions are:

ProxyPassMatch ^/(.*\.php(/.*)?)$ "fcgi://"


<FilesMatch \.php$>
   SetHandler "proxy:fcgi://"

But they are not recommended and they are overrideable.

There is a Drupal Core issue for adding mod_php7.c to .htaccess, but it's only for Drupal 8 (so how is this solved in Drupal 7 then?) https://www.drupal.org/node/2455465

There is solution for Apache How to disable PHP files from being run in the sites/default/files directory? but not nginx and php7.0-fpm.

So what is the solution?

(I'm running Security Review module that reports PHPs are executable within sites/defaul/files)

Screenshots: enter image description here


www-data:www-data 755 for dirs / 644 for files


# Turn off all options we don't need.
Options None
Options +FollowSymLinks

# Set the catch-all handler to prevent scripts from being executed.
SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
<Files *>
  # Override the handler again if we're run later in the evaluation list.
  SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003

# If we know how to do it safely, disable the PHP engine entirely.
<IfModule mod_php5.c>
  php_flag engine off

<IfModule mod_php7.c>
  php_flag engine off

I did restart nginx and php7.0-fpm.

  • 1
    You're aware that nginx doesn't process .htaccess files, those are for Apache?
    – Clive
    Commented Feb 8, 2017 at 15:28
  • good to know, but how to solve? Commented Feb 8, 2017 at 18:20
  • I think the easiest solution is to change your nginx php-fpm proxy to only access files Drupal needs to operate, e.g. /index.php and /cron.php. That way any other requested file simply won't be executed as php. You also might need to configure the handler so it doesn't serve requested .php files in plain text, no point in exposing that. I don't have examples to hand, hopefully someone else will
    – Clive
    Commented Feb 8, 2017 at 21:06

3 Answers 3


Since Nginx doesn't use .htaccess files, you have to place all your directives into the /etc/nginx/sites-available/yoursite.tld.vhost file. To prevent executing .php files, add the following lines.

location ~ \..*/.*\.php$ {
    return 403;

Place those lines before these lines.

location / {
    try_files $uri /index.php?$query_string; 

location ~ '\.php$|^/update.php|^/cron.php' {
    fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
    include fastcgi_params;
    # Block httpoxy attacks. See https://httpoxy.org/.
    fastcgi_param HTTP_PROXY "";
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param QUERY_STRING $query_string;
    fastcgi_intercept_errors on;
    fastcgi_read_timeout 180;
    # PHP 7 socket location (change it to fit your config)
    fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;

If there's a request for /anything/../file.php, it will return a 403 error, since PHP files rarely should be accessible from outside (except for index.php, update.php, and cron.php).

  • 1
    The location is clearly way too restrictive. See Gerald Melendez's answer for something that is actually correct.
    – jcaron
    Commented Apr 25, 2018 at 9:36
  • 1
    This answer is wrong. Proposed location block prevent access to PHP scripts only in hidden directories, or protect for malicious requests (such as "/forum/avatar/1232.jpg/file.php"). See: Nginx pitfalls Commented Apr 14, 2021 at 10:08

This is what works for nginx and only targets files directory:

location ~ /files/.*\.php$ {
    return 403;

This is more generic and wont let any php file in a directory execute directly:

location ~ /.*/.*\.php$ {
    return 403;

WARNING, this is posted all over the web but only works for hidden directories:

location ~ \..*/.*\.php$ {
    return 403;

How the Nginx site shows it done:

# Block access to scripts in site files directory
location ~ ^/sites/[^/]+/files/.*\.php$ {
    deny all;

The full reference file is here:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.