CVE-2026-13468

Visualizer <= 4.0.3 - Missing Authorization to Unauthenticated Sensitive Information Disclosure via /visualizer/v1/action/{chart}/{type}/ REST Endpoint

highMissing Authorization
7.5
CVSS Score
7.5
CVSS Score
high
Severity
4.0.4
Patched in
1d
Time to patch

Description

The Visualizer – Tables & Charts Manager with Built-in AI Generator plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 4.0.3. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for unauthenticated attackers to access and export the contents of any visualizer chart on the site — including charts in draft, private, pending, future, or trash status — as CSV, Excel, or HTML via the /wp-json/visualizer/v1/action/{chart}/{type}/ REST endpoint. This bypass is particularly impactful because the standard WordPress REST endpoint for the non-public 'visualizer' custom post type correctly enforces capability checks and returns HTTP 401 to unauthenticated callers, whereas this plugin-registered route circumvents that protection entirely.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=4.0.3
PublishedJune 30, 2026
Last updatedJuly 1, 2026
Affected pluginvisualizer

What Changed in the Fix

Changes introduced in v4.0.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-13468 (Visualizer Sensitive Information Disclosure) ## 1. Vulnerability Summary The **Visualizer** plugin for WordPress is vulnerable to an authorization bypass via its custom REST API endpoint `/visualizer/v1/action/{chart}/{type}/`. While the standard WordPr…

Show full research plan

Exploitation Research Plan: CVE-2026-13468 (Visualizer Sensitive Information Disclosure)

1. Vulnerability Summary

The Visualizer plugin for WordPress is vulnerable to an authorization bypass via its custom REST API endpoint /visualizer/v1/action/{chart}/{type}/. While the standard WordPress REST API for the visualizer custom post type correctly enforces permissions, this specific plugin-registered route lacks any capability checks or nonce verification in its permission_callback. This allows unauthenticated attackers to disclose the full data contents of any chart (including those in Draft, Private, or Trash status) by exporting them to CSV, Excel, or HTML formats.

2. Attack Vector Analysis

  • Endpoint: /wp-json/visualizer/v1/action/{chart}/{type}/
  • Base Route: visualizer/v1 (as defined by VISUALIZER_REST_VERSION in index.php)
  • HTTP Methods: GET (for data export actions) and POST (for saving).
  • Vulnerable Parameters:
    • {chart}: The ID of the visualizer chart (Post ID).
    • {type}: The action to perform. Valid types defined in get_actions(): csv, xls, print, copy, image.
  • Authentication: None (Unauthenticated).
  • Preconditions: At least one chart must exist (any status). The attacker needs to guess or iterate through chart IDs.

3. Code Flow

The vulnerability exists in classes/Visualizer/Module/Frontend.php:

  1. Route Registration: In endpoint_register(), the route is defined with a flawed permission_callback.
  2. Flawed Authorization: The permission_callback logic:
    '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 ) ) {
            return true; // Explicitly allows save/cancel without checks
        }
        // Vulnerable line: Defaults to true if the filter is not hooked (which it isn't in free version)
        return ! empty( $chart_id ) && apply_filters( 'visualizer_pro_show_chart', true, $chart_id );
    },
    
  3. Action Execution: If the callback returns true, perform_action is invoked.
  4. Data Retrieval: perform_action (and its subsequent calls like getCSV) fetches the post meta and associated data for the given chart_id regardless of post status (private, draft, etc.) because the REST API context bypasses standard frontend visibility checks.

4. Nonce Acquisition Strategy

Based on the source code in classes/Visualizer/Module/Frontend.php, no nonce is required for the GET requests to this endpoint.

The code explicitly mentions:

"let save and cancel go without any check as past version of pro did not send the X-WP-Nonce"

The permission_callback for other actions (like csv) relies solely on the visualizer_pro_show_chart filter, which defaults to true and does not perform any wp_verify_nonce or check_ajax_referer checks.

5. Exploitation Strategy

The goal is to demonstrate unauthenticated access to a private chart's data.

Step 1: Enumerate/Guess Chart ID

Since IDs are incremental integers, an attacker can iterate from 1 upwards.

Step 2: Request Export

Target the CSV export action.

  • Request Type: GET
  • URL: http://localhost:8080/wp-json/visualizer/v1/action/{ID}/csv/
  • Headers: None required.

Step 3: Parse Response

The server will respond with a CSV file containing the data used to populate the chart.

6. Test Data Setup

To verify the vulnerability, create a chart that should be inaccessible.

  1. Log in as Admin.
  2. Create a Chart: Navigate to Visualizer -> Library -> Add New. Create a "Table" chart with dummy sensitive data (e.g., "Salary" column with "User A: $100,000").
  3. Set Status to Private: Edit the newly created chart (it's a custom post type visualizer) and set its visibility to Private or its status to Draft.
  4. Note the ID: Identify the Post ID of the chart from the URL (e.g., post=123).

7. Expected Results

  • Unauthenticated Access: A GET request to /wp-json/visualizer/v1/action/123/csv/ should return HTTP 200 OK.
  • Data Disclosure: The response body should contain the CSV data of the "Private" chart.
  • Comparison: A standard REST request to /wp-json/wp/v2/visualizer/123 should return HTTP 401 Unauthorized or HTTP 403 Forbidden for unauthenticated users, highlighting the bypass in the custom endpoint.

8. Verification Steps

After the HTTP request, verify the content:

# Verify the response contains the sensitive setup data
echo "Checking if CSV data was leaked..."
if [[ "$RESPONSE_BODY" == *"Salary"* ]]; then
    echo "SUCCESS: Sensitive data disclosed."
else
    echo "FAILURE: Data not found in response."
fi

9. Alternative Approaches

If csv type is restricted or behaves unexpectedly, try other export types:

  • XLS: /wp-json/visualizer/v1/action/{ID}/xls/
  • Copy: /wp-json/visualizer/v1/action/{ID}/copy/ (often returns JSON or raw data)
  • Print: /wp-json/visualizer/v1/action/{ID}/print/ (returns HTML view of the data)

If the site is using a custom table prefix or modified REST base, check the source of the main page for visualizer_v1 strings to confirm the route.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Visualizer plugin for WordPress is vulnerable to an authorization bypass due to a flawed permission_callback in its custom REST API endpoint /visualizer/v1/action/{chart}/{type}/. This allows unauthenticated attackers to disclose the full data contents of any chart, including those in private, draft, or trash status, by exporting them to CSV, Excel, or HTML.

Vulnerable Code

/* classes/Visualizer/Module/Frontend.php lines 152-163 */
'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;
	}
	return ! empty( $chart_id ) && apply_filters( 'visualizer_pro_show_chart', true, $chart_id );
},

Security Fix

--- /classes/Visualizer/Module/Frontend.php
+++ /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 );
 				},

Exploit Outline

An unauthenticated attacker can exploit this vulnerability by sending a GET request to the /wp-json/visualizer/v1/action/{chart_id}/{type}/ endpoint. The attacker needs to guess or iterate through chart IDs (incremental integers) and specify an export type such as 'csv' or 'xls'. Because the permission_callback defaults to true for export actions and does not check post status or user capabilities, the plugin will serve the full data content of the chart, even if it is set to private or draft visibility. This bypasses the standard WordPress REST API access controls for the 'visualizer' custom post type.

Check if your site is affected.

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