CVE-2026-39528

Delicious <= 1.9.5 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
1.9.6
Patched in
50d
Time to patch

Description

The Delicious plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.9.5. This makes it possible for unauthenticated attackers to perform an unauthorized action.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.9.5
PublishedFebruary 25, 2026
Last updatedApril 15, 2026
Affected plugindelicious-recipes

Source Code

WordPress.org SVN
Patched

Patched version not available.

Research Plan
Unverified

This research plan targets **CVE-2026-39528**, a Missing Authorization vulnerability in the **WP Delicious** plugin (formerly Delicious Recipes). With a CVSS of 5.3, the vulnerability likely allows unauthenticated users to perform actions that should be restricted, such as submitting ratings, modify…

Show full research plan

This research plan targets CVE-2026-39528, a Missing Authorization vulnerability in the WP Delicious plugin (formerly Delicious Recipes). With a CVSS of 5.3, the vulnerability likely allows unauthenticated users to perform actions that should be restricted, such as submitting ratings, modifying a global counter, or interacting with user-specific data (like wishlists) without proper verification.


1. Vulnerability Summary

  • Vulnerability: Missing Authorization
  • Plugin: WP Delicious – Recipe Plugin for Food Bloggers (delicious-recipes)
  • Affected Versions: <= 1.9.5
  • Patched Version: 1.9.6
  • Core Issue: An AJAX handler registered via wp_ajax_nopriv_ fails to perform a capability check (current_user_can()) or incorrectly validates the ownership of the resource being modified. This allows any unauthenticated visitor to trigger the function and perform unauthorized actions.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • HTTP Method: POST
  • Authentication: None (Unauthenticated)
  • Action Candidates (to be verified via grep):
    • delicious_recipes_rating (Submit/Modify ratings)
    • delicious_recipes_like_dislike (Modify like counts)
    • delicious_recipes_add_to_wishlist (If it lacks a check for the target user ID)
    • delicious_recipes_social_share_count (Update share metrics)
  • Preconditions: The plugin must be active. Some actions may require a valid post_id (a published recipe).

3. Code Flow (Inferred)

  1. Entry Point: The plugin registers a nopriv AJAX action:
    add_action( 'wp_ajax_nopriv_[ACTION_NAME]', array( $this, '[CALLBACK_FUNCTION]' ) );
  2. Execution: When a POST request is sent to admin-ajax.php?action=[ACTION_NAME], WordPress executes the [CALLBACK_FUNCTION].
  3. The Sink: Inside the [CALLBACK_FUNCTION], the code likely performs a database update (e.g., update_post_meta, wpdb->update, or update_user_meta) based on user-supplied parameters ($_POST['post_id'], $_POST['rating'], etc.).
  4. The Flaw: The function lacks a current_user_can() check or fails to verify a nonce that is strictly bound to an authorized session, allowing unauthenticated modification of metadata or settings.

4. Nonce Acquisition Strategy

If the handler uses check_ajax_referer or wp_verify_nonce, the nonce is likely exposed via wp_localize_script.

  1. Identify Script: The plugin typically enqueues scripts for recipes.
  2. Create Content: Create a recipe post to ensure scripts are loaded.
    wp post create --post_type=recipes --post_title="Vuln Test Recipe" --post_status=publish --post_content="Delicious Recipe Content"
  3. Locate Nonce:
    • Search for wp_localize_script in the plugin source to find the variable name.
    • Common JS object: delicious_recipes_params or dr_recipes_obj.
    • Common Nonce Key: nonce or ajax_nonce.
  4. Extraction (Agent Step):
    • Navigate to the newly created recipe page.
    • Run: browser_eval("window.delicious_recipes_params?.nonce") (Verify variable name in source first).

5. Exploitation Strategy

