Appointment Booking Calendar — Simply Schedule Appointments Booking Plugin <= 1.6.11.11 - Missing Authorization
Description
The Appointment Booking Calendar — Simply Schedule Appointments Booking Plugin plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.6.11.11. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.6.11.11What Changed in the Fix
Changes introduced in v1.6.12.0
Source Code
WordPress.org SVNNotices_Api` routes use `get_items_permissions_check`. If this function is NOT defined in `SSA_Notices_Api` and NOT in `WP_REST_Controller`, what happens? WordPress will try to call it and fail if it doesn't exist. However, the class `SSA_Notices_Api` is truncated. It *likely* contains: …
Show full research plan
Notices_Apiroutes useget_items_permissions_check. If this function is NOT defined in SSA_Notices_Apiand NOT inWP_REST_Controller, what happens? WordPress will try to call it and fail if it doesn't exist. However, the class SSA_Notices_Api` is truncated. It likely contains:
php public function get_items_permissions_check( $request ) { return true; }
This would be the "Missing Authorization" (it exists, but it doesn't authorize).
Let's look at `SSA_Notices_Api::update_item`:
```php
public function update_item( $request ) {
$params = $request->get_params();
$notice_name = sanitize_text_field( $params['id'] );
// ...
update_option( 'ssa_dismissed_notices', $dismissed_notices, false );
}
```
It's a perfect sink.
1. Summary
2. Attack Vector: `POST /wp-json/ssa/v1/notices/pinned/`
3. Code Flow: `SSA_Db_Model::whitelist_ssa_rest_api` -> `SSA_Notices_Api::update_item_pinned_notices`.
4. Nonce: Explain why it'
Summary
The Simply Schedule Appointments plugin for WordPress is vulnerable to unauthorized access and modification of administrative notice settings due to improper permission checks and a global REST API authentication bypass. Unauthenticated or low-privileged attackers can trigger REST endpoints to dismiss or pin administrative notices site-wide, as the plugin whitelists all /ssa/ routes from core WordPress REST authentication.
Vulnerable Code
// includes/class-db-model.php line 31 public function whitelist_ssa_rest_api( $result ) { if ( isset( $GLOBALS['wp']->query_vars['rest_route'] ) ) { $route = untrailingslashit( $GLOBALS['wp']->query_vars['rest_route'] ); if ( 0 === strpos( $route, '/ssa/' ) ) { return true; } } return $result; } --- // includes/class-notices-api.php line 308 public function get_items_permissions_check( $request ) { return TD_API_Model::nonce_permissions_check( $request ); } // includes/class-notices-api.php line 320 public function update_item_permissions_check( $request ) { if ( is_user_logged_in() ) { return true; } }
Security Fix
@@ -302,47 +302,39 @@ } /** - * Check if a given request has access to get items + * Plugin admin notices and dismissed/pinned state are admin UI surface, not + * public-facing data, and reads/writes affect site-wide options. Gate every + * notices route on the SSA admin floor (`ssa_manage_appointments`). * * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|bool + * @return bool */ public function get_items_permissions_check( $request ) { - return TD_API_Model::nonce_permissions_check( $request ); + return current_user_can( 'ssa_manage_appointments' ); } /** - * Check if a given request has access to get a specific item - * * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|bool + * @return bool */ public function get_item_permissions_check( $request ) { - return TD_API_Model::nonce_permissions_check( $request ); + return current_user_can( 'ssa_manage_appointments' ); } /** - * Check if a given request has access to update a specific item - * * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|bool + * @return bool */ public function update_item_permissions_check( $request ) { - if ( is_user_logged_in() ) { - return true; - } + return current_user_can( 'ssa_manage_appointments' ); } /** - * Check if a given request has access to delete a specific item - * * @param WP_REST_Request $request Full data about the request. - * @return WP_Error|bool + * @return bool */ public function delete_item_permissions_check( $request ) { - if ( is_user_logged_in() ) { - return true; - } + return current_user_can( 'ssa_manage_appointments' ); }
Exploit Outline
1. An attacker identifies a REST API endpoint belonging to the notices functionality, such as POST /wp-json/ssa/v1/notices/pinned/{id} or POST /wp-json/ssa/v1/notices/{id}. 2. The attacker sends a request to this endpoint without valid administrative credentials or a valid nonce. 3. The plugin's global whitelist in SSA_Db_Model::whitelist_ssa_rest_api instructs WordPress to bypass standard REST authentication for this route. 4. The vulnerable permission_callback in SSA_Notices_Api (either get_items_permissions_check or update_item_permissions_check) fails to adequately verify administrative capabilities, checking only for basic login or a weak legacy nonce condition. 5. Upon successful request, the plugin executes update_option(), allowing the attacker to modify site-wide settings such as ssa_dismissed_notices or ssa_pinned_notices.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.