CVE-2026-25428

TS Poll – Survey, Versus Poll, Image Poll, Video Poll <= 2.5.5 - Authenticated (Editor+) Server-Side Request Forgery

mediumServer-Side Request Forgery (SSRF)
5.5
CVSS Score
5.5
CVSS Score
medium
Severity
2.6.0
Patched in
105d
Time to patch

Description

The TS Poll – Survey, Versus Poll, Image Poll, Video Poll plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 2.5.5. This makes it possible for authenticated attackers, with Editor-level access and above, to make web requests to arbitrary locations originating from the web application which can be used to query and modify information from internal services.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=2.5.5
PublishedJanuary 27, 2026
Last updatedMay 11, 2026
Affected pluginpoll-wp
Research Plan
Unverified

This research plan outlines the steps to identify and exploit the Authenticated Server-Side Request Forgery (SSRF) vulnerability in the **TS Poll – Survey, Versus Poll, Image Poll, Video Poll** plugin (<= 2.5.5). ### 1. Vulnerability Summary The TS Poll plugin for WordPress contains an SSRF vulnera…

Show full research plan

This research plan outlines the steps to identify and exploit the Authenticated Server-Side Request Forgery (SSRF) vulnerability in the TS Poll – Survey, Versus Poll, Image Poll, Video Poll plugin (<= 2.5.5).

1. Vulnerability Summary

The TS Poll plugin for WordPress contains an SSRF vulnerability accessible to users with Editor-level privileges or higher. The vulnerability exists because the plugin fails to properly validate or sanitize user-supplied URLs in a functionality that fetches remote content (likely related to image/video polls or poll imports). An attacker can leverage this to make the web server send requests to arbitrary internal or external locations.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • Action: tspoll_fetch_remote_data or ts_poll_get_video_meta (inferred).
  • Parameter: A URL parameter (e.g., url, video_url, or remote_path).
  • Authentication: Required (Editor+).
  • Preconditions: The attacker must have a valid session cookie for a user with the Editor role.

3. Code Flow (Inferred)

  1. Entry Point: An AJAX action is registered via add_action( 'wp_ajax_...', ... ) in the plugin's admin initialization code (likely admin/class-ts-poll-admin.php or includes/class-ts-poll.php).
  2. Nonce Verification: The handler likely checks a nonce using check_ajax_referer() or wp_verify_nonce().
  3. Source: User input is retrieved from $_POST['url'] (or similar).
  4. Sink: The input is passed directly into a WordPress HTTP API function like wp_remote_get() or wp_remote_request() without validation against a whitelist of allowed domains or internal IP ranges.
  5. Output: The response from the remote request (status code, headers, or body) is often returned to the user via wp_send_json_success().

4. Nonce Acquisition Strategy

Since this is an authenticated (Editor+) vulnerability, we must extract a valid nonce from the WordPress admin dashboard.

  1. Identify the Localized Script: The plugin likely uses wp_localize_script to pass a nonce to its admin JS.
  2. Target Page: Navigate to the "TS Poll" creation page (e.g., /wp-admin/admin.php?page=ts-poll-add-new).
  3. Extraction:
    • Log in as an Editor.
    • Navigate to the TS Poll admin menu.
    • Use browser_eval to find the nonce in the global JS scope.
    • Likely JS Variable: window.tspoll_admin_obj?.nonce or window.ts_poll_vars?.ajax_nonce (inferred).

5. Exploitation Strategy

The goal is to perform an SSRF to query internal services (e.g., the local web server or metadata services).

  1. Identify the vulnerable AJAX action: Search the plugin source for wp_remote_get to find the exact action name and parameter.
  2. Setup a Listener (Optional): Use a tool like Webhook.site to confirm external SSRF first.
  3. Craft the Request:
    • URL: http://<target-site>/wp-admin/admin-ajax.php
    • Method: POST
    • Body: action=TS_POLL_VULNERABLE_ACTION&nonce=NONCE_VALUE&url=http://127.0.0.1:80
  4. Execute via http_request:
    // Example Payload Structure
    {
      "method": "POST",
      "url": "http://localhost:8888/wp-admin/admin-ajax.php",
      "headers": {
        "Content-Type": "application/x-www-form-urlencoded",
        "Cookie": "wordpress_logged_in_..."
      },
      "body": "action=ts_poll_fetch_remote&nonce=a1b2c3d4e5&url=http://169.254.169.254/latest/meta-data/"
    }
    

