Skip to content

security: fix RLIKE SQLi, XSS, integer casting, and dynamic dispatch#209

Open
somethingwithproof wants to merge 1 commit intoCacti:developfrom
somethingwithproof:fix/security-hardening
Open

security: fix RLIKE SQLi, XSS, integer casting, and dynamic dispatch#209
somethingwithproof wants to merge 1 commit intoCacti:developfrom
somethingwithproof:fix/security-hardening

Conversation

@somethingwithproof
Copy link
Copy Markdown

Summary

  • Fix RLIKE SQL injection in db_functions.php:113 by using db_qstr() instead of string concatenation. Guest-accessible when $guest_account=true.
  • Add html_escape() to 5 hidden input value attributes in monitor_controller.php to prevent reflected XSS
  • Add html_escape() to host description/hostname in email notification body (poller_functions.php) to prevent stored XSS via SNMP
  • Add (int) cast to crit and site request vars before SQL concatenation as defense-in-depth
  • Add allowlist validation (default, tree, site, template) for the grouping parameter before dynamic function dispatch

Test plan

  • Verify monitor dashboard loads with all grouping modes (default, tree, site, template)
  • Verify filter/search works on the monitor page
  • Verify email notifications render device names correctly
  • Verify hidden form fields preserve values during page interactions

Fix RLIKE SQL injection in db_functions.php by wrapping
get_request_var('rfilter') with db_qstr() instead of manual
string concatenation. This is guest-accessible when monitor.php
sets $guest_account=true.

Add html_escape() to all hidden input value attributes in
monitor_controller.php to prevent reflected XSS.

Add html_escape() to host description and hostname in email
notification body in poller_functions.php to prevent stored
XSS via rogue SNMP device responses.

Add (int) cast to integer request vars (crit, site) before
SQL concatenation in db_functions.php as defense-in-depth.

Add allowlist validation for the grouping parameter before
dynamic function dispatch in monitor_controller.php. Only
default, tree, site, and template are permitted.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Copilot AI review requested due to automatic review settings March 28, 2026 03:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the Monitor plugin against injection and XSS issues by sanitizing request-driven dynamic behavior, escaping untrusted output, and tightening SQL predicate construction in core query helpers.

Changes:

  • Escapes host description/hostname in reboot notification HTML output to prevent stored XSS in email clients.
  • Adds HTML escaping to hidden filter inputs to prevent reflected XSS via request parameters.
  • Mitigates SQL injection in RLIKE filtering and adds defense-in-depth integer casting for SQL concatenation; introduces grouping allowlist before dynamic render dispatch.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
poller_functions.php Escapes host fields in reboot notification HTML table output.
monitor_controller.php Adds grouping allowlist for dynamic renderer dispatch; escapes hidden filter input values.
db_functions.php Hardens SQL where/join construction (casts numeric filters; quotes RLIKE pattern via db_qstr).
Comments suppressed due to low confidence (1)

monitor_controller.php:115

  • After computing the sanitized $grouping, this block still checks get_request_var('grouping') when deciding which html_start_box() title to use. If the request contains an invalid grouping, rendering will use $grouping but the header/title logic will follow the raw value. Use $grouping consistently here (or set_request_var('grouping', $grouping)) to keep behavior coherent.
	$function          = 'render' . ucfirst($grouping);

	if (function_exists($function) && get_request_var('view') != 'list') {
		if (get_request_var('grouping') == 'default' || get_request_var('grouping') == 'site') {
			html_start_box(__('Monitored Devices', 'monitor'), '100%', true, 3, 'center', '');

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants