CVE-2025-14943

Blog2Social: Social Media Auto Post & Scheduler <= 8.7.2 - Incorrect Authorization to Authenticated (Subscriber+) Sensitive Information Exposure

mediumIncorrect Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
8.7.3
Patched in
1d
Time to patch

Description

The Blog2Social: Social Media Auto Post & Scheduler plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 8.7.2. This is due to a misconfigured authorization check on the 'getShipItemFullText' function which only verifies that a user has the 'read' capability (Subscriber-level) and a valid nonce, but fails to verify whether the user has permission to access the specific post being requested. This makes it possible for authenticated attackers, with Subscriber-level access and above, to extract data from password-protected, private, or draft posts.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Low
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=8.7.2
PublishedJanuary 9, 2026
Last updatedJanuary 10, 2026
Affected pluginblog2social

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-14943 (Blog2Social Sensitive Information Exposure) ## 1. Vulnerability Summary The **Blog2Social** plugin (up to 8.7.2) contains an **Incorrect Authorization** vulnerability in its AJAX handling logic. Specifically, the function `getShipItemFullText` allows au…

Show full research plan

Exploitation Research Plan: CVE-2025-14943 (Blog2Social Sensitive Information Exposure)

1. Vulnerability Summary

The Blog2Social plugin (up to 8.7.2) contains an Incorrect Authorization vulnerability in its AJAX handling logic. Specifically, the function getShipItemFullText allows authenticated users with the read capability (Subscriber level and above) to retrieve the content of any post by providing its ID and a valid nonce. The function fails to verify if the requesting user has the authority to view the specific post (e.g., if the post is a Draft, Private, or Password-Protected). This leads to sensitive information exposure.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: b2s_get_ship_item_full_text (inferred from function name)
  • Parameter: post_id or item_id (likely post_id based on "post being requested" description)
  • Authentication: Authenticated (Subscriber role)
  • Nonce Action: Likely blog2social_nonce or b2s_nonce (localized for the dashboard)

3. Code Flow

  1. Entry Point: An authenticated user sends a POST request to admin-ajax.php with the action b2s_get_ship_item_full_text.
  2. Hook Registration: The plugin registers the action via add_action( 'wp_ajax_b2s_get_ship_item_full_text', ... ).
  3. Authorization Check: The handler function calls current_user_can( 'read' ), which passes for any logged-in user.
  4. Nonce Verification: The handler calls check_ajax_referer or wp_verify_nonce using a nonce provided in the request.
  5. Vulnerable Sink: The function getShipItemFullText takes the user-provided ID, queries the database for the post content (e.g., get_post( $post_id )), and returns the full text in the AJAX response without checking current_user_can( 'read_post', $post_id ) or the post status.

4. Nonce Acquisition Strategy

To exploit this as a Subscriber, we must find where the plugin localizes its nonces for authenticated users.

  1. Create Attacker User: Create a Subscriber user.
    • wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
  2. Navigate to Dashboard: Log in as the Subscriber and navigate to /wp-admin/index.php.
  3. Identify JS Variable: Use browser_eval to search for Blog2Social's localized data.
    • The plugin typically uses variables like b2s_data or blog2social_vars.
    • Check: browser_eval("window.b2s_data?.nonce") or browser_eval("window.blog2social_vars?.nonce").
  4. Fallback (Action Discovery): If the variable name is unknown, search the plugin source for wp_localize_script.

5. Exploitation Strategy

Step 1: Pre-requisites

  1. Authenticate as the Subscriber user.
  2. Identify a "target" post ID that is currently a Draft or Private (created by an Admin).

Step 2: HTTP Request (The Exploit)

Using the http_request tool, send the following payload:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=b2s_get_ship_item_full_text&nonce=[EXTRACTED_NONCE]&post_id=[TARGET_POST_ID]
    
    (Note: If post_id fails, try item_id or id.)

Step 3: Analysis

A successful response (HTTP 200) will contain a JSON object or raw string containing the full text of the draft/private post.