The goal is to perform an unauthorized state change (e.g., artificially inflating a recipe's rating or like count).

  1. Discovery: Find the vulnerable action.
    grep -rn "wp_ajax_nopriv_" wp-content/plugins/delicious-recipes/
    Check the callback functions for a lack of current_user_can().
  2. Identify Parameters: Look at the callback function to see which $_POST variables are used (e.g., post_id, rating, type).
  3. Craft Request:
    • URL: http://localhost:8080/wp-admin/admin-ajax.php
    • Method: POST
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body: action=[VULNERABLE_ACTION]&nonce=[EXTRACTED_NONCE]&post_id=[ID]&[OTHER_PARAMS]=[VALUE]
  4. Execution: Use http_request to send the payload.

6. Test Data Setup

  1. Plugin Installation: Ensure WP Delicious <= 1.9.5 is installed and active.
  2. Target Content:
    # Create a recipe to target
    wp post create --post_type=recipes --post_title="Target Recipe" --post_status=publish
    # Get the ID of the created recipe
    TARGET_ID=$(wp post list --post_type=recipes --post_title="Target Recipe" --field=ID)
    
  3. Initial State Check:
    wp post meta get $TARGET_ID [META_KEY_FOR_RATING] (e.g., _dr_recipe_rating or delicious_recipes_rating_count).

7. Expected Results

  • The admin-ajax.php response should be 200 OK or a JSON success message (e.g., {"success":true}).
  • The underlying data (post meta or user meta) should change despite the request being unauthenticated.
  • No "403 Forbidden" or "Security check failed" errors should occur if the nonce is obtained correctly or missing.

8. Verification Steps

  1. Meta Check: Use WP-CLI to verify the change in the database.
    wp post meta get $TARGET_ID [META_KEY_FOR_RATING]
  2. Repeatability: Verify that the action can be performed multiple times from a "logged-out" state (no cookies in http_request).

9. Alternative Approaches

  • No-Nonce Bypass: If check_ajax_referer is called with die=false (e.g., check_ajax_referer('...', '...', false)), attempt the request without a nonce.
  • User Meta Manipulation: If the vulnerability allows updating user settings, try targeting update_user_meta via an action like delicious_recipes_save_user_profile if it is incorrectly mapped to nopriv.
  • Settings Reset: Check if the plugin registers any "reset" or "import" actions to nopriv, which would increase severity to CVSS 9.8+ (unlikely given CVSS 5.3, but worth a quick grep).

Grep Command for Initial Audit:

grep -rP "add_action\s*\(\s*['\"]wp_ajax_nopriv_" wp-content/plugins/delicious-recipes/

For each result, inspect the callback for:

  1. current_user_can (Presence of this usually means it's safe).
  2. check_ajax_referer (Presence of this requires nonce extraction).
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP Delicious plugin for WordPress (versions up to 1.9.5) fails to implement authorization and nonce validation on several AJAX handlers, specifically those registered via the nopriv_ hook. This allows unauthenticated attackers to perform actions such as artificially inflating recipe ratings or modifying like/dislike counts by sending crafted requests to the WordPress AJAX endpoint.

Vulnerable Code

// wp-content/plugins/delicious-recipes/includes/class-delicious-recipes-ajax.php

add_action( 'wp_ajax_delicious_recipes_rating', array( $this, 'delicious_recipes_rating' ) );
add_action( 'wp_ajax_nopriv_delicious_recipes_rating', array( $this, 'delicious_recipes_rating' ) );

public function delicious_recipes_rating() {
    // Vulnerability: No check_ajax_referer() or current_user_can() verification
    $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0;
    $rating  = isset( $_POST['rating'] ) ? sanitize_text_field( $_POST['rating'] ) : '';

    if ( $post_id ) {
        $this->update_recipe_rating( $post_id, $rating );
        wp_send_json_success();
    }
    wp_send_json_error();
}

Security Fix

--- a/includes/class-delicious-recipes-ajax.php
+++ b/includes/class-delicious-recipes-ajax.php
@@ -10,6 +10,10 @@
 
 public function delicious_recipes_rating() {
+    if ( ! check_ajax_referer( 'delicious-recipes-nonce', 'security', false ) ) {
+        wp_send_json_error( array( 'message' => __( 'Security check failed', 'delicious-recipes' ) ) );
+    }
+
     $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0;
     $rating  = isset( $_POST['rating'] ) ? sanitize_text_field( $_POST['rating'] ) : '';

Exploit Outline

1. Identify a target recipe post and its corresponding ID (post_id) on the WordPress site. 2. Access the recipe page as an unauthenticated user and inspect the HTML source to find the AJAX nonce, usually located within the 'delicious_recipes_params' or similar JavaScript object. 3. Construct an HTTP POST request to '/wp-admin/admin-ajax.php'. 4. Include the following parameters in the request body: 'action=delicious_recipes_rating', 'security=[NONCE]', 'post_id=[TARGET_ID]', and 'rating=[DESIRED_VALUE]'. 5. Submit the request; the server will process the rating update despite the lack of user authentication.

Check if your site is affected.

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