From 8e0efa0f20484c8bbfdb8671d61b232b70e2bd0a Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 3 May 2026 20:01:41 +0200 Subject: [PATCH 5/6] GHSA-7qg2-v9fj-4mwv: [fpm] XSS within status endpoint Fixes GHSA-7qg2-v9fj-4mwv Fixes CVE-2026-6735 (cherry picked from commit 99a5ad7441de9914246c7863adb6997396008b9d) (cherry picked from commit cc2960e782eb5cc262d7bd572a7d18979a811954) (cherry picked from commit 62daef7b73108ceda2545862cde0673f252ba2d2) (cherry picked from commit aeaf48ca0bceba42b9595dff30d9e96029c54613) backport some new FPM tester features (cherry picked from commit 8b1746466f9fcf248f9879fabfa356106d365da0) --- sapi/fpm/fpm/fpm_status.c | 28 ++++- .../tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt | 48 ++++++++ sapi/fpm/tests/tester.inc | 111 ++++++++++++++++-- 3 files changed, 172 insertions(+), 15 deletions(-) create mode 100644 sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt diff --git a/sapi/fpm/fpm/fpm_status.c b/sapi/fpm/fpm/fpm_status.c index 45852a5b39..2c0d770329 100644 --- a/sapi/fpm/fpm/fpm_status.c +++ b/sapi/fpm/fpm/fpm_status.c @@ -387,8 +387,8 @@ int fpm_status_handle_request(void) /* {{{ */ if (full_syntax) { unsigned int i; int first; - zend_string *tmp_query_string; - char *query_string; + zend_string *tmp_query_string, *tmp_request_uri_string; + char *query_string, *request_uri_string; struct timeval duration, now; #ifdef HAVE_FPM_LQ float cpu; @@ -415,13 +415,30 @@ int fpm_status_handle_request(void) /* {{{ */ } } + request_uri_string = NULL; + tmp_request_uri_string = NULL; + if (proc.request_uri[0] != '\0') { + if (encode) { + tmp_request_uri_string = php_escape_html_entities_ex( + (unsigned char*)proc.request_uri, + strlen(proc.request_uri), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT, + NULL, /* double_encode */ 1); + request_uri_string = ZSTR_VAL(tmp_request_uri_string); + } else { + request_uri_string = proc.request_uri; + } + } + query_string = NULL; tmp_query_string = NULL; if (proc.query_string[0] != '\0') { if (!encode) { query_string = proc.query_string; } else { - tmp_query_string = php_escape_html_entities_ex((unsigned char *)proc.query_string, strlen(proc.query_string), 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT, NULL, 1); + tmp_query_string = php_escape_html_entities_ex( + (unsigned char*)proc.query_string, + strlen(proc.query_string), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT, + NULL, /* double_encode */ 1); query_string = ZSTR_VAL(tmp_query_string); } } @@ -449,7 +466,7 @@ int fpm_status_handle_request(void) /* {{{ */ proc.requests, duration.tv_sec * 1000000UL + duration.tv_usec, proc.request_method[0] != '\0' ? proc.request_method : "-", - proc.request_uri[0] != '\0' ? proc.request_uri : "-", + request_uri_string ? request_uri_string : "-", query_string ? "?" : "", query_string ? query_string : "", proc.content_length, @@ -462,6 +479,9 @@ int fpm_status_handle_request(void) /* {{{ */ PUTS(buffer); efree(buffer); + if (tmp_request_uri_string) { + zend_string_free(tmp_request_uri_string); + } if (tmp_query_string) { zend_string_free(tmp_query_string); } diff --git a/sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt b/sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt new file mode 100644 index 0000000000..475bc130a4 --- /dev/null +++ b/sapi/fpm/tests/ghsa-7qg2-v9fj-4mwv-status-xss.phpt @@ -0,0 +1,48 @@ +--TEST-- +FPM: GHSA-7qg2-v9fj-4mwv - status xss +--SKIPIF-- + +--FILE-- +start(); +$tester->expectLogStartNotices(); +$responses = $tester + ->multiRequest([ + ['uri' => '/', 'query' => ''], + ['uri' => '/status', 'query' => 'full&html', 'delay' => 100000], + ]); +var_dump(strpos($responses[1]->getBody(), '