CVE-2026-2559

Post SMTP <= 3.8.0 - Missing Authorization to Authenticated (Subscriber+) Office 365 OAuth Configuration Overwrite

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
3.9.0
Patched in
2d
Time to patch

Description

The Post SMTP plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the `handle_office365_oauth_redirect()` function in all versions up to, and including, 3.8.0. This is due to the function being hooked to `admin_init` without any `current_user_can()` check or nonce verification. This makes it possible for authenticated attackers, with Subscriber-level access and above, to overwrite the site's Office 365 OAuth mail configuration (access token, refresh token, and user email) via a crafted URL. The configuration option is used during wizard setup of Microsoft365 SMTP, only available in the Pro option of the plugin. This could cause an Administrator to believe an attacker-controlled Azure app is their own, and lead them to connect the plugin to the attacker's account during configuration after upgrading to Pro.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=3.8.0
PublishedMarch 17, 2026
Last updatedMarch 18, 2026
Affected pluginpost-smtp

What Changed in the Fix

Changes introduced in v3.9.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on exploiting a missing authorization vulnerability in the **Post SMTP** plugin, specifically in the OAuth configuration handling for Microsoft 365. ### 1. Vulnerability Summary The vulnerability exists in the `handle_office365_oauth_redirect()` function (inferred to be l…

Show full research plan

This research plan focuses on exploiting a missing authorization vulnerability in the Post SMTP plugin, specifically in the OAuth configuration handling for Microsoft 365.

1. Vulnerability Summary

The vulnerability exists in the handle_office365_oauth_redirect() function (inferred to be located in the Office 365 transport module). This function is hooked to admin_init, a hook that runs whenever a user (including a Subscriber) accesses a page in the /wp-admin/ directory. The function fails to implement any current_user_can( 'manage_options' ) capability check or nonce verification. Consequently, any authenticated user can trigger the function by visiting a crafted URL, allowing them to overwrite the site's email configuration with attacker-controlled Azure/Office 365 OAuth tokens.

2. Attack Vector Analysis

  • Entry Point: admin_init hook.
  • Vulnerable Function: handle_office365_oauth_redirect() (called on every admin page load).
  • Authentication: Authenticated (Subscriber or higher).
  • Payload Location: GET parameters.
  • Preconditions: The site must have the Office 365 transport mechanism available (typically part of the Pro/Premium features, but the hook registration often exists in the core code).

3. Code Flow

  1. Initialization: The plugin initializes and registers various hooks.
  2. Hook Registration: The function handle_office365_oauth_redirect is hooked to admin_init.
    • Note: In Postman/Dashboard/NewDashboard.php, we see standard dashboard initialization, but the vulnerable hook typically resides in the transport-specific logic.
  3. Trigger: A Subscriber-level user logs in and navigates to /wp-admin/index.php?page=postman&action=office365_auth_callback&....
  4. Execution: admin_init fires. The plugin checks if the relevant GET parameters (like action or code) are present.
  5. Sink: The function processes the tokens provided in the URL and calls update_option( 'postman_options', ... ) to save the new (malicious) access_token, refresh_token, and user_email without verifying the user's authority.

4. Nonce Acquisition Strategy

According to the vulnerability description, this specific function missing nonce verification. Therefore, no nonce is required to trigger the overwrite.

However, if a researcher needs to verify other parts of the dashboard or REST API (as seen in NewDashboard.php):

  1. The plugin localizes the nonce in NewDashboard.php inside the admin_enqueue_scripts method.
  2. JS Variable: window.postSmtpNewDashboard
  3. Nonce Key: nonce
  4. Acquisition:
    • Create a page with a Subscriber user.
    • Access the Post SMTP dashboard (if Subscriber has access) or the main admin dashboard where scripts are enqueued.
    • Execute: browser_eval("window.postSmtpNewDashboard?.nonce").

5. Exploitation Strategy

The goal is to overwrite the Microsoft 365 SMTP configuration with attacker-controlled tokens.

