Skip to content

Commit 13e72d1

Browse files
bukkasaundefined
authored andcommitted
GHSA-7qg2-v9fj-4mwv: [fpm] XSS within status endpoint
Fixes GHSA-7qg2-v9fj-4mwv Fixes CVE-2026-6735
1 parent 9992b81 commit 13e72d1

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
@@ -528,8 +528,8 @@ int fpm_status_handle_request(void) /* {{{ */
528528
if (full_syntax) {
529529
unsigned int i;
530530
int first;
531-
zend_string *tmp_query_string;
532-
char *query_string;
531+
zend_string *tmp_query_string, *tmp_request_uri_string;
532+
char *query_string, *request_uri_string;
533533
struct timeval duration, now;
534534
float cpu;
535535

@@ -554,13 +554,36 @@ int fpm_status_handle_request(void) /* {{{ */
554554
}
555555
}
556556

557+
request_uri_string = NULL;
558+
tmp_request_uri_string = NULL;
559+
if (proc->request_uri[0] != '\0') {
560+
if (encode_html) {
561+
tmp_request_uri_string = php_escape_html_entities_ex(
562+
(const unsigned char *) proc->request_uri,
563+
strlen(proc->request_uri), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT,
564+
NULL, /* double_encode */ 1, /* quiet */ 0);
565+
request_uri_string = ZSTR_VAL(tmp_request_uri_string);
566+
} else if (encode_json) {
567+
tmp_request_uri_string = php_json_encode_string(proc->request_uri,
568+
strlen(proc->request_uri), PHP_JSON_INVALID_UTF8_IGNORE);
569+
request_uri_string = ZSTR_VAL(tmp_request_uri_string);
570+
/* remove quotes around the string */
571+
if (ZSTR_LEN(tmp_request_uri_string) >= 2) {
572+
request_uri_string[ZSTR_LEN(tmp_request_uri_string) - 1] = '\0';
573+
++request_uri_string;
574+
}
575+
} else {
576+
request_uri_string = proc->request_uri;
577+
}
578+
}
579+
557580
query_string = NULL;
558581
tmp_query_string = NULL;
559582
if (proc->query_string[0] != '\0') {
560583
if (encode_html) {
561584
tmp_query_string = php_escape_html_entities_ex(
562585
(const unsigned char *) proc->query_string,
563-
strlen(proc->query_string), 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT,
586+
strlen(proc->query_string), 1, ENT_DISALLOWED | ENT_HTML_DOC_XML1 | ENT_COMPAT,
564587
NULL, /* double_encode */ 1, /* quiet */ 0);
565588
} else if (encode_json) {
566589
tmp_query_string = php_json_encode_string(proc->query_string,
@@ -599,7 +622,7 @@ int fpm_status_handle_request(void) /* {{{ */
599622
proc->requests,
600623
duration.tv_sec * 1000000UL + duration.tv_usec,
601624
proc->request_method[0] != '\0' ? proc->request_method : "-",
602-
proc->request_uri[0] != '\0' ? proc->request_uri : "-",
625+
request_uri_string ? request_uri_string : "-",
603626
query_string ? "?" : "",
604627
query_string ? query_string : "",
605628
proc->content_length,
@@ -610,6 +633,9 @@ int fpm_status_handle_request(void) /* {{{ */
610633
PUTS(buffer);
611634
efree(buffer);
612635

636+
if (tmp_request_uri_string) {
637+
zend_string_free(tmp_request_uri_string);
638+
}
613639
if (tmp_query_string) {
614640
zend_string_free(tmp_query_string);
615641
}
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)