From ecca35277dbd35f0ecfd7bebdb36610d16c4a272 Mon Sep 17 00:00:00 2001 From: Thomas Vincent Date: Wed, 8 Apr 2026 17:32:46 -0700 Subject: [PATCH 1/2] fix(hardening): migrate RLIKE to db_qstr for SQL injection prevention Wrap all get_request_var('rfilter') values with db_qstr() in RLIKE SQL clauses across thold.php, thold_graph.php, and notify_lists.php. 10 sites total. RLIKE accepts regex from rfilter which passes FILTER_VALIDATE_IS_REGEX but is not SQL-safe. A single quote breaks the SQL string context. Closes #761, #763 Signed-off-by: Thomas Vincent --- notify_lists.php | 10 +++++----- thold.php | 2 +- thold_graph.php | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/notify_lists.php b/notify_lists.php index 016e01d..058d17d 100644 --- a/notify_lists.php +++ b/notify_lists.php @@ -1399,7 +1399,7 @@ function tholds($header_label) { } if (strlen(get_request_var('rfilter'))) { - $sql_where .= (!strlen($sql_where) ? '' : ' AND ') . "td.name_cache RLIKE '" . get_request_var('rfilter') . "'"; + $sql_where .= (!strlen($sql_where) ? '' : ' AND ') . "td.name_cache RLIKE " . db_qstr(get_request_var('rfilter')) . ""; } if ($statefilter != '') { @@ -1739,7 +1739,7 @@ function templates($header_label) { } if (strlen(get_request_var('rfilter'))) { - $sql_where .= (!strlen($sql_where) ? 'WHERE ' : ' AND ') . "thold_template.name RLIKE '" . get_request_var('rfilter') . "'"; + $sql_where .= (!strlen($sql_where) ? 'WHERE ' : ' AND ') . "thold_template.name RLIKE " . db_qstr(get_request_var('rfilter')) . ""; } $sql = "SELECT * @@ -2144,9 +2144,9 @@ function clearFilter() { // form the 'where' clause for our main sql query if (strlen(get_request_var('rfilter'))) { $sql_where = "WHERE ( - name RLIKE '" . get_request_var('rfilter') . "' - OR description RLIKE '" . get_request_var('rfilter') . "' - OR emails RLIKE '" . get_request_var('rfilter') . "')"; + name RLIKE " . db_qstr(get_request_var('rfilter')) . " + OR description RLIKE " . db_qstr(get_request_var('rfilter')) . " + OR emails RLIKE " . db_qstr(get_request_var('rfilter')) . ")"; } else { $sql_where = ''; } diff --git a/thold.php b/thold.php index 0bf86f4..06be262 100644 --- a/thold.php +++ b/thold.php @@ -614,7 +614,7 @@ function list_tholds() { } if (get_request_var('rfilter') != '') { - $sql_where .= ($sql_where == '' ? '(' : ' AND ') . " td.name_cache RLIKE '" . get_request_var('rfilter') . "'"; + $sql_where .= ($sql_where == '' ? '(' : ' AND ') . " td.name_cache RLIKE " . db_qstr(get_request_var('rfilter')) . ""; } if ($statefilter != '') { diff --git a/thold_graph.php b/thold_graph.php index 619f2ee..a085a6a 100644 --- a/thold_graph.php +++ b/thold_graph.php @@ -404,7 +404,7 @@ function tholds() { $statefilter = thold_get_state_filter(get_request_var('state')); if (get_request_var('rfilter') != '') { - $sql_where .= ($sql_where == '' ? '(' : ' AND ') . " td.name_cache RLIKE '" . get_request_var('rfilter') . "'"; + $sql_where .= ($sql_where == '' ? '(' : ' AND ') . " td.name_cache RLIKE " . db_qstr(get_request_var('rfilter')) . ""; } if (get_request_var('data_template_id') != '-1') { @@ -937,8 +937,8 @@ function hosts() { if (get_request_var('rfilter') != '') { $sql_where .= " (h.deleted = '' - AND (h.hostname RLIKE '" . get_request_var('rfilter') . "' - OR h.description RLIKE '" . get_request_var('rfilter') . "')"; + AND (h.hostname RLIKE " . db_qstr(get_request_var('rfilter')) . " + OR h.description RLIKE " . db_qstr(get_request_var('rfilter')) . ")"; } if (get_request_var('host_status') == '-1') { @@ -1395,7 +1395,7 @@ function thold_export_log() { } if (get_request_var('rfilter') != '') { - $sql_where .= ($sql_where == '' ? '' : ' AND') . " tl.description RLIKE '" . get_request_var('rfilter') . "'"; + $sql_where .= ($sql_where == '' ? '' : ' AND') . " tl.description RLIKE " . db_qstr(get_request_var('rfilter')) . ""; } $sql_order = ''; @@ -1490,7 +1490,7 @@ function thold_show_log() { } if (get_request_var('rfilter') != '') { - $sql_where .= ($sql_where == '' ? '' : ' AND') . " tl.description RLIKE '" . get_request_var('rfilter') . "'"; + $sql_where .= ($sql_where == '' ? '' : ' AND') . " tl.description RLIKE " . db_qstr(get_request_var('rfilter')) . ""; } $sql_order = get_order_string(); From 5fda6926b868a4f77aaf6e1302d84571068b3c3f Mon Sep 17 00:00:00 2001 From: Thomas Vincent Date: Wed, 8 Apr 2026 17:47:46 -0700 Subject: [PATCH 2/2] fix(thold): correct trigger_cmd variable references for low/normal states thold_set_environ() for the breach_down path used trigger_cmd_high instead of trigger_cmd_low, and the breach_norm path also used trigger_cmd_high instead of trigger_cmd_norm. This caused low and normal threshold trigger commands to receive the high threshold command's environment variables. Closes #760 Signed-off-by: Thomas Vincent --- notify_lists.php | 28 +++++++++++++++------------- thold_functions.php | 4 ++-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/notify_lists.php b/notify_lists.php index 058d17d..40085db 100644 --- a/notify_lists.php +++ b/notify_lists.php @@ -1730,16 +1730,18 @@ function templates($header_label) { $rows = get_request_var('rows'); } - $sql_where = ''; - $sql_order = get_order_string(); - $sql_limit = ' LIMIT ' . ($rows * (intval(get_request_var('page')) - 1)) . ',' . $rows; + $sql_where = ''; + $sql_params = array(); + $sql_order = get_order_string(); + $sql_limit = ' LIMIT ' . ($rows * (intval(get_request_var('page')) - 1)) . ',' . $rows; if (get_request_var('associated') == 'true') { $sql_where .= (!strlen($sql_where) ? 'WHERE ' : ' AND ') . '(notify_warning=' . get_request_var('id') . ' OR notify_alert=' . get_request_var('id') . ')'; } if (strlen(get_request_var('rfilter'))) { - $sql_where .= (!strlen($sql_where) ? 'WHERE ' : ' AND ') . "thold_template.name RLIKE " . db_qstr(get_request_var('rfilter')) . ""; + $sql_where .= (!strlen($sql_where) ? 'WHERE ' : ' AND ') . 'thold_template.name RLIKE ?'; + $sql_params[] = get_request_var('rfilter'); } $sql = "SELECT * @@ -1748,7 +1750,7 @@ function templates($header_label) { $sql_order $sql_limit"; - $result = db_fetch_assoc($sql); + $result = db_fetch_assoc_prepared($sql, $sql_params); html_start_box(__('Associated Templates', 'thold') . ' ' . html_escape($header_label), '100%', false, '3', 'center', ''); ?> @@ -2142,24 +2144,24 @@ function clearFilter() { html_end_box(); // form the 'where' clause for our main sql query + $sql_params = array(); + if (strlen(get_request_var('rfilter'))) { - $sql_where = "WHERE ( - name RLIKE " . db_qstr(get_request_var('rfilter')) . " - OR description RLIKE " . db_qstr(get_request_var('rfilter')) . " - OR emails RLIKE " . db_qstr(get_request_var('rfilter')) . ")"; + $sql_where = 'WHERE (name RLIKE ? OR description RLIKE ? OR emails RLIKE ?)'; + $sql_params = array(get_request_var('rfilter'), get_request_var('rfilter'), get_request_var('rfilter')); } else { $sql_where = ''; } - $total_rows = db_fetch_cell("SELECT + $total_rows = db_fetch_cell_prepared("SELECT COUNT(*) FROM plugin_notification_lists - $sql_where"); + $sql_where", $sql_params); $sql_order = get_order_string(); $sql_limit = ' LIMIT ' . ($rows * (intval(get_request_var('page')) - 1)) . ',' . $rows; - $lists = db_fetch_assoc("SELECT id, name, enabled, description, emails, + $lists = db_fetch_assoc_prepared("SELECT id, name, enabled, description, emails, (SELECT COUNT(id) FROM thold_data WHERE notify_alert = nl.id) as thold_alerts, (SELECT COUNT(id) FROM thold_data WHERE notify_warning = nl.id) as thold_warnings, (SELECT COUNT(id) FROM thold_template WHERE notify_alert = nl.id) as template_alerts, @@ -2168,7 +2170,7 @@ function clearFilter() { FROM plugin_notification_lists nl $sql_where $sql_order - $sql_limit"); + $sql_limit", $sql_params); $nav = html_nav_bar('notify_lists.php', MAX_DISPLAY_PAGES, get_request_var('page'), $rows, $total_rows, 10, __('Lists', 'thold'), 'page', 'main'); diff --git a/thold_functions.php b/thold_functions.php index fc100b8..9c3a72a 100644 --- a/thold_functions.php +++ b/thold_functions.php @@ -4009,7 +4009,7 @@ function thold_command_execution(&$thold_data, &$h, $breach_up, $breach_down, $b $cmd = thold_replace_threshold_tags($thold_data['trigger_cmd_low'], $thold_data, $h, $thold_data['lastread'], $thold_data['local_graph_id'], $data_source_name); $cmd = thold_expand_string($thold_data, $cmd); - $environment = thold_set_environ($thold_data['trigger_cmd_high'], $thold_data, $h, $thold_data['lastread'], $thold_data['local_graph_id'], $data_source_name); + $environment = thold_set_environ($thold_data['trigger_cmd_low'], $thold_data, $h, $thold_data['lastread'], $thold_data['local_graph_id'], $data_source_name); if ($queue == 'on') { $data = [ @@ -4028,7 +4028,7 @@ function thold_command_execution(&$thold_data, &$h, $breach_up, $breach_down, $b $cmd = thold_replace_threshold_tags($thold_data['trigger_cmd_norm'], $thold_data, $h, $thold_data['lastread'], $thold_data['local_graph_id'], $data_source_name); $cmd = thold_expand_string($thold_data, $cmd); - $environment = thold_set_environ($thold_data['trigger_cmd_high'], $thold_data, $h, $thold_data['lastread'], $thold_data['local_graph_id'], $data_source_name); + $environment = thold_set_environ($thold_data['trigger_cmd_norm'], $thold_data, $h, $thold_data['lastread'], $thold_data['local_graph_id'], $data_source_name); if ($queue == 'on') { $data = [