|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #68053 PHP-FPM with cgi.fix_pathinfo 0 loads script from PATH_TRANSLATED
Submitted: 2014-09-19 10:44 UTC Modified: 2023-04-06 14:41 UTC
Avg. Score:4.2 ± 0.8
Reproduced:2 of 2 (100.0%)
Same Version:0 (0.0%)
Same OS:1 (50.0%)
From: devel at jasonwoods dot me dot uk Assigned: bukka (profile)
Status: Wont fix Package: FPM related
PHP Version: 5.5.17 OS: CentOS 6.5
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2014-09-19 10:44 UTC] devel at jasonwoods dot me dot uk
Looking at the nginx example config here:
(or even here:

During a request, PATH_TRANSLATED is set to the full path to the PATH_INFO on the filesystem as defined by the CGI specification:

Now we have something like this:

    location ~ [^/]\.php(/|$) {
        fastcgi_split_path_info ^((?U).*[^/]\.php)(/.*)$;
        include "fastcgi.conf"; # To get the other standard variables
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
        if (!-f $document_root$fastcgi_script_name) {
            return 404;
        fastcgi_pass unix:/var/run/php-fpm/{{ id }}.sock;

This works OK with cgi.fix_pathinfo=1 in the PHP-FPM configuration. Scripts run fine as expected with PATH_INFO populated and PATH_TRANSLATED populated. For example, requesting would load script.php.

Now, a lot of blogs (maybe incorrectly) say to disable cgi.fix_pathinfo for security, and reading the docs it makes sense... I've done the splitting in Nginx, why should FPM do any... However, setting it to 0 will generally result in "Access is denied!" and error_log such as the following:

FastCGI sent in stderr: "Access to the script '<root>/images' has been denied (see security.limit_extensions)" while reading response header from upstream, client: X.X.X.X, server:, request: "GET /test.php/images HTTP/1.1", upstream: "fastcgi://unix:/var/run/php-fpm/test.sock:", host: ""

If you change the request to, and actually create that script in <root>/images/anotherphpscript.php, it actually loads that script! It seems that when PATH_TRANSLATED is present and fix_pathinfo is 0, PHP loads the script from the path pointed to by PATH_TRANSLATED and ignores SCRIPT_FILENAME completely! Yet from what I can gather, PATH_TRANSLATED is the filesystem path to the PATH_INFO stem - this is not meant to be the script to run!

Looking into it further though, it seems PHP documentation kind of states this:
'PATH_TRANSLATED' - Filesystem- (not document root-) based path to the current script, after the server has done any virtual-to-real mapping.

Yet looking elsewhere you get a completely different definition:
Meanwhile, the variable PATH_TRANSLATED is also set, which maps the information stored in PATH_INFO to the document root directory (e.g., /usr/local/etc/httpd/ public/cgi/cgi-doc.txt).

Have I misunderstood this completely or PHP completely loading the wrong script?

The thing that concerns me is it appears that using configs on the Nginx website and following a common security recommendation on the web, essentially makes one potentially INSECURE, as it means someone could run a PHP file in /images/ even if you have a match in nginx on /images/ that returns 401

FYI - Adding cgi.discard_path = 1 (with cgi.fix_pathinfo = 0) seems to fix the problem though appears to be sparsely mentioned, but introduces a new issue in that PHP_SELF remains the same and ends up the PATH_INFO (/images/anotherphpscript.php - which would be right if it was still running that script)
Compare to cgi.discard_path = 0 (default) and cgi.fix_pathinfo = 1 where PHP_SELF is correct (/script.php/images/anotherphpscript.php)

Test script:
This is a really good example, who

Setup nginx with php-fpm and use following block for requests:

    location ~ [^/]\.php(/|$) {
        fastcgi_split_path_info ^((?U).*[^/]\.php)(/.*)$;
        include "fastcgi.conf"; # To get the other standard variables
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
        if (!-f $document_root$fastcgi_script_name) {
            return 404;
        fastcgi_pass unix:/var/run/php-fpm/{{ id }}.sock;

1. Create <root>/images/anotherphpscript.php

2. Create <root>/script.php to output "SCRIPT.PHP"
echo "SCRIPT.PHP";

3. Request

Expected result:
When requesting
Receive output "SCRIPT.PHP"

Actual result:
When requesting
Receive PHP info dump with following _SERVER:

_SERVER["USER"]	test
_SERVER["HOME"]	/home/test
_SERVER["SCRIPT_FILENAME"]	/home/access/site/script.php
_SERVER["SCRIPT_NAME"]	/script.php
_SERVER["REQUEST_URI"]	/script.php/images/anotherphpscript.php
_SERVER["DOCUMENT_URI"]	/script.php/images/anotherphpscript.php
_SERVER["DOCUMENT_ROOT"]	/home/access/site
_SERVER["PATH_INFO"]	/images/anotherphpscript.php
_SERVER["HTTPS"]	no value
_SERVER["PATH_TRANSLATED"]	/home/access/site/images/anotherphpscript.php
_SERVER["HTTP_ACCEPT"]	text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
_SERVER["HTTP_USER_AGENT"]	Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/537.75.14
_SERVER["PHP_SELF"]	/images/anotherphpscript.php
_SERVER["REQUEST_TIME_FLOAT"]	1398935271.6949
_SERVER["REQUEST_TIME"]	1398935271


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2014-09-19 10:45 UTC] devel at jasonwoods dot me dot uk
Originally raised as #67164 but was private, so we can delete/close/duplicate #67164 and keep this public one - I'm keen if anyone else experience this or knows what is "right"
 [2023-04-06 14:41 UTC]
-Status: Open +Status: Wont fix -Assigned To: +Assigned To: bukka
 [2023-04-06 14:41 UTC]
I have been looking into this and agree that the behaviour is a bit unfortunate. However I don't think we can fix it all at this stage as it could result in hard to find a BC break as some application might rely on the PATH_TRANSLATED being used and PHP_SELF having always PATH_INFO value if set. I don't think we can fix the PATH_TRANSLATED at all and don't see it as a big issue as there is still cgi.discard_path = 1. There is a better case for PHP_SELF though and I think we should address it as an improvement so we limit the impact of its BC break. For that I created following issue:

Closing this as won't fix even though the PHP_SELF will be likely addressed but that's just part of this report and will be more an improvement as I said.
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Jun 15 07:01:29 2024 UTC