CVE-2026-4300

Robo Gallery <= 5.1.3 - Authenticated (Author+) Stored Cross-Site Scripting via 'Loading Label' Setting

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

Description

The Robo Gallery plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'Loading Label' setting in all versions up to, and including, 5.1.3. The plugin uses a custom `|***...***|` marker pattern in its `fixJsFunction()` method to embed raw JavaScript function references within JSON-encoded configuration objects. When a gallery's options are rendered on the frontend, `json_encode()` wraps all string values in double quotes. The `fixJsFunction()` method then strips the `"|***` and `***|"` sequences, effectively converting a JSON string value into raw JavaScript code. The Loading Label field (stored as `rbs_gallery_LoadingWord` post_meta) is an `rbstext` type field that is sanitized with `sanitize_text_field()` on save. While this strips HTML tags, it does not strip the `|***...***|` markers since they contain no HTML. When a user inputs `|***alert(document.domain)***|`, the value passes through sanitization intact, is stored in post_meta, and is later retrieved and output within an inline `<script>` tag via `renderMainBlock()` with the quote markers stripped — resulting in arbitrary JavaScript execution. The gallery post type uses `capability_type => 'post'`, allowing Author-level users to create galleries. This makes it possible for authenticated attackers, with Author-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses a page containing the gallery shortcode.

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.1.3
PublishedApril 7, 2026
Last updatedApril 8, 2026
Affected pluginrobo-gallery

What Changed in the Fix

Changes introduced in v5.1.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-4300 (Robo Gallery Stored XSS) ## 1. Vulnerability Summary The **Robo Gallery** plugin (up to version 5.1.3) contains a stored cross-site scripting (XSS) vulnerability. It utilizes a custom mechanism intended to allow raw JavaScript functions to be passed thro…

Show full research plan

Exploitation Research Plan: CVE-2026-4300 (Robo Gallery Stored XSS)

1. Vulnerability Summary

The Robo Gallery plugin (up to version 5.1.3) contains a stored cross-site scripting (XSS) vulnerability. It utilizes a custom mechanism intended to allow raw JavaScript functions to be passed through JSON-encoded configuration objects.

The plugin processes gallery options by JSON-encoding them and then applying a method called fixJsFunction(). This method identifies a specific marker pattern—|***...***|—and strips both the markers and the surrounding double quotes added by json_encode().

Because the "Loading Label" setting (stored as rbs_gallery_LoadingWord post_meta) is sanitized only with sanitize_text_field(), an attacker can inject the |*** markers. When the gallery is rendered via a shortcode, the plugin retrieves this meta, includes it in the configuration JSON, and fixJsFunction() converts the string into raw, executable JavaScript within an inline <script> tag.

2. Attack Vector Analysis

  • Endpoint: WordPress Admin Post Editor (/wp-admin/post.php) or the plugin's AJAX saving mechanism.
  • Post Type: robo_gallery (defined by ROBO_GALLERY_TYPE_POST).
  • Capability Required: Author or higher (users with edit_posts for the robo_gallery capability type).
  • Vulnerable Parameter: The field corresponding to rbs_gallery_LoadingWord. Based on plugin patterns, this is likely a POST parameter named rbs_gallery_LoadingWord or robo_gallery_LoadingWord sent during a gallery update.
  • Precondition: A gallery must be created and its shortcode must be embedded on a page viewed by a victim (e.g., an administrator).

3. Code Flow

  1. Input (Save):

    • An Author-level user edits a gallery post.
    • The user submits a value like |***alert(document.domain)***| for the "Loading Label" field.
    • The plugin catches the save event (likely via save_post hook).
    • sanitize_text_field() is applied. It removes HTML tags but ignores the |*** markers.
    • update_post_meta($post_id, 'rbs_gallery_LoadingWord', $payload) stores the string in the database.
  2. Output (Render):

    • A victim views a page containing [robo-gallery id="X"].
    • The shortcode handler (likely renderMainBlock()) retrieves all gallery options.
    • Options are stored in an associative array: $options['LoadingWord'] = get_post_meta($id, 'rbs_gallery_LoadingWord', true);.
    • The array is JSON-encoded: $json = json_encode($options);. Result: {"LoadingWord":"|***alert(document.domain)***|"}.
    • fixJsFunction($json) is called. It uses a regex to find "|***(.*?)***|" and replaces it with $1.
    • Resulting string: {"LoadingWord":alert(document.domain)}.
    • This string is printed inside an inline <script> block, causing the browser to execute alert(document.domain).

4. Nonce Acquisition Strategy

To save the gallery settings, a WordPress nonce is required.

  1. Identify Entry Point: The plugin registers its post type in app/class.listing.php. Galleries are managed through the standard WordPress post editor interface.
  2. Create/Navigate: The agent should create a new gallery or navigate to an existing one.
  3. Extraction:
    • Navigation: browser_navigate("/wp-admin/post-new.php?post_type=robo_gallery") (assuming ROBO_GALLERY_TYPE_POST is robo_gallery).
    • Nonce Search: Post editing uses the standard _wpnonce field.
    • Custom Nonces: If the plugin uses a custom AJAX save, check for localized variables using browser_eval. Common candidates in this plugin would be window.robo_gallery_obj or similar.

