[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fy4HrPsGY1A8VFdtneuTl7PQ6OVE9mDPWZthPGwT0Tr4":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"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":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-7459","simple-history-track-log-and-audit-wordpress-changes-authenticated-subscriber-account-takeover-via-missing-authorization","Simple History – Track, Log, and Audit WordPress Changes \u003C= 5.26.0 - Authenticated (Subscriber+) Account Takeover via Missing Authorization on Event Reaction Endpoint","The Simple History – Track, Log, and Audit WordPress Changes plugin for WordPress is vulnerable to authenticated (Subscriber+) account takeover in all versions up to, and including, 5.26.0 via the event reaction endpoints (react_to_event() \u002F unreact_to_event()). The endpoints register get_items_permissions_check() as their permission_callback, which only verifies the requester is logged in and does not enforce the per-logger capability checks normally applied by Log_Query. As a result, a Subscriber-level user can POST to \u002Fwp-json\u002Fsimple-history\u002Fv1\u002Fevents\u002F\u003Cid>\u002Freact with the _fields=context query parameter and read the full context of any Simple History event — including SimpleUserLogger entries that record the full password-reset email body (reset URL with the reset key) for any user. The attacker triggers a password reset for an administrator via the lost-password form, brute-forces recent event IDs through the reaction endpoint to read the resulting user_requested_password_reset_link event, extracts the reset key from context.message, and completes the password reset to take over the administrator account. Exploitation requires an administrator to have first enabled the experimental features option (simple_history_experimental_features_enabled), which is not the default.","simple-history",null,"\u003C=5.26.0","5.27.0","high",7.5,"CVSS:3.1\u002FAV:N\u002FAC:H\u002FPR:L\u002FUI:N\u002FS:U\u002FC:H\u002FI:H\u002FA:H","Weak Password Recovery Mechanism for Forgotten Password","2026-05-29 20:38:32","2026-05-30 09:29:01",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F95d2bf1a-0993-4553-a00e-6f555c3f15be?source=api-prod",1,[22,23,24,25,26,27,28,29],"build\u002Findex.asset.php","build\u002Findex.js","css\u002Fstyles.css","inc\u002Fclass-helpers.php","inc\u002Fclass-log-query.php","inc\u002Fclass-simple-history.php","inc\u002Fclass-wp-rest-events-controller.php","inc\u002Fevent-details\u002Fclass-event-details-container.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-7459 - Simple History Account Takeover\n\n## 1. Vulnerability Summary\nThe **Simple History** plugin for WordPress is vulnerable to an authenticated account takeover in versions up to and including **5.26.0**. The vulnerability exists in the REST API reaction endpoints (`\u002Freact` and `\u002Funreact`). \n\nWhile the primary event retrieval endpoints (like `GET \u002Fevents\u002F\u003Cid>`) implement strict capability checks via `get_item_permissions_check()`, the reaction endpoints incorrectly use `get_items_permissions_check()` as their `permission_callback`. This callback only verifies that the user is logged in, failing to enforce per-logger or per-event capability checks. Consequently, a Subscriber-level user can perform a `POST` request to the reaction endpoint for any event ID. By utilizing the global WordPress REST API `_fields` parameter, the attacker can force the endpoint to return the full `context` of the event, which includes sensitive information like administrator password reset links logged by the `SimpleUserLogger`.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `POST \u002Fwp-json\u002Fsimple-history\u002Fv1\u002Fevents\u002F(?P\u003Cid>[\\d]+)\u002Freact`\n- **Query Parameters:** `_fields=context`\n- **Body Parameters:** `type=thumbsup` (or any valid reaction type from `get_allowed_reaction_types()`)\n- **Authentication:** Authenticated (Subscriber or higher).\n- **Precondition:** The \"Experimental Features\" option must be enabled (`simple_history_experimental_features_enabled`).\n\n## 3. Code Flow\n1. **Route Registration:** In `inc\u002Fclass-wp-rest-events-controller.php`, the `register_routes()` method registers the `react` endpoint:\n   ```php\n   \u002F\u002F From inc\u002Fclass-wp-rest-events-controller.php\n   register_rest_route(\n       $this->namespace,\n       '\u002F' . $this->rest_base . '\u002F(?P\u003Cid>[\\d]+)\u002Freact',\n       [\n           'args' => [ ... ],\n           [\n               'methods'             => WP_REST_Server::CREATABLE,\n               'callback'            => [ $this, 'react_to_event' ],\n               'permission_callback' => [ $this, 'get_items_permissions_check' ], \u002F\u002F VULNERABLE CALLBACK\n           ],\n       ]\n   );\n   ```\n2. **Permission Check:** `get_items_permissions_check()` is invoked. In this plugin's implementation (located in the controller), it typically returns `is_user_logged_in()`, allowing any Subscriber.\n3. **Callback Execution:** `react_to_event()` is called. It retrieves the event object by the provided `id`.\n4. **Data Leakage:** The method completes the reaction logic and returns the event object. The WordPress REST API infrastructure processes this return value, applying the `_fields` filter. Because the permission check was bypassed, the `context` data (which usually contains keys like `user_requested_password_reset_link`) is serialized and returned to the Subscriber.\n\n## 4. Nonce Acquisition Strategy\nThe REST API requires a `wp_rest` nonce for `POST` requests. As an authenticated user (Subscriber), the attacker can easily obtain this from the WordPress admin dashboard.\n\n1. **Setup:** Ensure the Subscriber user is logged in.\n2. **Navigation:** Navigate to the `\u002Fwp-admin\u002Fprofile.php` or any standard admin page.\n3. **Extraction:** Use `browser_eval` to extract the nonce from the global `wpApiSettings` object:\n   - **Command:** `browser_eval(\"window.wpApiSettings?.nonce\")`\n4. **Alternative:** If `wpApiSettings` is not available, the nonce can be found in the inline script block containing `_wpRestNonce`.\n\n## 5. Exploitation Strategy\n1. **Setup Environment:**\n   - Log in as the Subscriber (`attacker`).\n   - Identify the username of the target Administrator (e.g., `admin`).\n2. **Trigger Reset:**\n   - Send a request to `wp-login.php?action=lostpassword` for the Administrator account. This causes `SimpleUserLogger` to create a log entry containing the reset link.\n3. **Discover Event ID:**\n   - Simple History IDs are incremental. The attacker can predict the ID by checking a recent event they *can* see or by brute-forcing IDs starting from the current maximum.\n4. **Leak Reset Link:**\n   - Perform a `POST` request to the reaction endpoint for the guessed ID.\n   - **Request:**\n     ```http\n     POST \u002Fwp-json\u002Fsimple-history\u002Fv1\u002Fevents\u002F[ID]\u002Freact?_fields=context\n     Host: [TARGET]\n     Content-Type: application\u002Fx-www-form-urlencoded\n     X-WP-Nonce: [EXTRACTED_NONCE]\n\n     type=thumbsup\n     ```\n5. **Parse Response:**\n   - If the ID is correct, the response will look like:\n     ```json\n     {\n       \"context\": {\n         \"user_requested_password_reset_link\": \"https:\u002F\u002F[TARGET]\u002Fwp-login.php?action=rp&key=[KEY]&login=admin\",\n         \"message\": \"Requested a password reset link for user {user_login}...\"\n       }\n     }\n     ```\n6. **Takeover:** Use the extracted `user_requested_password_reset_link` to set a new password for the Administrator.\n\n## 6. Test Data Setup\n1. **Enable Plugin:** Install Simple History 5.26.0.\n2. **Configure Plugin:**\n   - `wp option update simple_history_experimental_features_enabled 1`\n3. **Users:**\n   - Administrator: `admin_user` \u002F `admin@example.com`\n   - Subscriber: `attacker_user` \u002F `attacker@example.com`\n4. **Trigger Event:**\n   - Use `wp-login.php` to request a password reset for `admin_user`.\n\n## 7. Expected Results\n- The `POST` request to `\u002Freact` succeeds (HTTP 200\u002F201).\n- The response body contains the `context` object.\n- The `context` object contains the `user_requested_password_reset_link` key.\n- Accessing the extracted link allows changing the Admin's password.\n\n## 8. Verification Steps\n1. **Check DB:** Verify a reaction was added to the event via CLI: `wp db query \"SELECT * FROM wp_simple_history_contexts WHERE history_id = [ID] AND key = '_reaction_thumbsup'\"` (the plugin stores reactions in context).\n2. **Login Test:** Attempt to log in with the new Administrator password set during the reset process.\n\n## 9. Alternative Approaches\nIf `_fields=context` does not return the full array in a specific environment, the attacker can try:\n- **No `_fields`:** Request the full object and look for `context` in the default response.\n- **`unreact` Endpoint:** The `POST \u002Fwp-json\u002Fsimple-history\u002Fv1\u002Fevents\u002F\u003Cid>\u002Funreact` endpoint shares the same flawed permission callback.\n- **Brute Force:** If the ID is unknown, use a simple script to iterate IDs `X` to `X+50` relative to the timestamp of the password reset request.","The Simple History plugin is vulnerable to an authenticated account takeover in versions up to 5.26.0 due to a missing authorization check on the event reaction REST API endpoints. While general event viewing is protected, any logged-in user (Subscriber+) can perform a POST request to the reaction endpoints and use the WordPress REST API '_fields' parameter to leak the full context of log entries, which may include administrator password reset links.","\u002F\u002F inc\u002Fclass-wp-rest-events-controller.php lines 205-212 and 224-231\n\n\t\t\u002F\u002F POST \u002Fwp-json\u002Fsimple-history\u002Fv1\u002Fevents\u002F\u003Cevent-id>\u002Freact.\n\t\tregister_rest_route(\n\t\t\t$this->namespace,\n\t\t\t'\u002F' . $this->rest_base . '\u002F(?P\u003Cid>[\\d]+)\u002Freact',\n\t\t\t[\n\t\t\t\t'args' => [\n\t\t\t\t\t'id'   => [\n\t\t\t\t\t\t'description' => __( 'Unique identifier for the event.', 'simple-history' ),\n\t\t\t\t\t\t'type'        => 'integer',\n\t\t\t\t\t],\n\t\t\t\t\t'type' => $reaction_type_arg,\n\t\t\t\t],\n\t\t\t\t[\n\t\t\t\t\t'methods'             => WP_REST_Server::CREATABLE,\n\t\t\t\t\t'callback'            => [ $this, 'react_to_event' ],\n\t\t\t\t\t'permission_callback' => [ $this, 'get_items_permissions_check' ],\n\t\t\t\t],\n\t\t\t]\n\t\t);\n\n\t\t\u002F\u002F POST \u002Fwp-json\u002Fsimple-history\u002Fv1\u002Fevents\u002F\u003Cevent-id>\u002Funreact.\n\t\tregister_rest_route(\n\t\t\t$this->namespace,\n\t\t\t'\u002F' . $this->rest_base . '\u002F(?P\u003Cid>[\\d]+)\u002Funreact',\n\t\t\t[\n\t\t\t\t'args' => [\n\t\t\t\t\t'id'   => [\n\t\t\t\t\t\t'description' => __( 'Unique identifier for the event.', 'simple-history' ),\n\t\t\t\t\t\t'type'        => 'integer',\n\t\t\t\t\t],\n\t\t\t\t\t'type' => $reaction_type_arg,\n\t\t\t\t],\n\t\t\t\t[\n\t\t\t\t\t'methods'             => WP_REST_Server::CREATABLE,\n\t\t\t\t\t'callback'            => [ $this, 'unreact_to_event' ],\n\t\t\t\t\t'permission_callback' => [ $this, 'get_items_permissions_check' ],\n\t\t\t\t],\n\t\t\t]\n\t\t);","--- inc\u002Fclass-wp-rest-events-controller.php\n+++ inc\u002Fclass-wp-rest-events-controller.php\n@@ -209,7 +209,7 @@\n \t\t\t\t[\n \t\t\t\t\t'methods'             => WP_REST_Server::CREATABLE,\n \t\t\t\t\t'callback'            => [ $this, 'react_to_event' ],\n-\t\t\t\t\t'permission_callback' => [ $this, 'get_items_permissions_check' ],\n+\t\t\t\t\t'permission_callback' => [ $this, 'get_item_permissions_check' ],\n \t\t\t\t],\n \t\t\t]\n \t\t);\n@@ -228,7 +228,7 @@\n \t\t\t\t[\n \t\t\t\t\t'methods'             => WP_REST_Server::CREATABLE,\n \t\t\t\t\t'callback'            => [ $this, 'unreact_to_event' ],\n-\t\t\t\t\t'permission_callback' => [ $this, 'get_items_permissions_check' ],\n+\t\t\t\t\t'permission_callback' => [ $this, 'get_item_permissions_check' ],\n \t\t\t\t],\n \t\t\t]\n \t\t);","1. Authentication: Log in to the target WordPress site with Subscriber-level credentials.\n2. Precondition: Ensure the 'Experimental Features' option is enabled in the Simple History settings.\n3. Reset Request: Trigger a password reset for the target Administrator account via \u002Fwp-login.php?action=lostpassword.\n4. Event Identification: Identify the event ID for the password reset log entry. Since IDs are incremental, this can be done by observing recent events or brute-forcing IDs starting from the current maximum.\n5. Context Leak: Send a POST request to \u002Fwp-json\u002Fsimple-history\u002Fv1\u002Fevents\u002F\u003CID>\u002Freact with the query parameter '_fields=context' and a valid 'type' (e.g., 'thumbsup'). Provide the authenticated 'X-WP-Nonce' in the headers.\n6. Extraction: The response body will contain the 'context' object. Extract the 'user_requested_password_reset_link' (the full reset URL with the key) from this object.\n7. Takeover: Navigate to the leaked reset URL and complete the password change to take control of the administrator account.","gemini-3-flash-preview","2026-06-04 15:05:52","2026-06-04 15:06:40",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","5.26.0","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsimple-history\u002Ftags\u002F5.26.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fsimple-history.5.26.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsimple-history\u002Ftags\u002F5.27.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fsimple-history.5.27.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsimple-history\u002Ftags"]