Skip to content
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@

locales/po/*.mo
vendor/
.omc/
2 changes: 0 additions & 2 deletions db_functions.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types = 1);

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down
2 changes: 0 additions & 2 deletions images/index.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types = 1);

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down
2 changes: 0 additions & 2 deletions locales/LC_MESSAGES/index.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types = 1);

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down
2 changes: 0 additions & 2 deletions monitor.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types = 1);

/*
Comment on lines 1 to 3
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down
14 changes: 6 additions & 8 deletions monitor_controller.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types = 1);

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down Expand Up @@ -450,7 +448,7 @@ function monitorRenderPrimaryFilterRow(array $dashboards, array $monitor_status,
}

print '<input type="button" value="' . (get_request_var('mute') == 'false' ? getMuteText() : getUnmuteText()) . '" id="sound" title="' . (get_request_var('mute') == 'false' ? __('%s Alert for downed Devices', getMuteText(), 'monitor') : __('%s Alerts for downed Devices', getUnmuteText(), 'monitor')) . '">' . PHP_EOL;
print '<input id="downhosts" type="hidden" value="' . get_request_var('downhosts') . '"><input id="mute" type="hidden" value="' . get_request_var('mute') . '">' . PHP_EOL;
print '<input id="downhosts" type="hidden" value="' . html_escape(get_request_var('downhosts')) . '"><input id="mute" type="hidden" value="' . html_escape(get_request_var('mute')) . '">' . PHP_EOL;
print '</span></td>';
}

Expand Down Expand Up @@ -548,23 +546,23 @@ function monitorRenderGroupingDropdowns(array $classes, array $criticalities, ar
*/
function monitorRenderHiddenFilterInputs(): void {
if (get_request_var('grouping') != 'tree') {
print '<td><input type="hidden" id="tree" value="' . get_request_var('tree') . '"></td>' . PHP_EOL;
print '<td><input type="hidden" id="tree" value="' . html_escape(get_request_var('tree')) . '"></td>' . PHP_EOL;
}

if (get_request_var('grouping') != 'site') {
print '<td><input type="hidden" id="site" value="' . get_request_var('site') . '"></td>' . PHP_EOL;
print '<td><input type="hidden" id="site" value="' . html_escape(get_request_var('site')) . '"></td>' . PHP_EOL;
}

if (get_request_var('grouping') != 'template') {
print '<td><input type="hidden" id="template" value="' . get_request_var('template') . '"></td>' . PHP_EOL;
print '<td><input type="hidden" id="template" value="' . html_escape(get_request_var('template')) . '"></td>' . PHP_EOL;
}

if (get_request_var('view') == 'list') {
print '<td><input type="hidden" id="size" value="' . get_request_var('size') . '"></td>' . PHP_EOL;
print '<td><input type="hidden" id="size" value="' . html_escape(get_request_var('size')) . '"></td>' . PHP_EOL;
}

if (get_request_var('view') != 'default') {
print '<td><input type="hidden" id="trim" value="' . get_request_var('trim') . '"></td>' . PHP_EOL;
print '<td><input type="hidden" id="trim" value="' . html_escape(get_request_var('trim')) . '"></td>' . PHP_EOL;
}
}

