Skip to content

fix: require POST for monitor state changes and check dashboard ownership on save - #280

Merged
TheWitness merged 2 commits into
Cacti:developfrom
somethingwithproof:fix/dashboard-post-and-ownership
Oct 23, 2026
Merged

TheWitness merged 2 commits into
Cacti:developfrom
somethingwithproof:fix/dashboard-post-and-ownership

Conversation

@somethingwithproof

Copy link
Copy Markdown
Member

Description

State-changing actions (save, saveDb, remove, ajax_mute_all, ajax_unmute_all, ajax_saveorder) now require POST so csrf-magic covers them. monitor.php dispatches through a new monitorRequestAction() helper, which turns those actions sent by any other method into a plain page draw. monitor.js now sends remove and the mute toggles as POST with __csrf_magic. The other three actions already did.

saveSettings() now always saves as the session user and no longer reads a user request variable. Updating a dashboard the user does not own is refused with the existing "could not be Saved!" message, now raised as an error, the same ownership rule removeDashboard() and saveCardOrder() already apply. A hand-built &user=0 URL can therefore no longer create a shared (user_id 0) dashboard. No UI ever sent user. An admin-gated way to create shared dashboards can follow as a separate change.

Related Issue

Related to #211 (addresses part of the audit; does not close it).

Motivation and Context

These are the only monitor endpoints that change stored state, and they were the ones outside csrf-magic's POST check. The save path was also the only dashboard write without an owner check.

Risk: small. A user can no longer save over a shared or foreign dashboard; "save as new" still works. If a dashboard is left open past Cacti's 2-hour CSRF token lifetime, Mute needs a second click. saveFilter and saveDb already behave this way. Read-only actions (ajax_status, ajax_hostpanel, dbchange) still accept GET. There are no new strings and no schema change.

How Has This Been Tested?

New Pest tests cover GET, POST and a missing request method for each of the six actions, and saveSettings with owned, foreign and shared dashboards and with a forged user. 4 of the 5 saveSettings tests fail on develop. Full suite: 148 passed (420 assertions) on PHP 8.4.25 and 8.5.12. php -l is clean on PHP 8.2 and 8.4. The patch-coverage, i18n POT and manifest checks pass locally. With includes/controller.php added to the coverage source, its changed lines are 100% covered.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation repository accordingly.

csrf-magic only validates POST, so save, saveDb, remove, the mute toggles
and the card-order save now fall through to the normal page draw when sent
by GET, and monitor.js sends remove and the mute toggles as POST with the
CSRF token.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
saveSettings() took the owner from an unvalidated user request variable and
let sql_save() overwrite any dashboard id. It now always uses the session
user and refuses to update a dashboard the user does not own, matching
removeDashboard() and saveCardOrder().

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
4.1% Duplication on New Code (required ≤ 3%)
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@TheWitness
TheWitness merged commit ec90326 into Cacti:develop Oct 23, 2026
6 of 7 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.

2 participants