In this article in digitalocean.com Justin Ellingwood recommends to turn off cgi.fix_pathinfo:

Inside, we need to find a section that configures the cgi.fix_pathinfo behavior. It will be commented out and set to "1" by default. We need to uncomment this and set it to "0". This will prevent PHP from trying to execute parts of the path if the file that was passed in to process is not found. This could be used by malicious users to execute arbitrary code

Even though IMHO Justin Ellingwood is very good in writing documentation, I must say this entire passage was somewhat unclear to me.

To take care of this as Justin recommended I ran:

sed -i "s/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g" /etc/php/*/fpm/php.ini

The article was wrriten in April 2016 and might have been based on somewhat "old" data. I'm not sure this recommendation is still critical in January 2018 and Nginx configurations can be quite dynamic.

To date, is it really critical to do the change recommended there?


I would not describe this change as "critical" per se, but it still has security implications. I'm not aware of anything that has fundamentally changed since that advice became relevant -- PHP's behavior tends strongly towards backwards compatibility, even when that has security implications. Imagine you have a server that allows people to upload files to the server, say in a directory called upload. Now, your upload script is careful to only allow files with certain extensions (say only .png) to ensure nobody uploads a malicious PHP file.

Now, as an attacker, I'll try to write a PHP shell into a file, name the file evil.png, and upload it. When it uploads, I'll visit http://example.com/upload/evil.png, but I'll discover that this just downloads the file to me -- nginx never dispatched the request to php-fcgi to be processed as php, because the filename ends in .png.

If I'm an attacker who's aware of PATH_INFO, next I'll try http://example.com/upload/evil.png/index.php. If your server is so configured, this will result in PHP being executed (because nginx sees the index.php at the end) and PHP will walk the path until it finds a component that is a file, not a directory (evil.png) and attempt to execute it. Then my shell gets executed and I win.

That being said, there's better ways to deal with this by having the NGINX config split the path in advance, so PHP isn't walking the filesystem.

From Neal Poole's excellent blog post on the issue:

# Pass all .php files onto a php-fpm/php-fcgi server.
location ~ \.php$ {
   # Zero-day exploit defense.
   # http://forum.nginx.org/read.php?2,88845,page=3
   # Won't work properly (404 error) if the file is not stored on this server, which is entirely possible with php-fpm/php-fcgi.
   # Comment the 'try_files' line out if you set up php-fpm/php-fcgi on another machine.  And then cross your fingers that you won't get hacked.
   try_files $uri =404;

   fastcgi_split_path_info ^(.+\.php)(/.+)$;
   include fastcgi_params;
   fastcgi_index index.php;
   fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
   fastcgi_pass php;
  • 1
    Thanks David. Do you have an opinion on why it's setted as ;cgi.fix_pathinfo=1 in the first place? I mean, given what you described (php injection is the term?), I can't understand why the PHP-FPM developers didn't set this to cgi.fix_pathinfo=0 from the start. Jan 12 '18 at 17:44
  • To clarify: your snippet at the end compliments the situation where (a) fix_pathinfo=0 (b) fix_pathinfo=1, or (c) either? Jun 5 '20 at 14:30

Even now it seems to carry danger because of how PHP is still processing script from the 1st occurence of found file. So why did they keep the default as ;cgi.fix_pathinfo=1 then?

Because CGI is independent of PHP and have its own standard. CGI (Common Gateway Interface) is an interface that instructs the server on how to communicate data with applications, how request information and body is passed, from input to output. Servers of Web can be configured to execute a program as a CGI, which means they will forward the request data to a specific program. And that's how NGinx passes request to PHP.

Speaking of CGI Standard, PHP-FPM developers have to comply with CGI standard as they stated in the PHP-FPM ini file ex : /etc/php/7.2/fpm/php.ini :

; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI.  PHP's
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is.  For more information on PATH_INFO, see the cgi specs.  Setting
; this to 1 will cause PHP CGI to fix its paths to conform to the spec.  A setting
; of zero causes PHP to behave as before.  Default is 1.  You should fix your scripts
; http://php.net/cgi.fix-pathinfo

So I suppose the text Setting this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting of zero causes PHP to behave as before. explains the choice. Here is the PATH_INFO CGI Spec.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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