[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fE8ulaKP63UF-mpmdwIXHjW3ETVtO33evCTLxFRKr5qE":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-7051","blog2social-social-media-auto-post-scheduler-missing-authorization-to-authenticated-subscriber-delete-arbitrary-b2s-post","Blog2Social: Social Media Auto Post & Scheduler \u003C= 8.9.0 - Missing Authorization to Authenticated (Subscriber+) Delete Arbitrary B2S Post Records via 'postId' Parameter","The Blog2Social: Social Media Auto Post & Scheduler plugin for WordPress is vulnerable to Missing Authorization in all versions up to, and including, 8.9.0. This is due to a missing ownership verification in the B2S_Post_Tools::deleteUserPublishPost() and B2S_Post_Tools::deleteUserSchedPost() functions, neither function includes a blog_user_id constraint in its database query, allowing authenticated attackers to soft-delete any user's B2S post records by supplying arbitrary sequential wp_b2s_posts.id values via the 'postId' parameter. This makes it possible for authenticated attackers to delete other users' published and scheduled social media post records, disrupting content publishing workflows.","blog2social",null,"\u003C=8.9.0","8.9.1","medium",5.4,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:L","Missing Authorization","2026-05-12 15:27:25","2026-05-13 04:26:45",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Ff0859e21-851a-4a6d-aa6c-9f759c5866d9?source=api-prod",1,[22,23,24,25,26,27,28,29],"assets\u002Fjs\u002Fb2s\u002Fgeneral.js","blog2social.php","includes\u002FAjax\u002FGet.php","includes\u002FAjax\u002FPost.php","includes\u002FB2S\u002FPost\u002FTools.php","includes\u002FB2S\u002FShip\u002FItem.php","includes\u002FLoader.php","includes\u002FNotice.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-7051 (Blog2Social IDOR)\n\n## 1. Vulnerability Summary\nThe **Blog2Social** plugin (up to 8.9.0) contains an Insecure Direct Object Reference (IDOR) vulnerability in its post-deletion functions. The functions `B2S_Post_Tools::deleteUserPublishPost()` and `B2S_Post_Tools::deleteUserSchedPost()` handle the deletion (soft-deletion via a `hide` flag) of social media post records stored in the `wp_b2s_posts` table. These functions fail to verify if the requesting user owns the record being deleted, allowing any authenticated user (Subscriber level and above) to delete arbitrary records by providing their numeric ID.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Actions**: \n    - `b2s_delete_user_publish_post` (for published posts)\n    - `b2s_delete_user_sched_post` (for scheduled posts)\n- **HTTP Method**: POST\n- **Payload Parameter**: `postId` (likely an array or single integer, handled in `B2S_Post_Tools` as an array)\n- **Authentication**: Authenticated (Subscriber+)\n- **Preconditions**:\n    - The attacker must have a valid session.\n    - A valid `b2s_security_nonce` must be obtained.\n    - The target `wp_b2s_posts.id` must be known or guessed (sequential).\n\n## 3. Code Flow\n1. **Entry Point**: A POST request is sent to `admin-ajax.php` with `action=b2s_delete_user_publish_post`.\n2. **AJAX Routing**: `includes\u002FAjax\u002FPost.php` registers the action:\n   ```php\n   add_action('wp_ajax_b2s_delete_user_publish_post', array($this, 'deleteUserPublishPost'));\n   ```\n3. **AJAX Handler**: `Ajax_Post::deleteUserPublishPost()` (wrapper) extracts the `postId` and calls the logic tool.\n4. **Vulnerable Logic (Sink)**: `includes\u002FB2S\u002FPost\u002FTools.php`:\n   ```php\n   public static function deleteUserPublishPost($postIds = array()) {\n       global $wpdb;\n       \u002F\u002F ...\n       foreach ($postIds as $v) {\n           \u002F\u002F VULNERABLE: No blog_user_id check in this query\n           $row = $wpdb->get_row($wpdb->prepare(\"SELECT id,v2_id,post_id FROM {$wpdb->prefix}b2s_posts WHERE id =%d\", (int) $v));\n           if (isset($row->id) && (int) $row->id == $v) {\n               \u002F\u002F Soft delete by setting 'hide' to 1\n               $wpdb->update($wpdb->prefix.'b2s_posts', array('hook_action' => $hook_action, 'hide' => 1), array('id' => $v));\n               \u002F\u002F ...\n           }\n       }\n   }\n   ```\n   The query only checks if the record exists by ID. It does not verify the `blog_user_id` column against `get_current_user_id()`.\n\n## 4. Nonce Acquisition Strategy\nThe plugin uses a global nonce `b2s_security_nonce`. This nonce is frequently localized for use in the admin dashboard and Blog2Social-specific pages.\n\n1. **Check Availability**: The nonce is generated for the action string `'b2s_security_nonce'`.\n2. **Identification**: In `assets\u002Fjs\u002Fb2s\u002Fgeneral.js`, the nonce is accessed via `jQuery('#b2s_security_nonce').val()`.\n3. **Strategy**:\n    - Log in as a Subscriber.\n    - Navigate to the WordPress Dashboard (`\u002Fwp-admin\u002Findex.php`) or any B2S page if accessible.\n    - If the plugin enqueues its scripts for all authenticated users, the nonce will be in the HTML.\n    - Use `browser_eval` to search for the hidden input:\n      `browser_eval(\"document.getElementById('b2s_security_nonce')?.value\")`\n    - Alternatively, check for localized objects in the page source like `b2s_security_nonce`.\n\n## 5. Exploitation Strategy\n### Step 1: Discover Target ID\nSince IDs in `wp_b2s_posts` are sequential, an attacker can brute-force IDs. For a PoC, we will create a post as Admin and identify its ID in the database.\n\n### Step 2: Request Deletion\nSend the following request using the `http_request` tool:\n\n**Request Details**:\n- **URL**: `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Method**: POST\n- **Headers**: `Content-Type: application\u002Fx-www-form-urlencoded`\n- **Body**:\n  ```text\n  action=b2s_delete_user_publish_post&postId[]=TARGET_ID&b2s_security_nonce=VALID_NONCE\n  ```\n  *(Note: If `postId[]` fails, try `postId=TARGET_ID` as the description implies a single parameter, but the code handles an array).*\n\n## 6. Test Data Setup\n1. **Admin User**: Log in as Admin.\n2. **Create Post**: Create a standard WordPress post.\n3. **Blog2Social Action**: Use the Blog2Social \"Site Sharing\" feature to \"Share on Networks\". This will create an entry in the `wp_b2s_posts` table.\n4. **Identify ID**:\n   ```bash\n   wp db query \"SELECT id FROM wp_b2s_posts ORDER BY id DESC LIMIT 1;\"\n   ```\n5. **Subscriber User**: Create a user with the `subscriber` role.\n\n## 7. Expected Results\n- **Response**: The server should return a JSON response: `{\"result\": true, \"postId\": [TARGET_ID], ...}`.\n- **Database Change**: The record in `wp_b2s_posts` with `id = TARGET_ID` should now have the `hide` column set to `1`.\n\n## 8. Verification Steps\nAfter the exploit request, use WP-CLI to verify the \"soft delete\" state:\n```bash\nwp db query \"SELECT id, hide FROM wp_b2s_posts WHERE id = TARGET_ID;\"\n```\nIf successful, the output will show `hide` as `1`.\n\n## 9. Alternative Approaches\nIf `b2s_delete_user_publish_post` is restricted by capability checks in the AJAX wrapper (not visible in truncated source), try the scheduled post endpoint:\n- **Action**: `b2s_delete_user_sched_post`\n- **Constraint**: The record must have `publish_date = '0000-00-00 00:00:00'` to pass the `SELECT` query in `deleteUserSchedPost`.\n\nIf the Subscriber cannot see the nonce on the default dashboard, navigate to:\n- `\u002Fwp-admin\u002Fadmin.php?page=blog2social` (if permitted)\n- Or inspect the Profile page to see if scripts are loaded.","The Blog2Social plugin for WordPress is vulnerable to an Insecure Direct Object Reference (IDOR) flaw due to missing ownership verification in its post-deletion functions. Authenticated attackers with Subscriber-level permissions can soft-delete arbitrary published or scheduled social media post records by providing sequential record IDs via AJAX endpoints, disrupting other users' content workflows.","\u002F\u002F includes\u002FB2S\u002FPost\u002FTools.php:27 (deleteUserSchedPost)\n$row = $wpdb->get_row($wpdb->prepare(\"SELECT b.id,b.post_id,b.post_for_relay,b.post_for_approve,b.sched_details_id,d.network_id,d.network_type FROM {$wpdb->prefix}b2s_posts b LEFT JOIN {$wpdb->prefix}b2s_posts_network_details d ON (d.id = b.network_details_id) WHERE b.id =%d AND b.publish_date = %s\", (int) $v, \"0000-00-00 00:00:00\"));\n\n---\n\n\u002F\u002F includes\u002FB2S\u002FPost\u002FTools.php:118 (deleteUserPublishPost)\npublic static function deleteUserPublishPost($postIds = array()) {\n    global $wpdb;\n    $resultPostIds = array();\n    $blogPostId = 0;\n    $count = 0;\n    foreach ($postIds as $v) {\n        $row = $wpdb->get_row($wpdb->prepare(\"SELECT id,v2_id,post_id FROM {$wpdb->prefix}b2s_posts WHERE id =%d\", (int) $v));\n        if (isset($row->id) && (int) $row->id == $v) {\n            $hook_action = (isset($row->v2_id) && (int) $row->v2_id > 0) ? 0 : 4; \u002F\u002FoldItems\n            $wpdb->update($wpdb->prefix.'b2s_posts', array('hook_action' => $hook_action, 'hide' => 1), array('id' => $v));","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fblog2social\u002F8.9.0\u002Fincludes\u002FAjax\u002FGet.php\t2026-04-14 11:54:18.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fblog2social\u002F8.9.1\u002Fincludes\u002FAjax\u002FGet.php\t2026-05-05 12:19:12.000000000 +0000\n@@ -54,7 +54,7 @@\n \n     public function getBlogPostStatus() {\n \n-        if (!current_user_can('read') || !check_ajax_referer('b2s_security_nonce', 'b2s_security_nonce', false)) {\n+        if (!current_user_can('edit_posts') || !check_ajax_referer('b2s_security_nonce', 'b2s_security_nonce', false)) {\n             echo wp_json_encode(array('result' => false, 'error' => 'nonce'));\n             wp_die();\n         }\n@@ -70,7 +70,7 @@\n \n     public function scrapeUrl() {\n \n-        if (!current_user_can('read') || !check_ajax_referer('b2s_security_nonce', 'b2s_security_nonce', false)) {\n+        if (!current_user_can('edit_posts') || !check_ajax_referer('b2s_security_nonce', 'b2s_security_nonce', false)) {\n             echo wp_json_encode(array('result' => false, 'error' => 'nonce'));\n             wp_die();\n         }\n... (truncated)","To exploit this vulnerability, an attacker must have an authenticated session (Subscriber level or higher). First, the attacker retrieves a valid 'b2s_security_nonce', which is commonly available in the admin dashboard source code. Next, the attacker sends a POST request to '\u002Fwp-admin\u002Fadmin-ajax.php' with the 'action' parameter set to 'b2s_delete_user_publish_post' (for published records) or 'b2s_delete_user_sched_post' (for scheduled records). The payload must include 'postId[]' containing the target record's numeric ID. Because the underlying SQL queries in B2S_Post_Tools do not verify that the record's 'blog_user_id' matches the current user's ID, the plugin will proceed to mark the record as hidden ('hide' => 1) in the database regardless of ownership.","gemini-3-flash-preview","2026-05-14 18:04:41","2026-05-14 18:05:14",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","8.9.0","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fblog2social\u002Ftags\u002F8.9.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fblog2social.8.9.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fblog2social\u002Ftags\u002F8.9.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fblog2social.8.9.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fblog2social\u002Ftags"]