Step-by-Step:

  1. Log in as Subscriber: Use the http_request tool to authenticate.
  2. Craft the Request: The URL must include the trigger parameters for the Office 365 OAuth callback. Based on the vulnerability description and common Post SMTP patterns:
    • Endpoint: /wp-admin/index.php
    • Parameters:
      • page: postman
      • action: postman_office365_oauth_callback (inferred)
      • access_token: EVIL_ACCESS_TOKEN
      • refresh_token: EVIL_REFRESH_TOKEN
      • user_email: attacker@evil-domain.com
  3. Execute the Overwrite:
    # Payload
    GET /wp-admin/index.php?page=postman&action=postman_office365_oauth_callback&access_token=AT-999&refresh_token=RT-999&user_email=attacker@evil.com
    

6. Test Data Setup

  1. Install Plugin: Post SMTP <= 3.8.0.
  2. Create User: A user with the subscriber role.
  3. Initial State: Configure the plugin to use any transport (e.g., PHPMailer) so that postman_options exists in the database.
  4. Enable Pro (Optional/Simulated): If the code path is restricted to Pro users, ensure is_plugin_active( 'post-smtp-pro/post-smtp-pro.php' ) returns true via wp plugin activate if available, or simply verify the admin_init hook is registered in the core.

7. Expected Results

  • HTTP Response: A 200 OK or a 302 Redirect back to the settings page.
  • Data Change: The postman_options entry in the wp_options table will now contain the access_token, refresh_token, and user_email provided in the GET request.

8. Verification Steps

After sending the request, use WP-CLI to inspect the plugin's settings:

# Check the postman_options for the injected values
wp option get postman_options --format=json | jq .

Verify that the user_email is attacker@evil.com and tokens match the payload.

9. Alternative Approaches

If the action parameter postman_office365_oauth_callback does not trigger the function, try alternative triggers discovered by searching the source for the handle_office365_oauth_redirect string:

  1. ?office365_auth_callback=1...
  2. ?page=postman&state=office365...

The key is that admin_init handlers often look for a specific flag in $_GET to determine if they should process an OAuth return. Once the flag is found, the missing capability check allows the overwrite.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Post SMTP plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the handle_office365_oauth_redirect() function. This function is hooked to admin_init without any capability or nonce verification, allowing authenticated users with Subscriber-level access or higher to overwrite the site's Office 365 OAuth email configuration via a crafted URL.

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/post-smtp/3.8.0/Postman/Dashboard/assets/css/app.css /home/deploy/wp-safety.org/data/plugin-versions/post-smtp/3.9.0/Postman/Dashboard/assets/css/app.css
--- /home/deploy/wp-safety.org/data/plugin-versions/post-smtp/3.8.0/Postman/Dashboard/assets/css/app.css	2026-01-20 06:26:16.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/post-smtp/3.9.0/Postman/Dashboard/assets/css/app.css	2026-03-17 07:12:48.000000000 +0000
@@ -1,34 +1,43 @@
+/*!***************************************************************!*\
+  !*** css ./node_modules/css-loader/dist/cjs.js!./src/app.css ***!\
+  \***************************************************************/
 @import url(https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap);
+/*!**************************************************************************************************************************************************************************************************************************************************************************!*\
+  !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/vue-loader/dist/index.js??ruleSet[1].rules[6].use[0]!./src/components/post-smtp-app-wrapper.vue?vue&type=style&index=0&id=7c6051c6&scoped=true&lang=css ***!\
+  \**************************************************************************************************************************************************************************************************************************************************************************/

Exploit Outline

To exploit this vulnerability, an attacker must first authenticate with Subscriber-level privileges or higher. The attacker then crafts a URL targeting any administrative page (like /wp-admin/index.php) to trigger the 'admin_init' hook. The URL must include specific GET parameters that the plugin's OAuth redirect handler looks for (inferred as 'page=postman' and an action like 'postman_office365_oauth_callback'), along with malicious 'access_token', 'refresh_token', and 'user_email' values. Because the handler lacks nonce verification and capability checks (e.g., current_user_can('manage_options')), the plugin will process the request and overwrite the site's global 'postman_options' configuration with the attacker-supplied tokens.

Check if your site is affected.

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