5. Exploitation Strategy

Step 1: Authentication

Log in to the WordPress instance as a user with Author privileges.

Step 2: Create a Gallery

Create a new gallery to obtain a post_ID.

# Using WP-CLI to create the post first is easier
wp post create --post_type=robo_gallery --post_status=publish --post_title="Exploit Gallery" --user=author_user

Step 3: Inject Payload

Perform an HTTP POST request to update the gallery meta. We will target the post.php endpoint.

Request:

  • URL: http://localhost:8080/wp-admin/post.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body Parameters:
    • action: editpost
    • post_ID: [GALLERY_ID]
    • _wpnonce: [EXTRACTED_NONCE]
    • rbs_gallery_LoadingWord: |***alert(document.domain)***|
    • post_type: robo_gallery (inferred)

Step 4: Trigger the XSS

  1. Create a public page containing the shortcode for the gallery.
    wp post create --post_type=page --post_status=publish --post_content='[robo-gallery id="[GALLERY_ID]"]'
    
  2. Navigate to this page using browser_navigate().

6. Test Data Setup

  1. User: Create a user with the author role.
  2. Post Type: Ensure the robo-gallery plugin is active so the robo_gallery post type exists.
  3. Payload: |***alert(document.domain)***|.

7. Expected Results

  • When viewing the page with the shortcode, the browser should execute the injected JavaScript.
  • Inspecting the page source should reveal a JSON object where the LoadingWord property is not a string (not wrapped in quotes) but raw code:
    var galleryConfig = {"some_option": "value", "LoadingWord": alert(document.domain)};
    

8. Verification Steps

After the exploitation attempt, verify the data is stored correctly in the database via WP-CLI:

wp post meta get [GALLERY_ID] rbs_gallery_LoadingWord

Confirm the output is exactly |***alert(document.domain)***|.

9. Alternative Approaches

If the standard post.php submission does not work:

  1. AJAX Save: Check app/extensions/fields/ (inferred path from app/app.php) for AJAX handlers that save gallery settings. The hook would likely be wp_ajax_robo_gallery_save_settings.
  2. Attribute Breakout: If fixJsFunction() is not stripping the quotes as expected, try a payload that breaks out of the JSON string manually, though the |*** technique is the primary vulnerability.
  3. Field Name: If rbs_gallery_LoadingWord doesn't work, inspect the HTML source of the gallery editor to find the exact name attribute of the "Loading Label" input field. It may be nested or use a different prefix. (e.g., robo_gallery_options[LoadingWord]).
Research Findings
Static analysis — not yet PoC-verified

Summary

The Robo Gallery plugin up to version 5.1.3 is vulnerable to Stored Cross-Site Scripting via the 'Loading Label' gallery setting. The plugin uses a custom pattern `|***...***|` in its `fixJsFunction()` method to strip JSON quotes and markers, effectively converting string values into raw JavaScript; an attacker with Author-level access can abuse this to execute arbitrary scripts when a gallery is viewed.

Vulnerable Code

// In the rendering logic (e.g., renderMainBlock() or similar configuration generators)
$options['LoadingWord'] = get_post_meta($id, 'rbs_gallery_LoadingWord', true);
$json = json_encode($options);
// The following method call strips the quotes and markers, turning the string into raw code
echo "<script>var config = " . $this->fixJsFunction($json) . ";</script>";

---

// Likely implementation of the marker-stripping logic
public function fixJsFunction($str) {
    // This regex identifies the custom markers and strips both the markers and the double quotes added by json_encode
    return preg_replace('/"\|\*\*\*(.*?)\*\*\*\|"/', '$1', $str);
}

Security Fix

--- a/app/extensions/fields/save.php
+++ b/app/extensions/fields/save.php
@@ -10,7 +10,7 @@
-    $loading_word = sanitize_text_field($_POST['rbs_gallery_LoadingWord']);
+    $loading_word = str_replace(array('|***', '***|'), '', sanitize_text_field($_POST['rbs_gallery_LoadingWord']));
     update_post_meta($post_id, 'rbs_gallery_LoadingWord', $loading_word);

--- a/app/class.utils.php
+++ b/app/class.utils.php
@@ -200,5 +200,5 @@
-    public function fixJsFunction($str) {
-        return preg_replace('/"\|\*\*\*(.*?)\*\*\*\|"/', '$1', $str);
-    }
+    public function fixJsFunction($str) {
+        return $str;
+    }

Exploit Outline

1. Login as an authenticated user with 'Author' privileges or higher (capable of editing `robo_gallery` posts). 2. Create a new gallery or edit an existing one. 3. Locate the 'Loading Label' configuration setting (meta key `rbs_gallery_LoadingWord`). 4. Inject the payload `|***alert(document.domain)***|` into the field. 5. Save the gallery post. The `sanitize_text_field()` function will allow the custom markers to pass through because they do not contain HTML tags. 6. Embed the gallery shortcode `[robo-gallery id="POST_ID"]` on a page and publish it. 7. When any user views the page, the plugin's `fixJsFunction()` will strip the quotes and markers from the configuration JSON, resulting in the raw `alert()` script being executed in the victim's browser context.

Check if your site is affected.

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