[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fgWVkfsS0ZYSjYoeWlAaRHi1JEKyU6kGxYXA8XpfAv5w":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":28,"research_verified":29,"research_rounds_completed":30,"research_plan":31,"research_summary":32,"research_vulnerable_code":33,"research_fix_diff":34,"research_exploit_outline":35,"research_model_used":36,"research_started_at":37,"research_completed_at":38,"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":29,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":29,"source_links":39},"CVE-2026-9013","bogo-missing-authorization-to-authenticated-subscriber-sensitive-information-exposure-via-rest-api","Bogo \u003C= 3.9.1 - Missing Authorization to Authenticated (Subscriber+) Sensitive Information Exposure via REST API","The Bogo plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 3.9.1 via the bogo_rest_create_post_translation. This makes it possible for authenticated attackers, with subscriber-level access and above, to extract the raw title, content, excerpt, and password of any private, draft, or password-protected post by triggering its duplication via the translation endpoint and reading the returned title.raw, content.raw, and excerpt.raw fields of the duplicated post. This vulnerability is exploitable against posts written in a non-default locale, as authenticated subscribers can request a translation into the site's default locale to pass the locale-only permission gate. While subscribers can trigger the endpoint, this is only impactful at the Contributor-level as they can actually read the duplicated content.","bogo",null,"\u003C=3.9.1","3.9.2","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:L\u002FI:N\u002FA:N","Missing Authorization","2026-06-18 16:00:47","2026-06-19 04:31:33",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fb04ba117-da4b-445e-99c2-69a5e4f34a65?source=api-prod",1,[22,23,24,25,26,27],"admin\u002Fincludes\u002Fjs\u002Findex.js","bogo.php","includes\u002Fblock-editor\u002Flanguage-switcher\u002Findex.js","includes\u002Frest-api.php","license.txt","readme.txt","researched",false,3,"# Exploitation Research Plan: CVE-2026-9013 (Bogo Sensitive Information Exposure)\n\n## 1. Vulnerability Summary\nThe Bogo plugin for WordPress is vulnerable to **Sensitive Information Exposure** in versions up to 3.9.1. The vulnerability exists within the REST API endpoint used to create post translations (`bogo_rest_create_post_translation`). \n\nThe plugin fails to perform adequate authorization checks on the source post being translated. Specifically, the `permission_callback` for the translation creation route only verifies if the current user has access to the *target locale* (`bogo_access_locale`), but does not verify if the user has permission to read or edit the *source post*. An authenticated attacker with Subscriber-level permissions can trigger a translation of a private, draft, or password-protected post into a locale they have access to (such as the site's default locale), and the REST API response will return the `raw` content of the newly created (duplicated) post, effectively leaking the original sensitive content.\n\n## 2. Attack Vector Analysis\n*   **Endpoint:** `\u002Fwp-json\u002Fbogo\u002Fv1\u002Fposts\u002F(?P\u003Cid>\\d+)\u002Ftranslations\u002F(?P\u003Clocale>[a-z]{2,3}...)`\n*   **Method:** `POST`\n*   **Vulnerable Function:** `bogo_rest_create_post_translation` in `includes\u002Frest-api.php`.\n*   **Authentication Required:** Authenticated (Subscriber or higher).\n*   **Preconditions:** \n    *   The target post must be of a \"localizable\" post type (standard posts\u002Fpages).\n    *   The target post must be in a non-default locale (to bypass simple locale gates if the subscriber only has access to the default locale).\n    *   The attacker needs a valid `wp_rest` nonce for the authenticated session.\n\n## 3. Code Flow\n1.  **Entry Point:** An authenticated user sends a POST request to `\u002Fwp-json\u002Fbogo\u002Fv1\u002Fposts\u002F[ID]\u002Ftranslations\u002F[LOCALE]`.\n2.  **Route Registration (`includes\u002Frest-api.php`):**\n    *   The route calls the `permission_callback` which checks `current_user_can( 'bogo_access_locale', $locale )`.\n    *   Subscribers typically have access to the site's default locale.\n3.  **Vulnerable Callback (`bogo_rest_create_post_translation`):**\n    *   `$post_id` is retrieved from the request parameters.\n    *   `$post = get_post( $post_id )` retrieves the source post.\n    *   **The Bug:** The function proceeds to duplicate the post using `bogo_duplicate_post( $post, $locale )` without checking if the user has `read_post` or `edit_post` capabilities for the source `$post_id`.\n4.  **Information Leak:**\n    *   After duplication, the function constructs a response array:\n        ```php\n        $response[$locale] = array(\n            \u002F\u002F ...\n            'title' => array( 'rendered' => '', 'raw' => $new_post->post_title ),\n            'content' => array( 'rendered' => '', 'raw' => $new_post->post_content ),\n            'excerpt' => array( 'rendered' => '', 'raw' => $new_post->post_excerpt ),\n        );\n        ```\n    *   Because `$new_post` is a duplicate of the private source post, `content.raw` contains the full, sensitive text of the original post.\n\n## 4. Nonce Acquisition Strategy\nThe Bogo REST API requires a standard WordPress REST API nonce (`wp_rest` action). \n\n1.  **Identify Trigger:** Bogo enqueues its admin scripts on post editing screens.\n2.  **Creation of Environment:**\n    *   The agent should log in as a Subscriber.\n    *   Navigate to the WordPress Dashboard (even if limited, Subscribers can access `wp-admin\u002Fprofile.php`).\n3.  **Extraction:**\n    *   In the browser context, WordPress typically exposes the REST nonce via the `wpApiSettings` object.\n    *   **Action:** `browser_eval(\"window.wpApiSettings?.nonce\")`\n4.  **Alternative:** If `wpApiSettings` is not available, the nonce is often found in the `_wpnonce` attribute of the localized script for Bogo (though the JS source provided suggests it uses `apiFetch`, which relies on the standard `wp_rest` nonce).\n\n## 5. Exploitation Strategy\n\n### Step 1: Authentication\nAuthenticate the session as a Subscriber.\n\n### Step 2: Identification\nIdentify a sensitive post ID (e.g., a \"Private\" post with ID `123` currently in a locale like `fr_FR`). Identify the site's default locale (e.g., `en_US`).\n\n### Step 3: Trigger Duplication via REST API\nUsing the `http_request` tool, send the following request:\n\n*   **Method:** `POST`\n*   **URL:** `http:\u002F\u002F[TARGET]\u002Fwp-json\u002Fbogo\u002Fv1\u002Fposts\u002F123\u002Ftranslations\u002Fen_US`\n*   **Headers:**\n    *   `Content-Type: application\u002Fjson`\n    *   `X-WP-Nonce: [EXTRACTED_NONCE]`\n    *   `Cookie: [SUBSCRIBER_COOKIES]`\n*   **Body:** `{}` (Parameters are in the URL path).\n\n### Step 4: Parse Response\nThe server will respond with a `200 OK` and a JSON object. Locate the `en_US` key (or whichever locale was requested) and extract:\n*   `title.raw`\n*   `content.raw`\n\n## 6. Test Data Setup\n1.  **Administrator Action:** \n    *   Install and activate Bogo.\n    *   Install a secondary language pack (e.g., French).\n    *   Create a \"Private\" post in French:\n        ```bash\n        wp post create --post_title='Secret French Post' --post_content='This is sensitive internal data.' --post_status='private' --post_author=1\n        # Assign French locale (Bogo stores this as a term or meta, verify with bogo_set_post_locale)\n        wp eval \"bogo_set_post_locale( [POST_ID], 'fr_FR' );\"\n        ```\n2.  **Attacker Account:**\n    *   Create a Subscriber user:\n        ```bash\n        wp user create attacker attacker@example.com --role=subscriber --user_pass=password123\n        ```\n\n## 7. Expected Results\n*   The REST API call should return a JSON object representing the newly created translation.\n*   The `content.raw` field in the JSON response must match the content of the private post created by the administrator (`'This is sensitive internal data.'`).\n*   The attacker should receive this data despite not having permission to view private posts.\n\n## 8. Verification Steps\n1.  **Post-Exploit CLI Check:**\n    *   Use `wp post list --post_status=any` to verify that a new post was actually created in the target locale.\n    *   Compare the ID returned in the REST response with the ID of the new post in the database.\n2.  **Compare Content:**\n    *   `wp post get [ORIGINAL_ID] --field=post_content`\n    *   Compare with the data captured in the `content.raw` field of the exploit response.\n\n## 9. Alternative Approaches\n*   **Targeting Drafts:** If no private posts are available, target `draft` status posts.\n*   **Targeting Password-Protected:** Target posts where `post_password` is set. The `bogo_duplicate_post` function usually copies the content regardless of the password protection status.\n*   **Locale Hunting:** If `en_US` is forbidden, use `wp-json\u002Fbogo\u002Fv1\u002Flanguages` to list all available locales and iterate through them until one passes the `bogo_access_locale` check.","The Bogo plugin for WordPress is vulnerable to Sensitive Information Exposure via its REST API due to missing authorization checks on the source post during translation creation. Authenticated users with Subscriber-level access can duplicate private, draft, or password-protected posts into a locale they have access to and receive the raw content of those posts in the API response.","\u002F\u002F includes\u002Frest-api.php line 40\nregister_rest_route( 'bogo\u002Fv1',\n\t\t'\u002Fposts\u002F(?P\u003Cid>\\d+)\u002Ftranslations\u002F(?P\u003Clocale>' . $locale_pattern . ')',\n\t\tarray( \n\t\t\t'methods' => WP_REST_Server::CREATABLE,\n\t\t\t'callback' => 'bogo_rest_create_post_translation',\n\t\t\t'permission_callback' => static function( WP_REST_Request $request ) {\n\t\t\t\t$locale = $request->get_param( 'locale' );\n\n\t\t\t\tif ( current_user_can( 'bogo_access_locale', $locale ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t} else {\n\t\t\t\t\treturn new WP_Error( 'bogo_locale_forbidden',\n\t\t\t\t\t\t__( 'You are not allowed to access posts in the requested locale.', 'bogo' ),\n\t\t\t\t\t\tarray( 'status' => 403 )\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\t\t)\n\t);\n\n---\n\n\u002F\u002F includes\u002Frest-api.php line 186\nfunction bogo_rest_create_post_translation( WP_REST_Request $request ) {\n\t$post_id = $request->get_param( 'id' );\n\n\t$post = get_post( $post_id );\n\n\t\u002F\u002F ... (missing check to see if user can read $post) ...\n\n\t$new_post_id = bogo_duplicate_post( $post, $locale );\n\n\tif ( ! $new_post_id ) {\n\t\treturn new WP_Error( 'bogo_post_duplication_failed',\n\t\t\t__( 'Failed to duplicate a post.', 'bogo' ),\n\t\t\tarray( 'status' => 500 )\n\t\t);\n\t}\n\n\t$new_post = get_post( $new_post_id );\n\t$response = array();\n\n\t$response[$locale] = array(\n\t\t'lang' => array( 'tag' => bogo_language_tag( $locale ) ),\n\t\t'id' => $new_post->ID,\n\t\t'link' => get_permalink( $new_post->ID ),\n\t\t'edit_link' => get_edit_post_link( $new_post->ID, 'raw' ),\n\t\t'slug' => $new_post->post_name,\n\t\t'type' => $new_post->post_type,\n\t\t'date' => mysql_to_rfc3339( $new_post->post_date ),\n\t\t'date_gmt' => mysql_to_rfc3339( $new_post->post_date_gmt ),\n\t\t'modified' => mysql_to_rfc3339( $new_post->post_modified ),\n\t\t'modified_gmt' => mysql_to_rfc3339( $new_post->post_modified_gmt ),\n\t\t'guid' => array( 'rendered' => '', 'raw' => $new_post->guid ),\n\t\t'title' => array( 'rendered' => '', 'raw' => $new_post->post_title ),\n\t\t'content' => array( 'rendered' => '', 'raw' => $new_post->post_content ),\n\t\t'excerpt' => array( 'rendered' => '', 'raw' => $new_post->post_excerpt ),\n\t);","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fbogo\u002F3.9.1\u002Fincludes\u002Frest-api.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fbogo\u002F3.9.2\u002Fincludes\u002Frest-api.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fbogo\u002F3.9.1\u002Fincludes\u002Frest-api.php\t2025-09-21 08:06:34.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fbogo\u002F3.9.2\u002Fincludes\u002Frest-api.php\t2026-06-16 09:20:42.000000000 +0000\n@@ -31,14 +31,28 @@\n \t\t\t'permission_callback' => static function( WP_REST_Request $request ) {\n \t\t\t\t$locale = $request->get_param( 'locale' );\n \n-\t\t\t\tif ( current_user_can( 'bogo_access_locale', $locale ) ) {\n-\t\t\t\t\treturn true;\n-\t\t\t\t} else {\n+\t\t\t\tif ( ! current_user_can( 'bogo_access_locale', $locale ) ) {\n \t\t\t\t\treturn new WP_Error( 'bogo_locale_forbidden',\n \t\t\t\t\t\t__( 'You are not allowed to access posts in the requested locale.', 'bogo' ),\n-\t\t\t\t\t\tarray( 'status' => 403 )\n+\t\t\t\t\t\tarray( 'status' => rest_authorization_required_code() )\n \t\t\t\t\t);\n \t\t\t\t}\n+\n+\t\t\t\t$post_id = $request->get_param( 'id' );\n+\n+\t\t\t\tif ( $post = get_post( $post_id ) ) {\n+\t\t\t\t\tif (\n+\t\t\t\t\t\t! $post_type_object = get_post_type_object( $post->post_type ) or\n+\t\t\t\t\t\t! current_user_can( $post_type_object->cap->create_posts )\n+\t\t\t\t\t) {\n+\t\t\t\t\t\treturn new WP_Error( 'bogo_post_cannot_create',\n+\t\t\t\t\t\t\t__( 'You are not allowed to create posts as this user.', 'bogo' ),\n+\t\t\t\t\t\t\tarray( 'status' => rest_authorization_required_code() )\n+\t\t\t\t\t\t);\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\n+\t\t\t\treturn true;\n \t\t\t},\n \t\t)\n \t);\n@@ -222,10 +249,10 @@\n \t\t'date_gmt' => mysql_to_rfc3339( $new_post->post_date_gmt ),\n \t\t'modified' => mysql_to_rfc3339( $new_post->post_modified ),\n \t\t'modified_gmt' => mysql_to_rfc3339( $new_post->post_modified_gmt ),\n-\t\t'guid' => array( 'rendered' => '', 'raw' => $new_post->guid ),\n-\t\t'title' => array( 'rendered' => '', 'raw' => $new_post->post_title ),\n-\t\t'content' => array( 'rendered' => '', 'raw' => $new_post->post_content ),\n-\t\t'excerpt' => array( 'rendered' => '', 'raw' => $new_post->post_excerpt ),\n+\t\t'guid' => array( 'rendered' => '', 'raw' => '' ),\n+\t\t'title' => array( 'rendered' => '', 'raw' => '' ),\n+\t\t'content' => array( 'rendered' => '', 'raw' => '' ),\n+\t\t'excerpt' => array( 'rendered' => '', 'raw' => '' ),\n \t);\n \n \t$lang = bogo_get_language( $locale );\n@@ -235,16 +262,28 @@\n \tif ( ! empty( $new_post->guid ) ) {\n \t\t$response[$locale]['guid']['rendered'] =\n \t\t\tapply_filters( 'get_the_guid', $new_post->guid );\n+\n+\t\tif ( current_user_can( $edit_post_cap, $new_post->ID ) ) {\n+\t\t\t$response[$locale]['guid']['raw'] = $new_post->guid;\n+\t\t}\n \t}\n \n \tif ( ! empty( $new_post->post_title ) ) {\n \t\t$response[$locale]['title']['rendered'] =\n \t\t\tget_the_title( $new_post->ID );\n+\n+\t\tif ( current_user_can( $edit_post_cap, $new_post->ID ) ) {\n+\t\t\t$response[$locale]['title']['raw'] = $new_post->post_title;\n+\t\t}\n \t}\n \n \tif ( ! empty( $new_post->post_content ) ) {\n \t\t$response[$locale]['content']['rendered'] =\n \t\t\tapply_filters( 'the_content', $new_post->post_content );\n+\n+\t\tif ( current_user_can( $edit_post_cap, $new_post->ID ) ) {\n+\t\t\t$response[$locale]['content']['raw'] = $new_post->post_content;\n+\t\t}\n \t}\n \n \tif ( ! empty( $new_post->post_excerpt ) ) {\n@@ -252,6 +291,10 @@\n \t\t\t'the_excerpt',\n \t\t\tapply_filters( 'get_the_excerpt', $new_post->post_excerpt )\n \t\t);\n+\n+\t\tif ( current_user_can( $edit_post_cap, $new_post->ID ) ) {\n+\t\t\t$response[$locale]['excerpt']['raw'] = $new_post->post_excerpt;\n+\t\t}\n \t}","The exploit involves an authenticated attacker with Subscriber-level permissions sending a POST request to the `\u002Fwp-json\u002Fbogo\u002Fv1\u002Fposts\u002F[ID]\u002Ftranslations\u002F[LOCALE]` endpoint. By targeting a private or draft post ID and requesting a translation into a locale the subscriber has permission to access (such as the site's default locale), the plugin duplicates the post and returns the full `raw` title, content, and excerpt in the JSON response. This allows the attacker to bypass standard WordPress post visibility controls.","gemini-3-flash-preview","2026-06-25 20:39:23","2026-06-25 20:40:10",{"type":40,"vulnerable_version":41,"fixed_version":11,"vulnerable_browse":42,"vulnerable_zip":43,"fixed_browse":44,"fixed_zip":45,"all_tags":46},"plugin","3.9.1","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fbogo\u002Ftags\u002F3.9.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fbogo.3.9.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fbogo\u002Ftags\u002F3.9.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fbogo.3.9.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fbogo\u002Ftags"]