CVE-2026-40729

3D viewer – Embed 3D Models <= 1.8.5 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.8.6
Patched in
68d
Time to patch

Description

The 3D viewer – Embed 3D Models plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.8.5. This makes it possible for authenticated attackers, with contributor-level access and above, to perform an unauthorized action.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.8.5
PublishedMarch 1, 2026
Last updatedMay 7, 2026
Affected plugin3d-viewer

What Changed in the Fix

Changes introduced in v1.8.6

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Detailed Exploitation Research Plan: CVE-2026-40729 ## 1. Vulnerability Summary The **3D Viewer – Display Interactive 3D Models** plugin (versions <= 1.8.5) contains a missing authorization vulnerability within its AJAX handlers. Specifically, the function `bp3d_pipe_checker` (and potentially oth…

Show full research plan

Detailed Exploitation Research Plan: CVE-2026-40729

1. Vulnerability Summary

The 3D Viewer – Display Interactive 3D Models plugin (versions <= 1.8.5) contains a missing authorization vulnerability within its AJAX handlers. Specifically, the function bp3d_pipe_checker (and potentially others like dismiss_product_edit_notice) is registered for authenticated users via the wp_ajax_ hook but fails to perform any capability check (e.g., current_user_can()). This allows any authenticated user, including those with Contributor roles, to execute these functions. While the immediate impact of bp3d_pipe_checker is low, the pattern of missing authorization across the plugin's AJAX interface allows for unauthorized state modification or information disclosure of plugin internals.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: bp3d_pipe_checker
  • Method: GET or POST (the code uses $_GET for the nonce but does not specify for the action, standard admin-ajax.php behavior applies).
  • Parameter: _wpnonce (the nonce value).
  • Required Role: Contributor or higher.
  • Preconditions: The plugin must be active. The attacker must be logged in as a Contributor.

3. Code Flow

  1. Registration: In 3d-viewer-block/plugin.php, the class TDVB3DViewerBlock registers the AJAX action:
    add_action('wp_ajax_bp3d_pipe_checker', [$this, 'bp3d_pipe_checker']);
    
  2. Exposure: In 3d-viewer-block/inc/block.php, the onInit method localizes a script and creates a nonce with the action string 'wp_ajax':
    wp_localize_script( 'tdvb-td-viewer-editor-script', 'bp3dBlock', [
        'nonce' => wp_create_nonce( 'wp_ajax' ),
        'ajaxURL' => admin_url( 'admin-ajax.php' )
    ] );
    
    This localization is sent to the browser whenever the Block Editor is loaded by a user with editing capabilities (Contributor+).
  3. Trigger: An attacker sends a request to admin-ajax.php?action=bp3d_pipe_checker&_wpnonce=[NONCE].
  4. Execution: The bp3d_pipe_checker function in 3d-viewer-block/plugin.php is invoked:
    function bp3d_pipe_checker() {
        $nonce = sanitize_text_field(wp_unslash($_GET['_wpnonce'] ?? ''));
        if (!wp_verify_nonce($nonce, 'wp_ajax')) { // Nonce check only
            wp_send_json_error();
        }
        wp_send_json_success(['isPipe' => false]); // No capability check here!
    }
    
  5. Vulnerability: Since there is no current_user_can() check before wp_send_json_success, the action completes for any authenticated user.

4. Nonce Acquisition Strategy

The nonce is generated with the action 'wp_ajax' and passed to the JavaScript object bp3dBlock under the key nonce.

  1. Step 1: Log in as a Contributor.
  2. Step 2: Navigate to the "Add New Post" page (/wp-admin/post-new.php). This loads the Gutenberg editor.
  3. Step 3: Use the browser_eval tool to extract the nonce from the global scope.
    • Command: browser_eval("window.bp3dBlock?.nonce")
  4. Alternative: If the script is not enqueued by default, create a post and insert a "3D Viewer" block, then refresh the editor.

5. Exploitation Strategy

Perform an unauthorized AJAX call to confirm the missing capability check.

  • Login: Authenticate as contributor.
  • Nonce Retrieval: Use the strategy in Section 4.
  • HTTP Request (via http_request tool):
    • URL: http://[TARGET]/wp-admin/admin-ajax.php?action=bp3d_pipe_checker&_wpnonce=[EXTRACTED_NONCE]
    • Method: GET
    • Headers: Use cookies from the contributor session.
  • Second Exploitation (Notice Dismissal):
    • According to build/admin.js, there is an action dismiss_product_edit_notice.
    • Request:
      • URL: http://[TARGET]/wp-admin/admin-ajax.php
      • Method: POST
      • Body: action=dismiss_product_edit_notice&security=[EXTRACTED_NONCE] (Note: This action might require a different nonce found in .bp3dv_woocommerce_admin_notice dataset if the generic wp_ajax nonce fails).

