Robo Gallery <= 5.1.3 - Authenticated (Author+) Stored Cross-Site Scripting via 'Loading Label' Setting
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:NTechnical Details
What Changed in the Fix
Changes introduced in v5.1.4
Source Code
WordPress.org SVN# 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 byROBO_GALLERY_TYPE_POST). - Capability Required: Author or higher (users with
edit_postsfor therobo_gallerycapability type). - Vulnerable Parameter: The field corresponding to
rbs_gallery_LoadingWord. Based on plugin patterns, this is likely a POST parameter namedrbs_gallery_LoadingWordorrobo_gallery_LoadingWordsent 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
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_posthook). 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.
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 executealert(document.domain).
- A victim views a page containing
4. Nonce Acquisition Strategy
To save the gallery settings, a WordPress nonce is required.
- Identify Entry Point: The plugin registers its post type in
app/class.listing.php. Galleries are managed through the standard WordPress post editor interface. - Create/Navigate: The agent should create a new gallery or navigate to an existing one.
- Extraction:
- Navigation:
browser_navigate("/wp-admin/post-new.php?post_type=robo_gallery")(assumingROBO_GALLERY_TYPE_POSTisrobo_gallery). - Nonce Search: Post editing uses the standard
_wpnoncefield. - Custom Nonces: If the plugin uses a custom AJAX save, check for localized variables using
browser_eval. Common candidates in this plugin would bewindow.robo_gallery_objor similar.
- Navigation:
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:editpostpost_ID:[GALLERY_ID]_wpnonce:[EXTRACTED_NONCE]rbs_gallery_LoadingWord:|***alert(document.domain)***|post_type:robo_gallery(inferred)
Step 4: Trigger the XSS
- 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]"]' - Navigate to this page using
browser_navigate().
6. Test Data Setup
- User: Create a user with the
authorrole. - Post Type: Ensure the
robo-galleryplugin is active so therobo_gallerypost type exists. - 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
LoadingWordproperty 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:
- AJAX Save: Check
app/extensions/fields/(inferred path fromapp/app.php) for AJAX handlers that save gallery settings. The hook would likely bewp_ajax_robo_gallery_save_settings. - 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. - Field Name: If
rbs_gallery_LoadingWorddoesn't work, inspect the HTML source of the gallery editor to find the exactnameattribute of the "Loading Label" input field. It may be nested or use a different prefix. (e.g.,robo_gallery_options[LoadingWord]).
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
@@ -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); @@ -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.