CVE-2026-57348

Paid Membership Subscriptions – Effortless Memberships, Recurring Payments & Content Restriction <= 3.0.4 - Unauthenticated Server-Side Request Forgery

mediumServer-Side Request Forgery (SSRF)
6.1
CVSS Score
6.1
CVSS Score
medium
Severity
3.0.5
Patched in
9d
Time to patch

Description

The Paid Membership Subscriptions – Effortless Memberships, Recurring Payments & Content Restriction plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 3.0.4. This makes it possible for unauthenticated attackers 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:N/UI:R/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
Required
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=3.0.4
PublishedJuly 1, 2026
Last updatedJuly 9, 2026

What Changed in the Fix

Changes introduced in v3.0.5

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on identifying and exploiting an unauthenticated Server-Side Request Forgery (SSRF) in the **Paid Membership Subscriptions** plugin. ### 1. Vulnerability Summary * **Vulnerability:** Unauthenticated SSRF. * **Location:** Likely within the payment gateway callback or I…

Show full research plan

This research plan focuses on identifying and exploiting an unauthenticated Server-Side Request Forgery (SSRF) in the Paid Membership Subscriptions plugin.

1. Vulnerability Summary

  • Vulnerability: Unauthenticated SSRF.
  • Location: Likely within the payment gateway callback or IPN (Instant Payment Notification) handling logic, which is typically hooked to init or wp_loaded to listen for external requests from payment providers (like PayPal).
  • Cause: The plugin accepts a URL or a target identifier from a user-controlled parameter (via $_GET or $_POST) and passes it to a sink like wp_remote_get() or wp_remote_post() without validating that the host is an authorized external service.
  • Impact: Attackers can force the web server to make requests to internal services (e.g., http://localhost:6379 for Redis, http://169.254.169.254 for AWS metadata) or conduct port scanning of the internal network.

2. Attack Vector Analysis

  • Endpoint: The vulnerability is reachable via the main WordPress index (/) or wp-admin/admin-ajax.php, depending on how the handler is registered.
  • Action Trigger: Based on assets/js/front-end.js, the plugin monitors parameters such as pms_gateway_payment_action and pms_gateway_payment_id.
  • Vulnerable Parameter: Likely a parameter such as ipn_url, webhook_url, or a specific action that triggers a remote request (e.g., pms_gateway_payment_action=verify_remote).
  • Authentication: Unauthenticated (AV:N/PR:N).

3. Code Flow (Inferred from Patterns)

  1. Entry Point: The plugin registers a handler on the init hook (as seen in the pattern in includes/admin/class-admin-members.php).
  2. Request Capture: The handler checks $_REQUEST['pms_gateway_payment_action'].
  3. URL Extraction: If the action matches a specific payment gateway (e.g., paypal_standard or paypal_express), the code extracts a URL or constructs one based on input.
  4. The Sink: The extracted URL is passed to wp_remote_get() or wp_remote_request() to "verify" the transaction with the provider.
  5. Missing Check: The code fails to use wp_safe_remote_get() or lacks a whitelist check against the provided URL.

4. Nonce Acquisition Strategy

Payment IPN and callback handlers usually do not require nonces because they are designed to receive asynchronous notifications from external servers. If a nonce is required for a front-end AJAX action:

  1. Identify Shortcode: The plugin uses [pms-register] or [pms-payment-form].
  2. Create Page:
    wp post create --post_type=page --post_title="Register" --post_status=publish --post_content='[pms-register]'
    
  3. Navigate & Extract: Use browser_navigate to the new page.
  4. Extract JS Variable: The plugin likely localizes data. Based on common PMS patterns, check for pms_vars or pms_front_end_js.
    // Use browser_eval
    window.pms_vars?.nonce || window.pms_front_end_js?.nonce
    

5. Exploitation Strategy

The goal is to force the server to request an internal resource.

  • Step 1: Locate the Sink.
    Use grep in the environment to find where pms_gateway_payment_action is handled and if it leads to an HTTP request.
    grep -rn "pms_gateway_payment_action" .
    grep -rn "wp_remote_get\|wp_remote_post" .
    
  • Step 2: Craft the SSRF Payload.
    Assume the vulnerable action is paypal_ipn_verify and it accepts a verify_url parameter (inferred names).
  • Step 3: Execution via http_request.
    {
      "method": "POST",
      "url": "http://localhost/wp-admin/admin-ajax.php",
      "headers": {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      "params": {
        "action": "pms_paypal_ipn_verify",
        "verify_url": "http://169.254.169.254/latest/meta-data/"
      }
    }
    
    Note: If triggered via init, send the request to the homepage (/) with the parameters.

6. Test Data Setup

  1. Activate Plugin: Ensure paid-member-subscriptions is active.
  2. Configure Gateway: Enable "PayPal Standard" or "PayPal Express" in membership settings to ensure the vulnerable code paths are initialized.
    wp option update pms_payments_settings '{"active_gateways":["paypal_standard"]}' --format=json
    
  3. External Listener: Use a tool like Webhook.site or a local netcat listener to confirm the outgoing request if testing "Blind SSRF".

7. Expected Results

  • Successful SSRF: The server response might include the content of the internal resource (if it's a "Partial SSRF" that returns body content) OR the attacker's listener receives a request from the WordPress server's IP address.
  • Response Indicators: Look for internal service banners (e.g., "Redis", "HTTP/1.1 200 OK" from an internal management interface).

8. Verification Steps

  1. Access Logs: Check the server access logs or use a collaborator to confirm the request originated from the WP server.
  2. Internal Probe: Attempt to hit http://localhost:80 and check if the response contains the WordPress site's own HTML, confirming it can reach its own loopback.

9. Alternative Approaches

  • Shortcode Vector: Check if any shortcodes (like [pms-restrict]) take a url parameter for "Remote Content" restriction.
  • File Inclusion Check: If the sink is file_get_contents(), attempt to use the file:// wrapper to read /etc/passwd.
  • Protocol Smuggling: If curl is used, try other protocols like gopher:// to interact with internal services like Memcached or Redis.

Check if your site is affected.

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