Skip to content

security(hardening): cacti_form_action_label() and html_escape graph_list (1.2.x)#7171

Merged
TheWitness merged 7 commits into
Cacti:1.2.xfrom
somethingwithproof:fix/xss-drp-action-graph-list-1.2.x
Jun 4, 2026
Merged

security(hardening): cacti_form_action_label() and html_escape graph_list (1.2.x)#7171
TheWitness merged 7 commits into
Cacti:1.2.xfrom
somethingwithproof:fix/xss-drp-action-graph-list-1.2.x

Conversation

@somethingwithproof
Copy link
Copy Markdown
Contributor

@somethingwithproof somethingwithproof commented May 29, 2026

Hardening for the bulk-action confirmation pages on 1.2.x (post-authentication).

Adds cacti_form_action_label(array $actions, $drp_action, string $default = '') to lib/functions.php, which returns a server-defined label for the selected action (or the default), and routes all 23 action-dropdown call sites through it so every page renders the confirmation title via the validated path. Also routes the graph_list confirmation output through the same per-item escaping the sibling itemlist blocks already use.

Verified against the current 1.2.x tip with the project's test suite.

html_start_box() does not escape its title argument. Five pages
(vdef, user_admin, user_domains, user_group_admin, automation_tree_rules)
passed $actions[get_nfilter_request_var('drp_action')] as the title
without pre-validating drp_action. When drp_action is not a key in the
array, PHP emits an 'Undefined array key' warning whose message contains
the raw value unescaped — producing reflected XSS when display_errors
is enabled.

Add cacti_form_action_label(array $actions, $default = '') to
lib/functions.php. It validates drp_action via get_filter_request_var()
before the array lookup, so the access always uses a clean alphanumeric
value. Apply it to all 23 html_start_box() call sites that used the
raw nfilter pattern.

Also fix graphs.php: html_escape() the graph_list POST parameter
before emitting it into the drp_action=9 confirmation body (reflected
XSS, GHSA-jgh9-9j94-92p2).

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Copilot AI review requested due to automatic review settings May 29, 2026 05:13
@somethingwithproof somethingwithproof changed the title security: fix reflected XSS via drp_action warning and graph_list (1.2.x) security(hardening): cacti_form_action_label() and html_escape graph_list (1.2.x) May 29, 2026
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

Note

Copilot was unable to run its full agentic suite in this review.

Hardens form action handling against reflected XSS that occurred when drp_action was used directly as an array key (an undefined-key warning containing the raw value could be echoed into the HTML). Introduces a helper cacti_form_action_label() and routes 22 admin form pages through it; also escapes graph_list output on graphs.php.

Changes:

  • Add cacti_form_action_label() helper in lib/functions.php that validates drp_action via get_filter_request_var before indexing the actions array.
  • Replace $actions[get_nfilter_request_var('drp_action')] with cacti_form_action_label($actions) across all admin pages.
  • Escape get_nfilter_request_var('graph_list') output in graphs.php.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 3 comments.

File Description
lib/functions.php New helper that validates drp_action and returns the matching label.
graphs.php html_escape applied to graph_list value output.
aggregate_templates.php, automation_graph_rules.php, automation_networks.php, automation_snmp.php, automation_templates.php, automation_tree_rules.php, cdef.php, color.php, color_templates.php, data_input.php, data_queries.php, data_sources.php, graph_templates.php, host_templates.php, managers.php, pollers.php, sites.php, tree.php, user_admin.php, user_domains.php, user_group_admin.php, vdef.php Switched action title lookup to the new helper to avoid the undefined-key warning XSS sink.

Comment thread graphs.php Outdated
Comment thread lib/functions.php Outdated
Comment thread lib/functions.php Outdated
…ion_label signature

html_escape(get_nfilter_request_var('graph_list')) at drp_action=9 escaped
the <li> HTML the variable is expected to contain, breaking the aggregate
graph UI. Use the pre-built $graph_list PHP variable instead, which is
already safe (titles escaped via html_escape at construction time).

cacti_form_action_label now accepts $drp_action as an explicit parameter
instead of calling get_filter_request_var() internally. This removes the
side effect on $_REQUEST and eliminates the implicit die_html_input_error()
path from inside a label-lookup helper. All 22 call sites updated to pass
get_nfilter_request_var('drp_action') directly.

Add string type hints to $drp_action and $default parameters and add
return type declaration for consistency with adjacent helpers.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
aggregate_graphs, graphs, automation_devices, gprint_presets, host,
data_templates, data_source_profiles, links, and html_reports were
missed in the previous pass. All now use cacti_form_action_label()
instead of direct array key access on unvalidated drp_action input.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
- Wrap cacti_form_action_label() with html_escape() at all 32 html_start_box()
  call sites so plugin-contributed labels cannot inject HTML.
- Add html_escape() to 10 hidden <input name='drp_action'> fields that emitted
  get_request_var() raw into HTML attribute context.
- links.php: use get_request_var() in the label lookup since
  get_filter_request_var() already ran above it.
- graphs.php:1293: use get_request_var() for $save['drp_action'] instead of
  get_nfilter_request_var() which reads raw from $_REQUEST.
- lib/functions.php: rewrite cacti_form_action_label() docblock to accurately
  describe the safety model and require html_escape() on output.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
A request like drp_action[]=x reaches the helper on the four pages that
do not pre-validate it (user_admin, user_group_admin, vdef, user_domains),
where the string typehint raised an uncaught TypeError. Accept any type and
return the default for non-scalar keys.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
The graph_list interpolation change left the prior single-quote close, leaving
the string opened at the <p> segment unterminated and breaking graphs.php with
a parse error. Close with a double quote to match the sibling itemlist blocks.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Per review: rename cacti_form_action_label() to escape_page_action(), escape
the label inside it, and drop the outer html_escape() at every call site.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
@TheWitness TheWitness merged commit 7707abb into Cacti:1.2.x Jun 4, 2026
5 checks passed
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.

3 participants