Accordion <= 3.0.3 - Authenticated (Editor+) Stored Cross-Site Scripting
Description
The Accordion plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 3.0.3 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with editor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page. This only affects multi-site installations and installations where unfiltered_html has been disabled.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=3.0.3Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2025-69350 ## 1. Vulnerability Summary The **Accordions – Responsive Accordion & FAQ Plugin** (versions <= 3.0.3) is vulnerable to **Stored Cross-Site Scripting (XSS)**. The vulnerability exists because the plugin fails to sanitize accordion item content when savi…
Show full research plan
Exploitation Research Plan - CVE-2025-69350
1. Vulnerability Summary
The Accordions – Responsive Accordion & FAQ Plugin (versions <= 3.0.3) is vulnerable to Stored Cross-Site Scripting (XSS). The vulnerability exists because the plugin fails to sanitize accordion item content when saving it to the database and subsequently fails to escape this content when rendering it via a shortcode. While WordPress core typically prevents Editors from injecting scripts if the unfiltered_html capability is removed (e.g., in Multisite or via configuration), this plugin bypasses those protections by manually handling post meta without applying wp_kses_post() or similar sanitization.
2. Attack Vector Analysis
- Endpoint: WordPress Admin Post Editor (
/wp-admin/post.phpor/wp-admin/post-new.php) - Post Type:
accordions - Vulnerable Parameter:
accordions_metabox_data[section][INDEX][content](inferred) - Authentication Level: Authenticated (Editor+)
- Preconditions:
- The site is a Multi-site installation OR
define( 'DISALLOW_UNFILTERED_HTML', true );is set inwp-config.php. - The Editor user must be able to create/edit
accordionspost types (standard plugin behavior).
- The site is a Multi-site installation OR
3. Code Flow (Inferred)
- Entry Point (Save): An Editor saves an accordion. The plugin hooks into
save_post(specifically for theaccordionspost type). - Processing: The function (likely
accordions_save_metabox_data) retrieves the array$_POST['accordions_metabox_data']. - Storage: The plugin calls
update_post_meta( $post_id, 'accordions_metabox_data', $data )without passing the content throughwp_kses_post(). - Entry Point (Render): A user visits a page containing the shortcode
[accordions id="XYZ"]. - Processing: The shortcode handler (likely
accordions_shortcode_callback) retrieves the meta usingget_post_meta(). - Sink: The plugin iterates through the accordion sections and outputs the content directly:
echo $section['content'](or equivalent), failing to useesc_html()orwp_kses_post().
4. Nonce Acquisition Strategy
Since the exploit requires Editor-level access to the Admin Dashboard, nonces must be retrieved from the page context.
- Identify the Page: The vulnerability is triggered during the creation or editing of an "Accordion" post.
- Navigate: Use
browser_navigateto go to/wp-admin/post-new.php?post_type=accordions. - Extract Nonce: The standard WordPress post nonce is located in the
#_wpnoncehidden input field.- Action String:
add-accordions(for new posts) orupdate-post_[ID](for existing). - JS Extraction:
browser_eval("document.querySelector('#_wpnonce').value")
- Action String:
- Note: If the plugin uses a custom AJAX save button, the nonce might be localized in a script object (e.g.,
accordions_ajax?.nonce). Check foraccordions_metabox_datarelated scripts in the source.
5. Exploitation Strategy
Step 1: Setup Environment
- Create an Editor user.
- Enforce
DISALLOW_UNFILTERED_HTMLto simulate a secured/Multisite environment where the Editor'sunfiltered_htmlcapability is stripped.
Step 2: Inject Payload
- Login as the Editor.
- Navigate to the Accordion creation page.
- Capture the necessary form fields, specifically the
post_ID(if auto-drafted) and the_wpnonce. - Submit a POST request to
/wp-admin/post.phpwith the following parameters:action:editpostpost_type:accordionspost_ID:[ID]_wpnonce:[EXTRACTED_NONCE]accordions_metabox_data[section][0][header]:Test Headeraccordions_metabox_data[section][0][content]:<script>alert(document.domain)</script>post_title:XSS Accordionpublish:Publish
Step 3: Trigger Execution
- Create a new public post or page.
- Insert the shortcode:
[accordions id="[POST_ID]"]. - Navigate to the public page as any user (e.g., Administrator).
- Observe the JavaScript execution.
6. Test Data Setup
- User:
wp user create editor_user editor@example.com --role=editor --user_pass=password123 - Security Config: Add
define( 'DISALLOW_UNFILTERED_HTML', true );towp-config.php. - Shortcode Page:
wp post create --post_type=page --post_title="Accordion Test" --post_content='[accordions id="REPLACE_WITH_ID"]' --post_status=publish
7. Expected Results
- The POST request to save the accordion should return a 302 redirect back to the editor, indicating success.
- When viewing the public page, a browser alert should appear displaying the domain name.
- The HTML source of the rendered accordion should contain the literal
<script>tag instead of escaped entities.
8. Verification Steps
- Database Check: Use WP-CLI to verify the unsanitized content is stored:
wp post meta get [POST_ID] accordions_metabox_data
Confirm the output contains the raw<script>tag. - Capability Check: Confirm the Editor user does not have
unfiltered_html:wp user cap list editor_user | grep unfiltered_html(Should return nothing).
9. Alternative Approaches
- Nested Payloads: If
contentis partially sanitized, attempt to inject into theheaderfield (e.g.,accordions_metabox_data[section][0][header]). - JSON Meta: If the plugin stores data as a JSON string in post meta, ensure the payload is correctly escaped for the POST request but remains active in the final HTML.
- SVG Payload: If
<script>is blocked by a WAF, use<img src=x onerror=alert(1)>or a malicious SVG within the accordion content.
Summary
The Accordion plugin for WordPress (<= 3.0.3) is vulnerable to Stored Cross-Site Scripting (XSS) via the accordion item content. Authenticated attackers with Editor-level permissions can inject malicious scripts into accordion meta data, which are then rendered without escaping on public pages, bypassing 'unfiltered_html' restrictions typically enforced in Multisite environments.
Vulnerable Code
/* Inferred from research plan: Saving logic without sanitization */ if (isset($_POST['accordions_metabox_data'])) { $accordions_metabox_data = $_POST['accordions_metabox_data']; update_post_meta($post_id, 'accordions_metabox_data', $accordions_metabox_data); } --- /* Inferred from research plan: Rendering logic without escaping */ $accordions_metabox_data = get_post_meta($post_id, 'accordions_metabox_data', true); $sections = $accordions_metabox_data['section']; foreach($sections as $section) { echo '<div class="accordion-content">' . $section['content'] . '</div>'; }
Security Fix
@@ -10,1 +10,1 @@ - update_post_meta($post_id, 'accordions_metabox_data', $_POST['accordions_metabox_data']); + $sanitized_data = array_map_recursive('wp_kses_post', $_POST['accordions_metabox_data']); + update_post_meta($post_id, 'accordions_metabox_data', $sanitized_data); @@ -25,1 +25,1 @@ - echo '<div class="accordion-content">' . $section['content'] . '</div>'; + echo '<div class="accordion-content">' . wp_kses_post($section['content']) . '</div>';
Exploit Outline
The exploit targets the Accordion post creation/editing functionality available to Editor+ roles. 1. The attacker logs into the WordPress admin panel as an Editor. 2. They navigate to create or edit an 'accordions' post type. 3. Using the browser's developer tools or a proxy, the attacker submits a POST request to '/wp-admin/post.php' containing the 'accordions_metabox_data' parameter. 4. Within the payload, the attacker includes a script tag (e.g., <script>alert(1)</script>) inside the 'content' field of a section. 5. Once the post is saved, the attacker embeds the accordion shortcode [accordions id="POST_ID"] into a public page. 6. When any user views that page, the unsanitized script executes in their browser context.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.