CVE-2026-4330

Blog2Social: Social Media Auto Post & Scheduler <= 8.8.3 - Authenticated (Subscriber+) Insecure Direct Object Reference to Arbitrary Post Schedule Modification via 'b2s_id' Parameter

mediumAuthorization Bypass Through User-Controlled Key
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
8.8.4
Patched in
1d
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=8.8.3
PublishedApril 7, 2026
Last updatedApril 8, 2026
Affected pluginblog2social

What Changed in the Fix

Changes introduced in v8.8.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

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:** 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 (or postId) parameter in multiple AJAX handlers.
  • Root Cause: The plugin's AJAX handlers (specifically those handling UPDATE and DELETE operations 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 in curation.draft.js)
    • b2s_re_post_submit (Verified in repost.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) or b2s_re_post_submit (Modify).
    • postId or b2s_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_posts database table (created by an Administrator).

3. Code Flow (Trace)

  1. Client-Side Trigger: In assets/js/b2s/curation.draft.js, a click on .b2s-delete-cc-draft-confirm-btn triggers an AJAX request.
  2. 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()
        },
        // ...
    });
    
  3. Server-Side Processing (Vulnerable Logic):
    • The PHP handler for wp_ajax_b2s_delete_user_cc_draft_post is called.
    • It checks check_ajax_referer('b2s-security-nonce', 'b2s_security_nonce').
    • It retrieves $_POST['postId'].
    • It performs a SQL DELETE query: DELETE FROM {$wpdb->prefix}b2s_posts WHERE id = %d without appending AND user_id = %d.

4. Nonce Acquisition Strategy

The nonce is localized to an input field #b2s_security_nonce or a JS variable.

  1. Create a Subscriber User: Use WP-CLI to create a Subscriber.
  2. 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.
  3. Check Access: Test if a Subscriber can access wp-admin/admin.php?page=blog2social-dashboard.
  4. Extract Nonce:
    • Navigate to the Dashboard.
    • Use browser_eval to 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:
    action=b2s_re_post_submit&b2s_id=[VICTIM_POST_ID]&b2s_security_nonce=[EXTRACTED_NONCE]&...[OTHER_REQUIRED_FIELDS]
    
    (Note: Modification might require more parameters found in the serialized form in repost.js).

6. Test Data Setup

  1. 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
    
  2. 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 on curation.draft.js success handler).
  • Database Change: The record with the victim's ID should be removed from the wp_b2s_posts table despite the request being sent by a Subscriber.

8. Verification Steps

  1. Check Database:
    wp db query "SELECT * FROM wp_b2s_posts WHERE post_title = 'Admin Scheduled Post'"
    
    Success Criteria: The query returns no results.
  2. 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-dashboard is blocked, check wp-admin/profile.php to see if b2s_security_nonce is enqueued there. Many B2S versions enqueued assets on all admin pages.
Research Findings
Static analysis — not yet PoC-verified

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

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/blog2social/8.8.3/includes/Ajax/Get.php /home/deploy/wp-safety.org/data/plugin-versions/blog2social/8.8.4/includes/Ajax/Get.php
--- /home/deploy/wp-safety.org/data/plugin-versions/blog2social/8.8.3/includes/Ajax/Get.php	2026-03-23 13:17:40.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/blog2social/8.8.4/includes/Ajax/Get.php	2026-03-30 11:59:54.000000000 +0000
@@ -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();
             }
             
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/blog2social/8.8.3/includes/Ajax/Post.php /home/deploy/wp-safety.org/data/plugin-versions/blog2social/8.8.4/includes/Ajax/Post.php
--- /home/deploy/wp-safety.org/data/plugin-versions/blog2social/8.8.3/includes/Ajax/Post.php	2026-03-23 13:17:40.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/blog2social/8.8.4/includes/Ajax/Post.php	2026-03-30 11:59:54.000000000 +0000
@@ -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.