Visualizer <= 4.0.3 - Missing Authorization to Unauthenticated Sensitive Information Disclosure via /visualizer/v1/action/{chart}/{type}/ REST Endpoint
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:NTechnical Details
What Changed in the Fix
Changes introduced in v4.0.4
Source Code
WordPress.org SVN# 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 byVISUALIZER_REST_VERSIONinindex.php) - HTTP Methods:
GET(for data export actions) andPOST(for saving). - Vulnerable Parameters:
{chart}: The ID of the visualizer chart (Post ID).{type}: The action to perform. Valid types defined inget_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:
- Route Registration: In
endpoint_register(), the route is defined with a flawedpermission_callback. - Flawed Authorization: The
permission_callbacklogic:'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 ); }, - Action Execution: If the callback returns
true,perform_actionis invoked. - Data Retrieval:
perform_action(and its subsequent calls likegetCSV) fetches the post meta and associated data for the givenchart_idregardless 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.
- Log in as Admin.
- 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").
- 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. - Note the ID: Identify the Post ID of the chart from the URL (e.g.,
post=123).
7. Expected Results
- Unauthenticated Access: A
GETrequest to/wp-json/visualizer/v1/action/123/csv/should returnHTTP 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/123should returnHTTP 401 UnauthorizedorHTTP 403 Forbiddenfor 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.
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
@@ -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.