TS Poll <= 2.5.5 - Missing Authorization
Description
The TS Poll plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.5.5. This makes it possible for authenticated attackers, with subscriber-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v2.6.0
Source Code
WordPress.org SVNThis research plan targets **CVE-2025-68588**, a Missing Authorization vulnerability in the **TS Poll** plugin. The vulnerability allows Subscriber-level users to perform unauthorized actions, likely modifying or creating poll data, due to missing capability checks in AJAX handlers and `init` reques…
Show full research plan
This research plan targets CVE-2025-68588, a Missing Authorization vulnerability in the TS Poll plugin. The vulnerability allows Subscriber-level users to perform unauthorized actions, likely modifying or creating poll data, due to missing capability checks in AJAX handlers and init request processors.
1. Vulnerability Summary
The TS Poll plugin (<= 2.5.5) fails to implement adequate authorization checks on several administrative functions. Specifically, functions hooked to wp_ajax_ (authenticated AJAX) and the init hook (global request processing) lack current_user_can() checks. While these functions are restricted to "admin" contexts via is_admin(), WordPress considers any request to wp-admin/admin-ajax.php or wp-admin/admin.php as being in the admin context, regardless of the user's role.
2. Attack Vector Analysis
- Endpoints:
/wp-admin/admin.php(viats_poll_admin::tsp_process_requestsoninit)/wp-admin/admin-ajax.php(via variouswp_ajax_hooks)
- Vulnerable Functions:
tsp_process_requests(Processes template imports and other builder logic)tsp_save_question(Saves poll data)tspoll_dashboard_update_callback(Updates dashboard settings)
- Required Role: Subscriber or higher (Authenticated).
- Preconditions: The attacker must be logged in.
3. Code Flow (Template Import via init)
- Registration: In
admin/class-ts_poll-admin.php, the constructor registerstsp_process_requestson theinithook. - State Initialization: The constructor sets
$this->tsp_page_slugif$_GET['page']matches plugin slugs (e.g.,ts-poll-builder). - Request: A Subscriber sends a GET request to
/wp-admin/admin.php?page=ts-poll-builder&tsp-template-id=1. - Logic Trigger:
tsp_process_requestschecksif ( 'ts-poll-builder' === $this->tsp_page_slug && is_admin() ). This evaluates totruefor a Subscriber because they are accessingwp-admin/. - Execution: The code proceeds to process
tsp-template-idand triggers thetsp_import_templatefilter logic, resulting in database modification without verifying administrative permissions.
4. Nonce Acquisition Strategy
The vulnerability is "Missing Authorization," which in many TS Poll components implies a lack of both capability checks and nonce verification for these specific actions.
tsp_process_requests: The provided source shows no nonce check surrounding thetsp-template-idlogic.tsp_save_question: Not enqueued with a nonce in the Gutenberg block localization (ts_poll_block::ts_poll_block_editor_scripts).- Verification: The PoC will first attempt the actions without a nonce. If a "forbidden" or "0" response is received specifically due to nonce failure, the
browser_navigatetool will be used to visit the Subscriber's profile or dashboard to see if any nonces are leaked in the footer or localized scripts.
5. Exploitation Strategy
Approach A: Unauthorized Template Import (via init)
- Target: Create a new poll by importing a template.
- HTTP Request:
- Tool:
http_request - Method:
GET - URL:
{{base_url}}/wp-admin/admin.php?page=ts-poll-builder&tsp-template-id=1 - Authentication: Subscriber cookies.
- Tool:
- Expected Result: A 302 redirect back to the referer (via `wp_redirect
Summary
The TS Poll plugin for WordPress is vulnerable to unauthorized access and data modification due to missing capability checks on several functions hooked to AJAX and the 'init' action. This allows authenticated attackers with subscriber-level permissions to import templates, update dashboard settings, and modify poll questions.
Vulnerable Code
// admin/class-ts_poll-admin.php (Line 135) public function tsp_process_requests(){ if ( 'ts-poll-builder' === $this->tsp_page_slug && is_admin() ) { // ... logic for template import if(isset( $_GET['tsp-template-id'] ) && is_numeric( $_GET['tsp-template-id'] ) && is_int( (int) $_GET['tsp-template-id'] )){ $tsp_insert_id = apply_filters( "tsp_import_template",sanitize_text_field( $_GET['tsp-template-id'] )); --- // admin/class-ts_poll-admin.php (Line 526) function tspoll_dashboard_fetch_callback() { $tsp_dashboard_list_table = new ts_poll_dashboard(); $tsp_dashboard_list_table->ajax_response(); } function tspoll_dashboard_update_callback() { check_ajax_referer( 'tsp-dashboard-nonce', 'ts_poll_dashboard_widget_nonce' ); $tsp_dashboard_list_table = new ts_poll_dashboard(); $tsp_dashboard_list_table->prepare_items(); --- // admin/class-ts_poll-admin.php (Line 894) function tsp_save_question() { if ( ! isset( $_POST['tsp_nonce'] ) || $_POST['tsp_nonce'] == '' || ! wp_verify_nonce( $_POST['tsp_nonce'], 'tsp_builder_nonce_field' ) ) { wp_send_json_error( 'TS Poll nonce error.' ); } // ... logic to save question data
Security Fix
@@ -134,6 +98,9 @@ } } public function tsp_process_requests(){ + if ( ! current_user_can( 'manage_options' ) ) { + return; + } if ( 'ts-poll-builder' === $this->tsp_page_slug && is_admin() ) { $this->tsp_themes = array( 'standard_poll' => array( "name" => 'Standard Poll', "free" => true), @@ -146,7 +113,13 @@ 'video_in_question' => array( "name" => 'Video in Question', "free" => true), 'versus_poll' => array( "name" => 'Versus Poll', "free" => false) ); - if(isset( $_GET['tsp-template-id'] ) && is_numeric( $_GET['tsp-template-id'] ) && is_int( (int) $_GET['tsp-template-id'] )){ + if ( + isset( $_GET['tsp-template-id'] ) + && is_numeric( $_GET['tsp-template-id'] ) + && is_int( (int) $_GET['tsp-template-id'] ) + && isset( $_GET['tsp_import_nonce'] ) + && wp_verify_nonce( sanitize_text_field( $_GET['tsp_import_nonce'] ), 'tsp_import_template' ) + ){ $tsp_insert_id = apply_filters( "tsp_import_template",sanitize_text_field( $_GET['tsp-template-id'] )); if ($tsp_insert_id !== false) { wp_safe_redirect( add_query_arg( 'tsp-id', $tsp_insert_id, admin_url( 'admin.php?page=ts-poll-builder' ) ) ); @@ -524,10 +492,17 @@ <?php } function tspoll_dashboard_fetch_callback() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => 'Forbidden' ), 403 ); + } + check_ajax_referer( 'tsp-dashboard-nonce', 'ts_poll_dashboard_widget_nonce', true ); $tsp_dashboard_list_table = new ts_poll_dashboard(); $tsp_dashboard_list_table->ajax_response(); } function tspoll_dashboard_update_callback() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => 'Forbidden' ), 403 ); + } check_ajax_referer( 'tsp-dashboard-nonce', 'ts_poll_dashboard_widget_nonce', true ); $tsp_dashboard_list_table = new ts_poll_dashboard(); $tsp_dashboard_list_table->prepare_items(); @@ -888,6 +863,9 @@ wp_send_json_success( $data ); } function tsp_save_question() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => 'Forbidden' ), 403 ); + }
Exploit Outline
The vulnerability can be exploited by an authenticated user with Subscriber-level permissions. For the 'init' hook bypass, an attacker can send a GET request to '/wp-admin/admin.php?page=ts-poll-builder&tsp-template-id=1'. Because WordPress evaluates 'is_admin()' as true for any request to the wp-admin directory, and the plugin lacks a capability check (current_user_can), the plugin will process the request and import the template, creating new poll entries in the database. For AJAX-based actions like saving questions or updating the dashboard, an attacker can send POST requests to '/wp-admin/admin-ajax.php' with the corresponding 'action' parameter (e.g., 'tsp_save_question'). Although some actions require a nonce, the lack of capability checks means any user who can obtain or guess the nonce can perform administrative actions.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.