6. Test Data Setup

  1. User: Create a user with the role contributor.
  2. Plugin Configuration: Ensure the plugin is activated.
  3. Content: No specific 3D models are required to trigger the authorization bypass on the AJAX endpoints.

7. Expected Results

  • Success Condition: The server returns a HTTP 200 with a JSON body: {"success":true,"data":{"isPipe":false}}.
  • Failure Condition (Fixed): If the plugin were patched, it would return a HTTP 403 or {"success":false} because the user lacks the manage_options (or similar) capability.

8. Verification Steps

Research Findings
Static analysis — not yet PoC-verified

Summary

The 3D Viewer – Embed 3D Models plugin for WordPress is vulnerable to unauthorized access because it fails to perform capability checks on its AJAX handlers. This allows authenticated users with Contributor-level access to execute actions like bp3d_pipe_checker by obtaining a valid nonce from the WordPress post editor.

Vulnerable Code

// 3d-viewer-block/plugin.php

add_action('wp_ajax_bp3d_pipe_checker', [$this, 'bp3d_pipe_checker']); // line 17

// ...

function bp3d_pipe_checker() // line 43
{
    $nonce = sanitize_text_field(wp_unslash($_GET['_wpnonce'] ?? ''));

    if (!wp_verify_nonce($nonce, 'wp_ajax')) {
        wp_send_json_error();
    }

    wp_send_json_success([
        'isPipe' => false
    ]);
}

---

// 3d-viewer-block/inc/block.php

function onInit(){ // line 19
    // ...
    wp_localize_script( 'tdvb-td-viewer-editor-script', 'bp3dBlock', [
        'nonce' => wp_create_nonce( 'wp_ajax' ),
        'ajaxURL' => admin_url( 'admin-ajax.php' )
    ] ); // line 26
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/3d-viewer/1.8.5/3d-viewer-block/inc/block.php /home/deploy/wp-safety.org/data/plugin-versions/3d-viewer/1.8.6/3d-viewer-block/inc/block.php
--- /home/deploy/wp-safety.org/data/plugin-versions/3d-viewer/1.8.5/3d-viewer-block/inc/block.php	2026-03-11 04:36:20.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/3d-viewer/1.8.6/3d-viewer-block/inc/block.php	2026-04-01 09:00:16.000000000 +0000
@@ -30,10 +30,10 @@
 	
 			wp_set_script_translations( 'tdvb-td-viewer-editor-script', 'model-viewer', plugin_dir_path( __FILE__ ) . 'languages' ); // Translate
 	
-			wp_localize_script( 'tdvb-td-viewer-editor-script', 'bp3dBlock', [
-				'nonce' => wp_create_nonce( 'wp_ajax' ),
-				'ajaxURL' => admin_url( 'admin-ajax.php' )
-			] );
+		// wp_localize_script( 'tdvb-td-viewer-editor-script', 'bp3dBlock', [
+		// 	'nonce' => wp_create_nonce( 'wp_ajax' ),
+		// 	'ajaxURL' => admin_url( 'admin-ajax.php' )
+		// ] );
 		}
 	
 		function render( $attributes ){
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/3d-viewer/1.8.5/3d-viewer-block/plugin.php /home/deploy/wp-safety.org/data/plugin-versions/3d-viewer/1.8.6/3d-viewer-block/plugin.php
--- /home/deploy/wp-safety.org/data/plugin-versions/3d-viewer/1.8.5/3d-viewer-block/plugin.php	2026-03-11 04:36:20.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/3d-viewer/1.8.6/3d-viewer-block/plugin.php	2026-04-01 09:00:16.000000000 +0000
@@ -50,7 +51,7 @@
 		}
 
 		wp_send_json_success([
-			'isPipe' => false
+			'isPipe' => true
 		]);
 	}

Exploit Outline

1. Authenticate as a user with Contributor-level privileges (or higher). 2. Navigate to the post editor (e.g., /wp-admin/post-new.php) to load the Gutenberg block editor assets. 3. Extract the security nonce from the global JavaScript object 'bp3dBlock.nonce', which is localized into the page for any user with editing permissions. 4. Construct an AJAX request to /wp-admin/admin-ajax.php using the extracted nonce and the action parameter 'bp3d_pipe_checker'. 5. Submit the request (GET or POST) and observe that the server executes the handler without any capability verification (such as current_user_can), returning a successful JSON response.

Check if your site is affected.

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