From a8489535c528609b2d00e3e5b9ed6bb29879ba67 Mon Sep 17 00:00:00 2001 From: Thomas Vincent Date: Fri, 6 Mar 2026 13:53:58 -0800 Subject: [PATCH 1/4] hardening: escape syslog output surfaces Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Thomas Vincent --- js/functions.js | 6 +++++- syslog.php | 17 ++++++++--------- syslog_removal.php | 3 +-- syslog_reports.php | 5 ++--- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/js/functions.js b/js/functions.js index a96d47d..dd6d756 100644 --- a/js/functions.js +++ b/js/functions.js @@ -220,7 +220,11 @@ function initSyslogMain(config) { $.each(data, function(index, hostData) { if ($('#host option[value="'+index+'"]').length == 0) { - $('#host').append(''); + var option = $(''; + print ''; } } ?> @@ -541,7 +541,7 @@ function syslog_stats_filter() { if (cacti_sizeof($facilities)) { foreach ($facilities as $r) { - print '\n"; + print '\n"; } } ?> @@ -561,7 +561,7 @@ function syslog_stats_filter() { if (cacti_sizeof($priorities)) { foreach ($priorities as $r) { - print '\n"; + print '\n"; } } ?> @@ -1349,7 +1349,7 @@ function syslog_filter($sql_where, $tab) { } } print '>'; - print $host['host'] . ''; + print html_escape($host['host']) . ''; } } ?> @@ -2037,4 +2037,3 @@ function syslog_form_callback($form_name, $classic_sql, $column_display, $column ' . $removal_info . ''; + $removal_list .= '
  • ' . html_escape($removal_info) . '
  • '; $removal_array[] = $matches[1]; } } @@ -810,4 +810,3 @@ function removal_import() { header('Location: syslog_removal.php'); } - diff --git a/syslog_reports.php b/syslog_reports.php index f0caec2..1decde4 100644 --- a/syslog_reports.php +++ b/syslog_reports.php @@ -157,7 +157,7 @@ function form_actions() { FROM `' . $syslogdb_default . '`.`syslog_reports` WHERE id=' . $matches[1]); - $report_list .= '
  • ' . $report_info . '
  • '; + $report_list .= '
  • ' . html_escape($report_info) . '
  • '; $report_array[] = $matches[1]; } } @@ -725,7 +725,7 @@ function syslog_report() { form_selectable_cell(filter_value(title_trim($report['name'], read_config_option('max_title_length')), get_request_var('filter'), $config['url_path'] . 'plugins/syslog/syslog_reports.php?action=edit&id=' . $report['id']), $report['id']); form_selectable_cell((($report['enabled'] == 'on') ? __('Yes', 'syslog'):__('No', 'syslog')), $report['id']); form_selectable_cell($message_types[$report['type']], $report['id']); - form_selectable_cell($report['message'], $report['id']); + form_selectable_ecell($report['message'], $report['id']); form_selectable_cell($syslog_freqs[$report['timespan']], $report['id']); form_selectable_cell($syslog_times[$report['timepart']], $report['id']); form_selectable_cell(($report['lastsent'] == 0 ? __('Never', 'syslog'): date('Y-m-d H:i:s', $report['lastsent'])), $report['id']); @@ -872,4 +872,3 @@ function report_import() { header('Location: syslog_reports.php'); } - From b31203be6dac7ac7bc9f793ac13d11353d0c3445 Mon Sep 17 00:00:00 2001 From: Thomas Vincent Date: Fri, 6 Mar 2026 14:51:36 -0800 Subject: [PATCH 2/4] test: add regression checks for XSS hardening Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Thomas Vincent --- .github/workflows/plugin-ci-workflow.yml | 10 +++++ CHANGELOG.md | 1 + tests/regression/issue252_xss_output_test.php | 45 +++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 tests/regression/issue252_xss_output_test.php diff --git a/.github/workflows/plugin-ci-workflow.yml b/.github/workflows/plugin-ci-workflow.yml index 7580ee1..76612ac 100644 --- a/.github/workflows/plugin-ci-workflow.yml +++ b/.github/workflows/plugin-ci-workflow.yml @@ -187,6 +187,16 @@ jobs: echo "Syntax errors found!" exit 1 fi + + - name: Run Plugin Regression Tests + run: | + cd ${{ github.workspace }}/cacti/plugins/syslog + if [ -d tests/regression ]; then + for test in tests/regression/*.php; do + [ -f "$test" ] || continue + php "$test" + done + fi - name: Run Cacti Poller diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f1e7f2..77cfb0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ --- develop --- +* issue#252: Escape syslog output surfaces and harden host option rendering * issue: Making changes to support Cacti 1.3 * issue: Don't use MyISAM for non-analytical tables * issue: The install advisor for Syslog was broken in current Cacti releases diff --git a/tests/regression/issue252_xss_output_test.php b/tests/regression/issue252_xss_output_test.php new file mode 100644 index 0000000..5833bc8 --- /dev/null +++ b/tests/regression/issue252_xss_output_test.php @@ -0,0 +1,45 @@ +')") === false || + strpos($functionsJs, ".text(hostData.host);") === false || + strpos($functionsJs, "$('#host').append(option);") === false) { + fwrite(STDERR, "Expected DOM-safe host option rendering in js/functions.js.\n"); + exit(1); +} + +if (strpos($functionsJs, "$('#host').append('');") !== false) { + fwrite(STDERR, "Legacy unsafe host option HTML concatenation still present.\n"); + exit(1); +} + +echo "issue252_xss_output_test passed\n"; From e7dba8e09b692298f47662b101fb94c541be4966 Mon Sep 17 00:00:00 2001 From: Thomas Vincent Date: Sat, 7 Mar 2026 17:34:52 -0800 Subject: [PATCH 3/4] fix: correct form_selectable_ecell typo to form_selectable_cell form_selectable_ecell() does not exist in Cacti core. The correct function is form_selectable_cell(). The typo would cause a PHP fatal error on every row rendered in the report listing page. Signed-off-by: Thomas Vincent --- syslog_reports.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syslog_reports.php b/syslog_reports.php index 1decde4..bad4022 100644 --- a/syslog_reports.php +++ b/syslog_reports.php @@ -725,7 +725,7 @@ function syslog_report() { form_selectable_cell(filter_value(title_trim($report['name'], read_config_option('max_title_length')), get_request_var('filter'), $config['url_path'] . 'plugins/syslog/syslog_reports.php?action=edit&id=' . $report['id']), $report['id']); form_selectable_cell((($report['enabled'] == 'on') ? __('Yes', 'syslog'):__('No', 'syslog')), $report['id']); form_selectable_cell($message_types[$report['type']], $report['id']); - form_selectable_ecell($report['message'], $report['id']); + form_selectable_cell($report['message'], $report['id']); form_selectable_cell($syslog_freqs[$report['timespan']], $report['id']); form_selectable_cell($syslog_times[$report['timepart']], $report['id']); form_selectable_cell(($report['lastsent'] == 0 ? __('Never', 'syslog'): date('Y-m-d H:i:s', $report['lastsent'])), $report['id']); From 34c710438d6f05b4174c8fcb658fa3e18b6728cf Mon Sep 17 00:00:00 2001 From: Thomas Vincent Date: Sun, 8 Mar 2026 03:55:28 -0700 Subject: [PATCH 4/4] chore: add CHANGELOG entry for develop Signed-off-by: Thomas Vincent --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77cfb0a..7625bff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ --- develop --- -* issue#252: Escape syslog output surfaces and harden host option rendering +* issue#252: Harden unescaped syslog UI output paths and remove unsafe HTML string insertion * issue: Making changes to support Cacti 1.3 * issue: Don't use MyISAM for non-analytical tables * issue: The install advisor for Syslog was broken in current Cacti releases