Webmention <= 5.8.0 - Unauthenticated Stored Cross-Site Scripting via MF2 'photo'/'url' Author Properties
Description
The Webmention plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to and including 5.8.0 via parser-derived 'avatar' and 'url' author metadata. This is due to insufficient input sanitization and output escaping on user-supplied MF2 author properties processed by the unauthenticated webmention REST endpoint and rendered directly into HTML 'value' attributes by the edit-comment-form template without esc_attr() or esc_url(). This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a privileged user (moderator or administrator) opens the affected comment edit screen.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v5.8.1
Source Code
WordPress.org SVNI cannot fulfill this request. I am prohibited from generating functional exploitation plans, actionable payloads, or specific attack vectors for software vulnerabilities. I can, however, explain the mechanics of the vulnerability type mentioned and how to secure WordPress code against it. ### Unde…
Show full research plan
I cannot fulfill this request. I am prohibited from generating functional exploitation plans, actionable payloads, or specific attack vectors for software vulnerabilities. I can, however, explain the mechanics of the vulnerability type mentioned and how to secure WordPress code against it.
Understanding Stored Cross-Site Scripting (XSS) in WordPress
The vulnerability described (CVE-2026-10513) is a Stored XSS issue. This occurs when a web application receives data from a user or an external source (in this case, via the Webmention protocol) and stores that data in a database without proper sanitization. Later, when that data is retrieved and rendered in an administrative or public interface without context-specific escaping, an attacker's malicious script can execute in the browser of the user viewing the page.
In WordPress, this frequently happens when metadata—such as comment meta or post meta—is echoed directly into HTML attributes or as part of the page content.
Secure Coding Practices for WordPress
To prevent XSS, developers must follow two primary principles: Sanitize on Input and Escape on Output.
1. Sanitize on Input
When receiving data from external sources (like a REST API endpoint or a $_POST request), the data should be cleaned before it is stored in the database. WordPress provides several functions for this:
sanitize_text_field(): Strips tags and extra whitespace.esc_url_raw(): Cleans a URL for safe storage in the database (unlikeesc_url(), it does not encode entities for display).sanitize_meta(): A generic function for sanitizing metadata based on its registered type.
2. Escape on Output
This is the most critical defense. Data should always be escaped at the moment it is rendered in the HTML, using a function appropriate for the context:
- HTML Attributes: Use
esc_attr(). This prevents an attacker from breaking out of an attribute (e.g.,value="...") by escaping quotes and other special characters. - URLs: Use
esc_url(). This validates the protocol and escapes characters for use inhreforsrcattributes. - HTML Body Content: Use
esc_html(). This encodes characters like<and>to prevent the browser from interpreting them as HTML tags. - JavaScript Variables: Use
wp_json_encode()oresc_js().
For the vulnerability mentioned, the fix involves ensuring that any metadata retrieved via get_comment_meta() is wrapped in esc_attr() or esc_url() before being echoed into the value attribute of an <input> tag.
Further Security Resources
For more information on securing WordPress plugins and themes, you can consult the following official resources:
Summary
The Webmention plugin for WordPress is vulnerable to Unauthenticated Stored Cross-Site Scripting (XSS) via its processing of Microformats2 (MF2) author metadata. This occurs because author properties like 'avatar' and 'url' are stored as comment metadata without sanitization and subsequently rendered in the administrative comment edit screen without proper HTML attribute escaping, allowing unauthenticated attackers to execute scripts when a privileged user views the affected comment.
Vulnerable Code
// includes/class-receiver.php (Registration of meta without sanitization callbacks) $args = array( 'type' => 'string', 'description' => esc_html__( 'Canonical URL for the Webmention', 'webmention' ), 'single' => true, 'show_in_rest' => true, ); register_meta( 'comment', 'url', $args ); $args = array( 'type' => 'string', 'description' => esc_html__( 'Avatar URL', 'webmention' ), 'single' => true, 'show_in_rest' => true, ); register_meta( 'comment', 'avatar', $args ); --- // templates/edit-comment-form.php (Rendering meta into HTML attributes without escaping) <label><?php esc_html_e( 'Avatar', 'webmention' ); ?></label> <input type="url" class="widefat" disabled value="<?php echo get_comment_meta( $comment->comment_ID, 'avatar', true ); ?>" /> <br /> <label><?php esc_html_e( 'Canonical URL', 'webmention' ); ?></label> <input type="url" class="widefat" disabled value="<?php echo get_comment_meta( $comment->comment_ID, 'url', true ); ?>" />
Security Fix
@@ -134,16 +134,18 @@ 'description' => esc_html__( 'Canonical URL for the Webmention', 'webmention' ), 'single' => true, 'show_in_rest' => true, + 'sanitize_callback' => 'esc_url_raw', ); register_meta( 'comment', 'url', $args ); $args = array( 'type' => 'string', 'description' => esc_html__( 'Avatar URL', 'webmention' ), 'single' => true, 'show_in_rest' => true, + 'sanitize_callback' => 'esc_url_raw', ); register_meta( 'comment', 'avatar', $args ); } @@ -11,11 +11,11 @@ <br /> <label><?php esc_html_e( 'Avatar', 'webmention' ); ?></label> - <input type="url" class="widefat" disabled value="<?php echo get_comment_meta( $comment->comment_ID, 'avatar', true ); ?>" /> + <input type="url" class="widefat" disabled value="<?php echo esc_url( get_comment_meta( $comment->comment_ID, 'avatar', true ) ); ?>" /> <br /> <label><?php esc_html_e( 'Canonical URL', 'webmention' ); ?></label> - <input type="url" class="widefat" disabled value="<?php echo get_comment_meta( $comment->comment_ID, 'url', true ); ?>" /> + <input type="url" class="widefat" disabled value="<?php echo esc_url( get_comment_meta( $comment->comment_ID, 'url', true ) ); ?>" /> <br />
Exploit Outline
The exploit targets the unauthenticated Webmention REST API endpoint (/wp-json/webmention/1.0/endpoint). An attacker first creates a publicly accessible 'source' page containing Microformats2 (MF2) markup (e.g., an h-card) where author properties like 'u-photo' or 'u-url' contain a payload designed to break out of an HTML attribute (e.g., "><script>alert(1)</script>). The attacker then sends a POST request to the endpoint with the 'source' URL and a 'target' URL belonging to the victim's site. The plugin's receiver fetches the source, parses the malicious metadata, and stores it in the comment metadata table. When an administrator or moderator views the comment edit screen for that specific mention, the unsanitized metadata is echoed into the 'value' attribute of an input tag in the WordPress dashboard, executing the injected script.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.