CVE-2025-14348

weMail <= 2.0.7 - Insufficient Authorization via x-wemail-user Header to Sensitive Information Disclosure

mediumImproper Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
2.0.8
Patched in
1d
Time to patch

Description

The weMail - Email Marketing, Lead Generation, Optin Forms, Email Newsletters, A/B Testing, and Automation plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 2.0.7. This is due to the plugin's REST API trusting the `x-wemail-user` HTTP header to identify users without verifying the request originates from an authenticated WordPress session. This makes it possible for unauthenticated attackers who know or can guess an admin email (easily enumerable via `/wp-json/wp/v2/users`) to impersonate that user and access the CSV subscriber endpoints, potentially exfiltrating subscriber PII (emails, names, phone numbers) from imported CSV files.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.0.7
PublishedJanuary 19, 2026
Last updatedJanuary 20, 2026
Affected pluginwemail

What Changed in the Fix

Changes introduced in v2.0.8

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2025-14348 - weMail Improper Authorization ## 1. Vulnerability Summary The **weMail** plugin for WordPress (versions <= 2.0.7) contains an improper authorization vulnerability in its REST API implementation. The plugin defines a custom authentication mechanism that trusts the `…

Show full research plan

Research Plan: CVE-2025-14348 - weMail Improper Authorization

1. Vulnerability Summary

The weMail plugin for WordPress (versions <= 2.0.7) contains an improper authorization vulnerability in its REST API implementation. The plugin defines a custom authentication mechanism that trusts the x-wemail-user HTTP header to identify and authenticate users. Specifically, in includes/Rest/Csv.php, the permission callback extracts an email address from this header and uses wp_set_current_user() to impersonate that user without verifying if the request originated from a valid WordPress session or contains a valid nonce/secret.

An unauthenticated attacker can provide an administrator's email address in the x-wemail-user header to gain administrative access to the plugin's CSV data endpoints, leading to the disclosure of sensitive subscriber information (PII) contained in uploaded CSV files.

2. Attack Vector Analysis

  • Vulnerable Endpoints:
    • GET /wp-json/wemail/v1/csv/(?P<id>[\d]+)/subscribers
    • GET /wp-json/wemail/v1/csv/(?P<id>[\d]+)/meta-fields
    • GET /wp-json/wemail/v1/csv/(?P<id>[\d]+)
  • Vulnerable Parameter (Header): x-wemail-user
  • Authentication Required: None (Unauthenticated).
  • Preconditions:
    1. The attacker must know or guess a valid administrator's email (enumerable via /wp-json/wp/v2/users).
    2. A CSV file must have been uploaded to the WordPress Media Library (as an attachment) and be known to the plugin.
    3. The attacker must know or guess the attachment id of the CSV file.

3. Code Flow

  1. Entry Point: A request is made to register_rest_route endpoints in includes/Rest/Csv.php.
  2. Permission Check: The permission_callback points to WeDevs\WeMail\Rest\Csv::permission($request).
  3. Header Extraction: At line 81, the code executes $user_email = $request->get_header( 'x-wemail-user' );.
  4. Impersonation:
    • At line 84, it looks up the user: $user = get_user_by( 'email', $user_email );.
    • At line 87, if the user exists, it performs the bypass: wp_set_current_user( $user->ID );.
  5. Capability Check: It returns wemail()->user->can( 'create_subscriber' ). In most weMail configurations, an administrator possesses this capability.
  6. Data Sink: Upon successful permission check, the subscribers($request) method (line 144) is called. It retrieves the attachment URL via wp_get_attachment_url($file_id), downloads the content via wp_remote_get, and parses it using League\Csv\Reader.
  7. Disclosure: The CSV content is returned as a JSON response via WP_REST_Response.

4. Nonce Acquisition Strategy

According to the source code in includes/Rest/Csv.php, the permission method does not check for a WordPress nonce (X-WP-Nonce) if the x-wemail-user header is provided.

Specifically, comparing includes/Rest/Csv.php to includes/Rest/Forms.php:

  • Forms.php uses: if ( $nonce && wp_verify_nonce( $nonce, 'wp_rest' ) ) (Line 124).
  • Csv.php uses: if ( ! empty( $user_email ) ) { ... wp_set_current_user( $user->ID ); ... } (Lines 83-88).

Since the vulnerability is exactly that the plugin trusts the header instead of a session/nonce, no nonce is required for this exploitation.

5. Exploitation Strategy

  1. Identify Admin Email:
    • Request: GET /wp-json/wp/v2/users
    • Extract the email of a user with the administrator role.
  2. Identify CSV Attachment ID:
    • In a real attack, IDs are sequential integers (e.g., 1, 2, 3...).
    • In PoC, we will create an attachment to get a valid ID.
  3. Exfiltrate Data:
    • Request: GET /wp-json/wemail/v1/csv/[ID]/subscribers
    • Header: x-wemail-user: [ADMIN_EMAIL]
    • Tool: http_request

6. Test Data Setup

  1. Create Admin: Ensure a user exists with email admin@example.com.
  2. Upload Sensitive CSV:
    • Create a file subscribers.csv with content:
      first_name,last_name,email,phone
      John,Doe,john@victim.com,555-0199
      Jane,Smith,jane@victim.com,555-0200
      
    • Use WP-CLI to sideload this into the media library to get an ID:
      wp media import subscribers.csv --porcelain (Capture the returned ID).
  3. No specific plugin settings are required other than the plugin being active.

7. Expected Results

  • The API should return a 200 OK response.
  • The response body should be a JSON object containing an array of subscriber records:
    {
        "subscribers": [
            {
                "first_name": "John",
                "last_name": "Doe",
                "email": "john@victim.com",
                "phone": "555-0199"
            },
            ...
        ]
    }
    
  • Without the x-wemail-user header, the API should return a 403 Forbidden or false.

8. Verification Steps

  1. Verify the exfiltrated data matches the content of the subscribers.csv file created in step 6.
  2. Check the wp_posts table via WP-CLI to confirm the attachment ID used matches the file:
    wp post get [ID] --field=post_title
  3. Confirm unauthenticated access by attempting the request without the header and ensuring it fails.

9. Alternative Approaches

  • Information Leakage (Metadata): If /subscribers is blocked or empty, try GET /wp-json/wemail/v1/csv/[ID]/meta-fields to at least prove authorization bypass by seeing the CSV headers.
  • Brute Force ID: If the specific attachment ID is unknown, the agent can loop through IDs 1-100.
  • API Key Path: The permission function also checks X-WeMail-Key against user meta wemail_api_key. If the x-wemail-user path were patched but this remained, an attacker could attempt to find leaked API keys. However, x-wemail-user is the primary and easiest vector here.

Check if your site is affected.

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