Expand Down
6 changes: 2 additions & 4 deletions monitor_render.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types = 1);

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down Expand Up @@ -962,7 +960,7 @@ function renderHeaderList(int $total_rows = 0, int $rows = 0): string {

ob_start();

$nav = html_nav_bar('monitor.php?rfilter=' . get_request_var('rfilter'), MAX_DISPLAY_PAGES, get_request_var('page'), $rows, $total_rows, 12, __('Devices'), 'page', 'main');
$nav = html_nav_bar('monitor.php?rfilter=' . rawurlencode(get_request_var('rfilter')), MAX_DISPLAY_PAGES, get_request_var('page'), $rows, $total_rows, 12, __('Devices'), 'page', 'main');

html_start_box(__('Monitored Devices', 'monitor'), '100%', false, 3, 'center', '');

Expand Down Expand Up @@ -1042,7 +1040,7 @@ function renderFooterList(int $total_rows, int $rows): string {
html_end_box(false);

if ($total_rows > 0) {
$nav = html_nav_bar('monitor.php?rfilter=' . get_request_var('rfilter'), MAX_DISPLAY_PAGES, get_request_var('page'), $rows, $total_rows, 12, __('Devices'), 'page', 'main');
$nav = html_nav_bar('monitor.php?rfilter=' . rawurlencode(get_request_var('rfilter')), MAX_DISPLAY_PAGES, get_request_var('page'), $rows, $total_rows, 12, __('Devices'), 'page', 'main');

print $nav;
}
Expand Down
2 changes: 0 additions & 2 deletions poller_functions.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types = 1);

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down
2 changes: 0 additions & 2 deletions poller_monitor.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

declare(strict_types = 1);

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down
1 change: 1 addition & 0 deletions setup.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down
41 changes: 41 additions & 0 deletions tests/Integration/test_monitor_request_output_wiring.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php
/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
+-------------------------------------------------------------------------+
| Cacti: The Complete RRDTool-based Graphing Solution |
+-------------------------------------------------------------------------+
*/

$checks = [
__DIR__ . '/../../monitor_controller.php' => [
"html_escape(get_request_var('downhosts'))",
"html_escape(get_request_var('mute'))",
"html_escape(get_request_var('tree'))",
"html_escape(get_request_var('site'))",
"html_escape(get_request_var('template'))",
"html_escape(get_request_var('size'))",
"html_escape(get_request_var('trim'))",
],
__DIR__ . '/../../monitor_render.php' => [
"rawurlencode(get_request_var('rfilter'))",
],
];
Comment on lines +10 to +23

foreach ($checks as $path => $patterns) {
$contents = file_get_contents($path);

if ($contents === false) {
fwrite(STDERR, "Unable to read {$path}\n");
exit(1);
}

foreach ($patterns as $pattern) {
if (strpos($contents, $pattern) === false) {
fwrite(STDERR, "Missing expected output hardening: {$pattern}\n");
exit(1);
}
}
}

print "OK\n";
40 changes: 40 additions & 0 deletions tests/e2e/test_monitor_no_raw_request_reuse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php
/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
+-------------------------------------------------------------------------+
| Cacti: The Complete RRDTool-based Graphing Solution |
+-------------------------------------------------------------------------+
*/

$checks = [
__DIR__ . '/../../monitor_controller.php' => [
"get_request_var('downhosts') . '\"><input id=\"mute\" type=\"hidden\" value=\"' . get_request_var('mute')",
"get_request_var('tree') . '\"></td>'",
"get_request_var('site') . '\"></td>'",
"get_request_var('template') . '\"></td>'",
"get_request_var('size') . '\"></td>'",
"get_request_var('trim') . '\"></td>'",
],
__DIR__ . '/../../monitor_render.php' => [
"monitor.php?rfilter=' . get_request_var('rfilter')",
],
];

foreach ($checks as $path => $patterns) {
$contents = file_get_contents($path);

if ($contents === false) {
fwrite(STDERR, "Unable to read {$path}\n");
exit(1);
}

foreach ($patterns as $pattern) {
if (strpos($contents, $pattern) !== false) {
fwrite(STDERR, "Raw request reuse remains: {$pattern}\n");
exit(1);
}
}
}

print "OK\n";
19 changes: 19 additions & 0 deletions tests/unit/test_request_output_escaping.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php
/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
+-------------------------------------------------------------------------+
| Cacti: The Complete RRDTool-based Graphing Solution |
+-------------------------------------------------------------------------+
*/

$payload = '" autofocus onfocus="alert(1)';
$escaped = htmlspecialchars($payload, ENT_QUOTES, 'UTF-8');

if (strpos($escaped, '"') === false && strpos($escaped, '&quot;') !== false) {
print "OK\n";
exit(0);
}
Comment on lines +10 to +16

fwrite(STDERR, "Expected request values to be escaped for hidden inputs\n");
exit(1);
1 change: 1 addition & 0 deletions themes/classic/index.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down
1 change: 1 addition & 0 deletions themes/dark/index.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down
1 change: 1 addition & 0 deletions themes/index.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down
1 change: 1 addition & 0 deletions themes/midwinter/index.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down
1 change: 1 addition & 0 deletions themes/modern/index.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down
1 change: 1 addition & 0 deletions themes/paper-plane/index.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down
1 change: 1 addition & 0 deletions themes/paw/index.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down
1 change: 1 addition & 0 deletions themes/sunrise/index.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
Expand Down