Skip to content

Commit 7537b5e

Browse files
bukkailuuu1994
authored andcommitted
GHSA-7qg2-v9fj-4mwv: [fpm] XSS within status endpoint
Fixes GHSA-7qg2-v9fj-4mwv Fixes CVE-2026-6735
1 parent eb9d772 commit 7537b5e

2 files changed

Lines changed: 78 additions & 4 deletions

File tree

sapi/fpm/fpm/fpm_status.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -522,8 +522,8 @@ int fpm_status_handle_request(void) /* {{{ */
522522
if (full_syntax) {
523523
unsigned int i;
524524
int first;
525-
zend_string *tmp_query_string;
526-
char *query_string;
525+
zend_string *tmp_query_string, *tmp_request_uri_string;
526+
char *query_string, *request_uri_string;
527527
struct timeval duration, now;
528528
float cpu;
529529

@@ -548,13 +548,36 @@ int fpm_status_handle_request(void) /* {{{ */
548548
}
549549
}
550550

551+
request_uri_string = NULL;
552+
tmp_request_uri_string = NULL;
553+
if (proc->request_uri[0] != '\0') {
554+
if (encode_html) {
555+
tmp_request_uri_string = php_escape_html_entities_ex(
556+
(const unsigned char *) proc->request_uri,
557+
strlen(proc->request_uri), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT,
558+
NULL, /* double_encode */ 1, /* quiet */ 0);
559+
request_uri_string = ZSTR_VAL(tmp_request_uri_string);
560+
} else if (encode_json) {
561+
tmp_request_uri_string = php_json_encode_string(proc->request_uri,
562+
strlen(proc->request_uri), PHP_JSON_INVALID_UTF8_IGNORE);
563+
request_uri_string = ZSTR_VAL(tmp_request_uri_string);
564+
/* remove quotes around the string */
565+
if (ZSTR_LEN(tmp_request_uri_string) >= 2) {
566+
request_uri_string[ZSTR_LEN(tmp_request_uri_string) - 1] = '\0';
567+
++request_uri_string;
568+
}
569+
} else {
570+
request_uri_string = proc->request_uri;
571+
}
572+
}
573+
551574
query_string = NULL;
552575
tmp_query_string = NULL;
553576
if (proc->query_string[0] != '\0') {
554577
if (encode_html) {
555578
tmp_query_string = php_escape_html_entities_ex(
556579
(const unsigned char *) proc->query_string,
557-
strlen(proc->query_string), 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT,
580+
strlen(proc->query_string), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT,
558581
NULL, /* double_encode */ 1, /* quiet */ 0);
559582
} else if (encode_json) {
560583
tmp_query_string = php_json_encode_string(proc->query_string,
@@ -593,7 +616,7 @@ int fpm_status_handle_request(void) /* {{{ */
593616
proc->requests,
594617
(unsigned long) (duration.tv_sec * 1000000UL + duration.tv_usec),
595618
proc->request_method[0] != '\0' ? proc->request_method : "-",
596-
proc->request_uri[0] != '\0' ? proc->request_uri : "-",
619+
request_uri_string ? request_uri_string : "-",
597620
query_string ? "?" : "",
598621
query_string ? query_string : "",
599622
proc->content_length,
@@ -604,6 +627,9 @@ int fpm_status_handle_request(void) /* {{{ */
604627
PUTS(buffer);
605628
efree(buffer);
606629

630+
if (tmp_request_uri_string) {
631+
zend_string_free(tmp_request_uri_string);
632+
}
607633
if (tmp_query_string) {
608634
zend_string_free(tmp_query_string);
609635
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
--TEST--
2+
FPM: GHSA-7qg2-v9fj-4mwv - status xss
3+
--SKIPIF--
4+
<?php include "skipif.inc"; ?>
5+
--FILE--
6+
<?php
7+
8+
require_once "tester.inc";
9+
10+
$cfg = <<<EOT
11+
[global]
12+
error_log = {{FILE:LOG}}
13+
[unconfined]
14+
listen = {{ADDR}}
15+
pm = static
16+
pm.max_children = 2
17+
pm.status_path = /status
18+
catch_workers_output = yes
19+
EOT;
20+
21+
$code = <<<EOT
22+
<?php
23+
usleep(200000);
24+
EOT;
25+
26+
$tester = new FPM\Tester($cfg, $code);
27+
$tester->start();
28+
$tester->expectLogStartNotices();
29+
$responses = $tester
30+
->multiRequest([
31+
['uri' => '/<script>alert(1)</script>', 'query' => '<script>alert(2)</script>'],
32+
['uri' => '/status', 'query' => 'full&html', 'delay' => 100000],
33+
]);
34+
var_dump(strpos($responses[1]->getBody(), '<script>'));
35+
$tester->terminate();
36+
$tester->expectLogTerminatingNotices();
37+
$tester->close();
38+
39+
?>
40+
Done
41+
--EXPECT--
42+
bool(false)
43+
Done
44+
--CLEAN--
45+
<?php
46+
require_once "tester.inc";
47+
FPM\Tester::clean();
48+
?>

0 commit comments

Comments
 (0)