6. Test Data Setup

  1. User Creation: Create a user with the Editor role.
    • wp user create editor_user editor@example.com --role=editor --user_pass=password123
  2. Internal Target: Ensure there is an internal service to hit (e.g., the standard WP instance itself or a simple file on the root).

7. Expected Results

  • Successful SSRF: The response from admin-ajax.php will contain data from the internal URL (e.g., the HTML of the local homepage or AWS metadata).
  • HTTP Response: Usually a 200 OK with a JSON body where one of the keys contains the content of the requested URL.

8. Verification Steps

  1. Check Logs: Verify in the access logs of the target internal service that a request originated from the web server's own IP address.
  2. Confirm Content: Match the response body returned by the AJAX call with the known content of the internal resource.

9. Alternative Approaches

If wp_remote_get is not the sink, look for:

  • file_get_contents($url): If the allow_url_fopen setting is enabled in PHP, this is a common SSRF sink.
  • curl_exec(): Used if the plugin implements its own CURL wrapper.
  • Blind SSRF: If the response is not returned, try to trigger a DNS request to an external collaborator (e.g., Burp Collaborator or Interactsh) to confirm the request was made.

10. Potential Action Strings to Search (Inferred)

Search the codebase for these strings to find the exact endpoint:

  • ts_poll_get_remote
  • tspoll_fetch_url
  • tspoll_video_data
  • import_poll_from_url
  • get_image_from_url (check if used in Image Polls)
Research Findings
Static analysis — not yet PoC-verified

Summary

The TS Poll plugin for WordPress is vulnerable to Authenticated (Editor+) Server-Side Request Forgery (SSRF) in versions up to and including 2.5.5. This allows users with Editor-level access or higher to make the web server send requests to arbitrary internal or external locations, potentially exposing internal service data.

Vulnerable Code

// Inferred based on Research Plan findings in admin/class-ts-poll-admin.php

add_action( 'wp_ajax_tspoll_fetch_remote_data', 'tspoll_fetch_remote_data_callback' );

function tspoll_fetch_remote_data_callback() {
    check_ajax_referer( 'tspoll_nonce', 'nonce' );
    $url = $_POST['url'];
    // The vulnerability exists here because $url is passed directly to wp_remote_get
    $response = wp_remote_get( $url );
    $body = wp_remote_retrieve_body( $response );
    wp_send_json_success( $body );
    wp_die();
}

Security Fix

--- a/admin/class-ts-poll-admin.php
+++ b/admin/class-ts-poll-admin.php
@@ -10,6 +10,11 @@
 function tspoll_fetch_remote_data_callback() {
     check_ajax_referer( 'tspoll_nonce', 'nonce' );
-    $url = $_POST['url'];
+    $url = esc_url_raw( $_POST['url'] );
+    if ( ! wp_http_validate_url( $url ) ) {
+        wp_send_json_error( 'Invalid URL' );
+    }
     $response = wp_remote_get( $url );

Exploit Outline

An attacker with Editor-level authentication must first obtain a valid AJAX nonce from the TS Poll admin dashboard (likely via a localized script variable like 'window.tspoll_admin_obj.nonce'). Then, the attacker sends a POST request to '/wp-admin/admin-ajax.php' with the action set to 'tspoll_fetch_remote_data' (or a similar remote-fetching action) and a 'url' parameter targeting an internal resource, such as 'http://169.254.169.254/latest/meta-data/'. The server performs the request and returns the resulting content in the AJAX response.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.