security: require POST+CSRF for GET-triggered purge/disable actions (GHSA-x664-x4hf-p9xh) (#8236)

* security: require POST+CSRF for GET-triggered purge/disable actions (GHSA-x664-x4hf-p9xh)

* style: align rrdcheck purge array operators for php-cs-fixer
This commit is contained in:
TheWitness authored and GitHub committed 2026-10-08 19:42:34 -04:00
1 parent 9df1923c83
commit c4a8c552a6
6 files changed
+45 -5

No files matched your search

+3
View File
@@ -65,6 +65,8 @@ set_default_action();
switch(grv('action')) {
case 'purge':
csrf_require_post();
purge_discovery_results();
break;
@@ -611,6 +613,7 @@ function create_automation_devices_filter() : array {
'display' => __('Purge'),
'action' => 'default',
'title' => __('Purge the Discovered Devices from the Database'),
'callback' => 'postUrl({ url: \'automation_devices.php?action=purge\' }, { __csrf_magic: csrfMagicToken })'
]
],
'sort' => [
+1
View File
@@ -0,0 +1 @@
Require a POST request with a CSRF token for state-changing GET actions (User Log purge, Automation Devices purge, RRDCheck purge, and plugin disable) so they can no longer be triggered cross-site via a GET request
+17
View File
@@ -414,3 +414,20 @@ function csrf_error_callback() : void {
exit;
}
/**
* csrf_require_post - reject a non-POST request for a state-changing action.
*
* State-changing actions reached through a direct action= URL must arrive by
* POST so they cannot be triggered cross-site with a GET (for example an <img>
* tag). csrf-magic validates the token on the resulting POST.
*
* @return void
*/
function csrf_require_post() : void {
if (!isset($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Allow: POST');
http_response_code(405);
exit;
}
}
+14
View File
@@ -307,6 +307,8 @@ switch($action) {
break;
case 'disable':
csrf_require_post();
api_plugin_disable($plugin);
header('Location: plugins.php');
@@ -945,6 +947,18 @@ function update_show_current() : void {
displayDialog(url, dialogTitle, dialogMessage, dialogForm, buttonContinue, buttonCancel, 80, 400);
});
$('.pidisable').off('click').on('click', function(event) {
event.preventDefault();
var url = $(this).attr('href');
if (url == '' || url == '#') {
return;
}
postUrl({ url: url }, { __csrf_magic: csrfMagicToken });
});
$('.piforceremove').off('click').on('click', function(event) {
event.preventDefault();
+7 -4
View File
@@ -39,6 +39,8 @@ if (read_config_option('rrdcheck_enable') != 'on') {
switch(grv('action')) {
case 'purge':
csrf_require_post();
rrdcheck_purge();
default:
@@ -250,10 +252,11 @@ function create_rrdcheck_filter() : array {
'title' => __('Reset filter to default values'),
],
'purge' => [
'method' => 'button',
'display' => __('Purge'),
'action' => 'default',
'title' => __('Purge Data Source Checks from the Database'),
'method' => 'button',
'display' => __('Purge'),
'action' => 'default',
'title' => __('Purge Data Source Checks from the Database'),
'callback' => 'postUrl({ url: \'rrdcheck.php?action=purge\' }, { __csrf_magic: csrfMagicToken })'
]
],
'sort' => [
+3 -1
View File
@@ -29,6 +29,8 @@ set_default_action();
switch (grv('action')) {
case 'purge_execute':
csrf_require_post();
clear_user_log();
raise_message('purge_user_log', __('User Log Purged.'), MESSAGE_LEVEL_INFO);
header('location: user_log.php');
@@ -220,7 +222,7 @@ function purge_user_log() : void {
$(function() {
$('#pc').click(function() {
strURL = location.pathname+'?action=purge_execute';
loadUrl({url:strURL})
postUrl({url: strURL}, {__csrf_magic: csrfMagicToken});
});
$('#cancel').click(function() {