Skip to content

Decode SCRIPT_FILENAME issue in php 8.5 #19817

Closed

Description

@akansc

Description

The GH-17645 seems to be a breaking change in comparison with other PHP versions.

Accessing link: https://hostname/check%2525.php

Earlier php 8.4 version (and older ones):

$_SERVER['HOME']	/var/www/html
$_SERVER['SCRIPT_NAME']	/check%25.php
$_SERVER['REQUEST_URI']	/check%2525.php
$_SERVER['SCRIPT_FILENAME']	/var/www/html/check%25.php

versus php 8.5:

$_SERVER['HOME']	/var/www/html
$_SERVER['SCRIPT_NAME']	/check%25.php
$_SERVER['REQUEST_URI']	/check%2525.php
$_SERVER['SCRIPT_FILENAME']	/var/www/html/check%.php

Now it gets doubledecoded.

Apache seem to handle as expected here:
...>SCRIPT_FILENAMEproxy:fcgi://localhost/var/www/html/check%25.php<...>QUERY_STRING\v\17REQUEST_URI/check%2525.php\v\rSCRIPT_NAME/check%25.php<...

More context:

{sa_family=AF_UNIX}, [112 => 2]) = 5
fcntl(5, F_GETFD)                       = 0
fcntl(5, F_SETFD, FD_CLOEXEC)           = 0
poll([{fd=5, events=POLLIN}], 1, 5000)  = 1 ([{fd=5, revents=POLLIN}])
times({tms_utime=0, tms_stime=0, tms_cutime=0, tms_cstime=0}) = 3055447099
read(5, "\1\1\0\1\0\10\0\0", 8)         = 8
read(5, "\0\1\0\0\0\0\0\0", 8)          = 8
read(5, "\1\4\0\1\5\2\0\0", 8)          = 8
read(5, "\t\33UNIQUE_IDaMPVIQE5oX3W9vLTiZZjnAAAyS8\22\0HTTP_AUTHORIZATION\5\2HTTPSon\v\rSSL_TLS_SNItest.srv.tld\5\2HTTP2on\6\3H2PUSHoff\7\3H2_PUSHoff\t\0H2_PUSHED\f\0H2_PUSHED_ON\f\1H2_STREAM_ID3\r\fH2_STREAM_TAG642972-180-3\21\1proxy-nokeepalive1\17FHTTP_USER_AGENTMozilla/5.0 (X11; Linux x86_64; rv:142.0) Gecko/20100101 Firefox/142.0\v?HTTP_ACCEPTtext/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\24\16HTTP_ACCEPT_LANGUAGEen-US,en;q=0.5\24\27HTTP_ACCEPT_ENCODINGgzip, deflate, br, zstd\v7HTTP_COOKIE__stripe_mid=896a9b1c-27db-4c99-84c0-7d824b516c1c64d868\36\1HTTP_UPGRADE_INSECURE_REQUESTS1\23\10HTTP_SEC_FETCH_DESTdocument\23\10HTTP_SEC_FETCH_MODEnavigate\23\4HTTP_SEC_FETCH_SITEnone\23\2HTTP_SEC_FETCH_USER?1\r\6HTTP_PRIORITYu=0, i\7\10HTTP_TEtrailers\t\rHTTP_HOSTtest.srv.tld\4<PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\20\0SERVER_SIGNATURE\17\10SERVER_SOFTWAREApache/2\v\rSERVER_NAMEtest.srv.tld\v\16SERVER_ADDRmo.di.fi.ed\v\3SERVER_PORT443\v\vREMOTE_ADDRmo.di.fi.ed\r\rDOCUMENT_ROOT/var/www/html\16\5REQUEST_SCHEMEhttps\16\0CONTEXT_PREFIX\25\rCONTEXT_DOCUMENT_ROOT/var/wwwhtml\f\23SERVER_ADMINwebmaster@localhost\0170SCRIPT_FILENAMEproxy:fcgi://localhost/var/www/html/check%25.php\v\5REMOTE_PORT43258\21\7GATEWAY_INTERFACECGI/1.1\17\10SERVER_PROTOCOLHTTP/2.0\16\3REQUEST_METHODGET\f\0QUERY_STRING\v\17REQUEST_URI/check%2525.php\v\rSCRIPT_NAME/check%25.php", 1282) = 1282
read(5, "\1\4\0\1\0\0\0\0", 8)          = 8
newfstatat(AT_FDCWD, "/var/www/html/check%.php", 0x7fffb1edb9c0, AT_SYMLINK_NOFOLLOW) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/var/www/html", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
newfstatat(AT_FDCWD, "/var/www", {st_mode=S_IFDIR|0711, st_size=4096, ...}, 0) = 0
newfstatat(AT_FDCWD, "/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
newfstatat(AT_FDCWD, "", 0x7fffb1edddc0, 0) = -1 ENOENT (No such file or directory)
[..]

According to CGI RFC, the SCRIPT_NAME is not url encoded:
https://datatracker.ietf.org/doc/html/rfc3875#section-4.1.13

And with the SCRIPT_FILENAME that we get the full path - gets url decoded by default with GH-17645 MR.

Apache had similar double decoding issues with their patches in 2.4.60 version, but they've fixed with 2.4.63
https://www.apachelounge.com/changelog-2.4.html

 *) mod_proxy_fcgi: Don't re-encode SCRIPT_FILENAME when set via SetHandler.
     PR 69203. [Yann Ylavic]

Food for thought:

The setting that brings back the old behavior:

fastcgi.script_path_encoded = on

Shouldn't the setting be the opposite? If the script path is encoded - then use decoding. If it's not url encoded - then decoding is not needed, thus off?

PHP Version

PHP 8.5.0beta2 (cli) (built: Sep 12 2025 11:40:47) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.5.0-dev, Copyright (c) Zend Technologies
    with Zend OPcache v8.5.0beta2, Copyright (c), by Zend Technologies

Operating System

Debian 12

Activity

  1. changed the title [-]Decode SCRIPT_PATH issue in php 8.5[/-] [+]Decode SCRIPT_FILENAME issue in php 8.5[/+] on Sep 16, 2025
  2. added a commit that references this issue on Oct 9, 2025
    9848f41
  3. bukka commented on Oct 9, 2025

    @bukka
    Member

    Looks like encoded files might be already used in many setups so the new default seems too risky. I just created #20114 to keep the 8.4 behaviour by default. So people that don't want to store files encoded can do it but they will need to enable the option (instead of forcing current users that saves is decoded to set it).

    The reason why I wanted to change default is to make it the same everywhere. The thing is that ProxyPass and ProxyPassMatch is the only setup that encodes the path. This is inconsistent even in Apache because SetHandler doesn't encode it (that's also how nginx behave). The pointed out break in Apache changed SetHandler in the way that encodes it as well but that was even a bigger break because more users use SetHandler and use decoded files in their FS. They needed to quickly change it back though (well they didn't mean to change it on purpose - it was side effect of one security fix really). It's all a bit of a mess but doing any changes to the default is just too risky.

    About fastcgi.script_path_encoded name, it is meant to point that script path on FS is encoded. It means that users saved file in encoded format. If it's the case, we don't need to do anything but if file is saved in decoded format, we need to decode it.

  4. added 2 commits that reference this issue on Oct 9, 2025
    74674c3
    d8a7018
  5. added a commit that references this issue on Oct 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions