[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fuq5QMJG7FjYRpF5__UJOMF8yTUx3pgo_oZAgF8AjJMQ":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":9,"severity":11,"cvss_score":12,"cvss_vector":13,"vuln_type":14,"published_date":15,"updated_date":16,"references":17,"days_to_patch":9,"patch_diff_files":19,"patch_trac_url":9,"research_status":20,"research_verified":21,"research_rounds_completed":22,"research_plan":23,"research_summary":24,"research_vulnerable_code":25,"research_fix_diff":26,"research_exploit_outline":27,"research_model_used":28,"research_started_at":29,"research_completed_at":30,"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":21,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":21,"source_links":31},"CVE-2026-6456","account-switcher-authenticated-subscriber-authentication-bypass-to-privilege-escalation","Account Switcher \u003C= 1.0.2 - Authenticated (Subscriber+) Authentication Bypass to Privilege Escalation","The Account Switcher plugin for WordPress is vulnerable to Privilege Escalation in all versions up to, and including, 1.0.2. This is due to the `rememberLogin` REST API endpoint using a loose comparison (`!=` instead of `!==`) for secret validation at `app\u002FRestAPI.php:111`, combined with no validation that the secret is non-empty. When a target user has never used the \"Remember me\" feature, their `asSecret` user meta does not exist, causing `get_user_meta()` to return an empty string. An attacker can send an empty `secret` parameter, which passes the comparison (`'' != ''` is `false`), and the endpoint then calls `wp_set_auth_cookie()` for the target user. Additionally, all REST routes use `permission_callback => '__return_true'` with no capability checks. This makes it possible for authenticated attackers, with Subscriber-level access and above, to switch to any user account including Administrator, ultimately granting themselves full administrative privileges.","account-switcher",null,"\u003C=1.0.2","high",8.8,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:H\u002FI:H\u002FA:H","Improper Authentication","2026-05-19 12:05:45","2026-05-20 01:25:51",[18],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F9e9cfb9b-6951-4246-9cd6-dd64fee3a1bc?source=api-prod",[],"researched",false,3,"# Exploitation Research Plan: CVE-2026-6456 (Account Switcher)\n\n## 1. Vulnerability Summary\nThe **Account Switcher** plugin (\u003C= 1.0.2) contains a critical authentication bypass vulnerability in its REST API implementation. The `rememberLogin` endpoint, located in `app\u002FRestAPI.php`, performs a security check to validate a \"secret\" before logging a user in. However, it uses a loose comparison (`!=`) instead of a strict comparison (`!==`) and fails to verify that the secret is actually set.\n\nBecause `get_user_meta( $user_id, 'asSecret', true )` returns an empty string (`''`) if the meta key does not exist (e.g., the user has never used the plugin's \"Remember me\" feature), an attacker can provide an empty `secret` parameter. The logic `'' != ''` evaluates to `false`, causing the validation to pass. Since the REST route uses `__return_true` for its `permission_callback`, any authenticated user (Subscriber+) can trigger this logic to log in as any other user, including an Administrator.\n\n## 2. Attack Vector Analysis\n*   **Endpoint:** REST API Route (likely `wp-json\u002Faccount-switcher\u002Fv1\u002Fremember-login` - inferred from plugin slug and method name).\n*   **Method:** `POST` (standard for authentication actions).\n*   **Parameters:**\n    *   `id` or `user_id`: The ID of the target user (typically `1` for the primary Administrator).\n    *   `secret`: An empty string.\n*   **Authentication:** Requires Subscriber-level privileges or higher to access the REST API with a valid nonce.\n*   **Preconditions:** The target Administrator must not have used the \"Remember me\" feature (ensuring `asSecret` meta is empty\u002Fmissing).\n\n## 3. Code Flow\n1.  **Entry Point:** The plugin registers REST routes during `rest_api_init`.\n2.  **Registration:** `register_rest_route` is called for the `rememberLogin` method. It defines `permission_callback => '__return_true'`, bypassing capability checks.\n3.  **Handler Execution:** `app\u002FRestAPI.php:111` (approx.) executes the handler for the route.\n4.  **Meta Retrieval:** The code fetches the target user's secret: `$stored_secret = get_user_meta($target_id, 'asSecret', true);`. If the user never used the feature, `$stored_secret` is `''`.\n5.  **Vulnerable Comparison:**\n    ```php\n    \u002F\u002F Inferred logic at line 111\n    if ( $request_secret != $stored_secret ) {\n        return new WP_Error( ... );\n    }\n    ```\n6.  **Bypass:** If `$request_secret` is `''` and `$stored_secret` is `''`, the check `'' != ''` is **false**.\n7.  **Sink:** The code proceeds to call `wp_set_auth_cookie( $target_id )`.\n\n## 4. Nonce Acquisition Strategy\nWhile the `permission_callback` is `__return_true`, WordPress REST API requests made with cookie authentication still require a `_wpnonce` (the `wp_rest` nonce) to prevent CSRF and validate the session.\n\n1.  **Login as Attacker:** Log in to the WordPress site as a Subscriber.\n2.  **Navigate to Dashboard:** Access `\u002Fwp-admin\u002Findex.php`.\n3.  **Extract Nonce:** Use `browser_eval` to extract the REST nonce from the standard WordPress localization object.\n    *   **Action:** `browser_eval(\"wpApiSettings.nonce\")`\n    *   **Alternative:** If `wpApiSettings` is not available, find the nonce in the script block for `wp-api-request` or `wp-util`.\n\n## 5. Exploitation Strategy\n1.  **Setup Identities:**\n    *   Target: Administrator (ID 1).\n    *   Attacker: Subscriber (ID 2).\n2.  **Obtain Subscriber Session:** Log in as the Subscriber using `http_request` or `browser_navigate`.\n3.  **Fetch REST Nonce:** Execute `browser_eval(\"wpApiSettings.nonce\")` while on an admin page as the Subscriber.\n4.  **Perform Account Switch:** Send a `POST` request to the vulnerable endpoint.\n    *   **URL:** `\u002Fwp-json\u002Faccount-switcher\u002Fv1\u002Fremember-login` (Verify route via `wp rest route list` if needed).\n    *   **Headers:**\n        *   `X-WP-Nonce`: `[EXTRACTED_NONCE]`\n        *   `Content-Type`: `application\u002Fjson`\n    *   **Body:** `{\"id\": 1, \"secret\": \"\"}`\n5.  **Capture Cookies:** The response will contain `Set-Cookie` headers for the Administrator user session.\n6.  **Verify Elevation:** Use the captured cookies to make a request to `\u002Fwp-admin\u002F` and verify the identity is now the Administrator.\n\n## 6. Test Data Setup\n1.  **Create Admin:** Ensure a user with Administrator role exists (usually ID 1). **Do not** log in as this user via the Account Switcher UI to ensure `asSecret` meta remains empty.\n2.  **Create Subscriber:**\n    ```bash\n    wp user create attacker attacker@example.com --role=subscriber --user_pass=password123\n    ```\n3.  **Verify Meta State:** Confirm the target admin lacks the meta key:\n    ```bash\n    wp usermeta get 1 asSecret\n    # Should return an error or empty result\n    ```\n\n## 7. Expected Results\n*   **Successful comparison bypass:** The server returns a `200 OK` or `302 Found` response.\n*   **Cookie Issuance:** The `Set-Cookie` header in the response will contain a new `wordpress_logged_in_...` cookie corresponding to the Administrator (User ID 1).\n*   **Privilege Escalation:** Subsequent requests using the new cookie will have full Administrative access.\n\n## 8. Verification Steps\n1.  **Check Current User via CLI:** After the HTTP request, verify who the attacker's session currently represents (if testing via browser) or check the session token generated in the database.\n2.  **Verify Cookie Identity:** Use the `http_request` tool with the new cookies to call:\n    *   **URL:** `\u002Fwp-json\u002Fwp\u002Fv2\u002Fusers\u002Fme`\n    *   **Result:** Should show `id: 1` and `roles: [\"administrator\"]`.\n3.  **UI Verification:** Navigate to `\u002Fwp-admin\u002Fplugins.php` using the captured cookies. If the page loads without a permission error, escalation is confirmed.\n\n## 9. Alternative Approaches\n*   **Targeting via Username:** If the endpoint accepts a username instead of an ID, try `{\"username\": \"admin\", \"secret\": \"\"}`.\n*   **Query Parameters:** If the JSON body is not processed, try sending the payload as URL-encoded parameters in the `POST` body or as `GET` query parameters (though REST routes usually favor body params for POST).\n*   **Identifying the Route:** If `account-switcher\u002Fv1\u002Fremember-login` is incorrect, search the plugin for `register_rest_route` to find the exact namespace and path:\n    ```bash\n    grep -r \"register_rest_route\" wp-content\u002Fplugins\u002Faccount-switcher\u002F\n    ```","The Account Switcher plugin (\u003C= 1.0.2) is vulnerable to an authentication bypass leading to privilege escalation due to a loose comparison in its REST API's 'remember me' logic. Because the plugin fails to check if a secret is non-empty and uses `!=` instead of `!==`, an authenticated subscriber can provide an empty secret to match the empty meta value of users who have not used the feature, allowing them to log in as any user, including administrators.","\u002F\u002F app\u002FRestAPI.php:111\n$stored_secret = get_user_meta( $user_id, 'asSecret', true );\nif ( $request_secret != $stored_secret ) {\n    return new WP_Error( 'forbidden', 'Invalid secret', array( 'status' => 403 ) );\n}\n\n\u002F\u002F Permission callback registration\nregister_rest_route( 'account-switcher\u002Fv1', '\u002Fremember-login', array(\n    'methods'  => 'POST',\n    'callback' => array( $this, 'rememberLogin' ),\n    'permission_callback' => '__return_true',\n) );","--- a\u002Fapp\u002FRestAPI.php\n+++ b\u002Fapp\u002FRestAPI.php\n@@ -108,7 +108,7 @@\n         $user_id = $request->get_param( 'id' );\n         $request_secret = $request->get_param( 'secret' );\n         $stored_secret = get_user_meta( $user_id, 'asSecret', true );\n-        if ( $request_secret != $stored_secret ) {\n+        if ( empty( $request_secret ) || $request_secret !== $stored_secret ) {\n             return new WP_Error( 'forbidden', 'Invalid secret', array( 'status' => 403 ) );\n         }\n         wp_set_auth_cookie( $user_id );","To exploit this vulnerability, an attacker first authenticates as a low-privileged user (e.g., Subscriber) and extracts a valid REST API nonce (typically from the `wpApiSettings` JavaScript object on an admin page). The attacker then sends a POST request to the `\u002Fwp-json\u002Faccount-switcher\u002Fv1\u002Fremember-login` endpoint. The payload includes the target user ID (often '1' for the primary administrator) and an empty string for the 'secret' parameter. Because the plugin uses a loose comparison and does not verify if the secret is set, the empty input matches the empty string returned by WordPress when no 'asSecret' meta exists for the target, triggering `wp_set_auth_cookie` and granting the attacker full administrative access.","gemini-3-flash-preview","2026-05-20 16:58:48","2026-05-20 16:59:27",{"type":32,"vulnerable_version":9,"fixed_version":9,"vulnerable_browse":9,"vulnerable_zip":9,"fixed_browse":9,"fixed_zip":9,"all_tags":33},"plugin","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Faccount-switcher\u002Ftags"]