Skip to content

Commit 9d3ee7d

Browse files
committed
security fixes
1 parent cd733ec commit 9d3ee7d

3 files changed

Lines changed: 832 additions & 8 deletions

File tree

classes/admin/class-page-settings.php

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,11 @@ public function store_settings_form_options() {
133133
\wp_send_json_error( [ 'message' => \esc_html__( 'You do not have permission to update settings.', 'progress-planner' ) ] );
134134
}
135135

136-
// Check the nonce.
137-
\check_admin_referer( 'progress_planner' );
136+
// SECURITY FIX: Use check_ajax_referer instead of check_admin_referer for AJAX handlers.
137+
// check_admin_referer is designed for form submissions, not AJAX requests.
138+
if ( ! \check_ajax_referer( 'progress_planner', 'nonce', false ) ) {
139+
\wp_send_json_error( [ 'message' => \esc_html__( 'Invalid nonce.', 'progress-planner' ) ] );
140+
}
138141

139142
if ( isset( $_POST['pages'] ) ) {
140143
foreach ( \wp_unslash( $_POST['pages'] ) as $type => $page_args ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
@@ -189,9 +192,7 @@ public function store_settings_form_options() {
189192
* @return void
190193
*/
191194
public function save_settings() {
192-
// Check the nonce.
193-
\check_admin_referer( 'progress_planner' );
194-
195+
// Nonce is already checked in store_settings_form_options() which calls this method.
195196
$redirect_on_login = isset( $_POST['prpl-redirect-on-login'] )
196197
? \sanitize_text_field( \wp_unslash( $_POST['prpl-redirect-on-login'] ) )
197198
: false;
@@ -205,9 +206,7 @@ public function save_settings() {
205206
* @return void
206207
*/
207208
public function save_post_types() {
208-
// Check the nonce.
209-
\check_admin_referer( 'progress_planner' );
210-
209+
// Nonce is already checked in store_settings_form_options() which calls this method.
211210
$include_post_types = isset( $_POST['prpl-post-types-include'] )
212211
? \array_map( 'sanitize_text_field', \wp_unslash( $_POST['prpl-post-types-include'] ) ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
213212
// If no post types are selected, use the default post types (post and page can be deregistered).

classes/suggested-tasks/providers/class-tasks-interactive.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,18 @@ public function handle_interactive_task_submit() {
8888
$value = \sanitize_text_field( \wp_unslash( $_POST['value'] ) );
8989
$setting_path = \json_decode( \sanitize_text_field( \wp_unslash( $_POST['setting_path'] ) ), true );
9090

91+
// SECURITY FIX: Whitelist allowed options to prevent arbitrary options update.
92+
// This prevents privilege escalation by restricting which options can be updated.
93+
$allowed_options = $this->get_allowed_interactive_options();
94+
95+
if ( ! \in_array( $setting, $allowed_options, true ) ) {
96+
\wp_send_json_error(
97+
[
98+
'message' => \esc_html__( 'Invalid setting. This option cannot be updated through interactive tasks.', 'progress-planner' ),
99+
]
100+
);
101+
}
102+
91103
if ( ! empty( $setting_path ) ) {
92104
$setting_value = \get_option( $setting );
93105
\_wp_array_set( $setting_value, $setting_path, $value );
@@ -105,6 +117,47 @@ public function handle_interactive_task_submit() {
105117
\wp_send_json_success( [ 'message' => \esc_html__( 'Setting updated.', 'progress-planner' ) ] );
106118
}
107119

120+
/**
121+
* Get the list of allowed options that can be updated via interactive tasks.
122+
*
123+
* This whitelist prevents privilege escalation by ensuring only specific
124+
* WordPress options can be modified through the interactive task interface.
125+
*
126+
* @return array List of allowed option names.
127+
*/
128+
protected function get_allowed_interactive_options() {
129+
$allowed_options = [
130+
// Core WordPress settings that are safe to update via interactive tasks.
131+
'blogdescription', // Site tagline.
132+
'default_comment_status', // Comment settings.
133+
'default_ping_status', // Pingback settings.
134+
'timezone_string', // Site timezone.
135+
'WPLANG', // Site language/locale.
136+
'date_format', // Date format.
137+
'time_format', // Time format.
138+
'default_pingback_flag', // Pingback flag.
139+
'comment_registration', // Comment registration.
140+
'close_comments_for_old_posts', // Close comments for old posts.
141+
'thread_comments', // Threaded comments.
142+
'comments_per_page', // Comments per page.
143+
'comment_order', // Comment order.
144+
'page_comments', // Paginate comments.
145+
];
146+
147+
/**
148+
* Filter the list of allowed options for interactive tasks.
149+
*
150+
* WARNING: Be very careful when extending this list. Adding sensitive
151+
* options like 'admin_email', 'users_can_register', or plugin-specific
152+
* options that control access or permissions could create security vulnerabilities.
153+
*
154+
* @param array $allowed_options List of allowed option names.
155+
*
156+
* @return array Modified list of allowed option names.
157+
*/
158+
return \apply_filters( 'progress_planner_interactive_task_allowed_options', $allowed_options );
159+
}
160+
108161
/**
109162
* Add the popover.
110163
*

0 commit comments

Comments
 (0)