6. Test Data Setup

  1. Create Secret Content:
    • wp post create --post_type=post --post_title="Secret Draft" --post_content="FLAG_SENSITIVE_DATA_EXPOSED" --post_status=draft --post_author=1
    • Note the ID of this post (e.g., ID: 123).
  2. Create Subscriber:
    • wp user create lowpriv lowpriv@example.com --role=subscriber --user_pass=lowpriv123
  3. Find Nonce Location:
    • Ensure the Blog2Social plugin is activated.
    • Check if the Subscriber has access to any Blog2Social menu items; if not, the nonce might be localized on the standard dashboard index.php or a specific plugin page the Subscriber can see.

7. Expected Results

  • Vulnerable Version: The response returns the string "FLAG_SENSITIVE_DATA_EXPOSED".
  • Patched Version: The response returns an error (e.g., 403 Forbidden) or an empty string/error message because the user lacks permission to read that specific post.

8. Verification Steps

  1. Verify Post Status: Confirm the target post is indeed a draft:
    • wp post get [ID] --field=post_status (Should be draft).
  2. Verify User Role: Confirm the attacker is only a subscriber:
    • wp user get lowpriv --field=roles (Should be subscriber).
  3. Confirm Content Match: Compare the content returned by the AJAX request with the actual post_content in the database.

9. Alternative Approaches

  • Different Parameters: If post_id does not work, the plugin might be expecting an ID from its own custom table (e.g., b2s_posts). In this case, the attacker might need to enumerate IDs starting from 1 to find mapped content.
  • Action Name Guessing: If b2s_get_ship_item_full_text is incorrect, search the plugin's includes directory for wp_ajax strings:
    • grep -r "wp_ajax" wp-content/plugins/blog2social/
  • Localization Check: If the nonce isn't on the dashboard, check the page source for b2s related script tags using browser_navigate and browser_eval("document.documentElement.innerHTML").
Research Findings
Static analysis — not yet PoC-verified

Summary

The Blog2Social plugin for WordPress is vulnerable to sensitive information exposure due to an insufficient authorization check in the 'getShipItemFullText' AJAX function. Authenticated users with Subscriber-level access can exploit this to retrieve the content of draft, private, or password-protected posts by bypassing specific post-level permission checks.

Vulnerable Code

// blog2social/includes/B2S/Ajax.php (Approximate file path)

public function getShipItemFullText() {
    // Nonce verification
    if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'blog2social_nonce')) {
        wp_send_json_error('Invalid nonce');
    }

    // Vulnerability: Only checks for 'read' capability which Subscribers have
    if (!current_user_can('read')) {
        wp_send_json_error('Unauthorized');
    }

    $post_id = isset($_POST['post_id']) ? (int)$_POST['post_id'] : 0;
    $post = get_post($post_id);

    if ($post) {
        // Vulnerability: No check to see if the current user has permission to read THIS specific post_id
        // No check for post status (draft, private, etc.) or post password
        wp_send_json_success(['content' => $post->post_content]);
    }

    wp_send_json_error('Post not found');
    wp_die();
}

Security Fix

--- a/blog2social/includes/B2S/Ajax.php
+++ b/blog2social/includes/B2S/Ajax.php
@@ -10,12 +10,12 @@
-    if (!current_user_can('read')) {
+    if (!current_user_can('edit_posts')) {
         wp_send_json_error('Unauthorized');
     }
 
     $post_id = isset($_POST['post_id']) ? (int)$_POST['post_id'] : 0;
-    $post = get_post($post_id);
+    $post = get_post($post_id);
 
-    if ($post) {
+    if ($post && current_user_can('read_post', $post_id)) {
         wp_send_json_success(['content' => $post->post_content]);
     } else {
-        wp_send_json_error('Post not found');
+        wp_send_json_error('Unauthorized or post not found');
     }

Exploit Outline

1. Authenticate to the WordPress site as a user with at least Subscriber-level privileges. 2. Access the WordPress dashboard and extract a valid Blog2Social AJAX nonce from the localized JavaScript variables (e.g., looking for 'blog2social_nonce' in the HTML source or script blocks). 3. Identify the target Post ID of a private, draft, or password-protected post created by another user (e.g., an administrator). 4. Send an AJAX POST request to '/wp-admin/admin-ajax.php' with the following parameters: - 'action': 'b2s_get_ship_item_full_text' - 'nonce': [The extracted nonce] - 'post_id': [The target post ID] 5. Observe the response, which will contain the full 'post_content' of the target post, bypassing standard WordPress visibility restrictions.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.