Make WordPress Core

Opened 3 weeks ago

Closed 3 weeks ago

Last modified 3 weeks ago

#62449 closed defect (bug) (invalid)

Bypassable Sanitization in the restfulAPI, which lead to the

Reported by: samjhuseclab's profile samjhuseclab Owned by:
Milestone: Priority: normal
Severity: normal Version:
Component: REST API Keywords:
Focuses: rest-api Cc:

Description

WordPress Core Potential Issue: JSONP Sanitization Bypass in wp_die

Overview

This document describes a potential sanitization bug in WordPress Core, specifically in the _jsonp_wp_die_handler function. The issue arises when a plugin uses the rest_jsonp_enabled filter to modify the _jsonp field after it has passed the wp_check_jsonp_callback validation. While this issue is not a direct security vulnerability, it reveals a sanitization flaw that can result in unexpected behavior.

Details

Affected Function: _jsonp_wp_die_handler

The _jsonp_wp_die_handler function uses the $_GET['_jsonp'] parameter to generate the JSONP callback name. The callback is directly output in the response without further validation after initial checks.

Key Code:

$jsonp_callback = $_GET['_jsonp'];
echo '/**/' . $jsonp_callback . '(' . $result . ');';

If the $_GET['_jsonp'] contains malicious or invalid characters, it may lead to unintended outputs.

Validation Process and the Problem

  1. Validation via wp_is_jsonp_request:
    • The function wp_is_jsonp_request validates $_GET['_jsonp'] using wp_check_jsonp_callback, ensuring the callback name only contains safe characters (alphanumeric, underscores, and dots).
    • Code:
      preg_replace('/[^\w\.]/', '', $callback, -1, $illegal_char_count);
      if ($illegal_char_count > 0) {
          return false;
      }
      
  1. The Problem:
    • After validation, the rest_jsonp_enabled filter is called:
      $jsonp_enabled = apply_filters('rest_jsonp_enabled', true);
      
    • At this stage, an attacker or a malicious plugin can modify $_GET['_jsonp'], bypassing the sanitization performed by wp_check_jsonp_callback.
  1. Potential Outcome:
    • The callback function name used in the response could contain unsanitized or unexpected values.
    • Example Output:
      /**/maliciousCallback({...});
      

Reproduction Steps

  1. Create a Plugin to Exploit the Issue:
    add_filter('rest_jsonp_enabled', function($enabled) {
        $_GET['_jsonp'] = 'maliciousCallback';
        return $enabled;
    });
    
  1. Trigger the Issue:
    • Send a request to any endpoint that invokes _jsonp_wp_die_handler:
      GET /wp-json?_jsonp=legitCallback
      
  1. Observe the Response:
    • Despite the original legitCallback passing validation, the plugin modifies it to:
      /**/maliciousCallback({...});
      

Impact

Risk Assessment

  • Threat Level: Low
  • Requirements for Exploitation:
    • A specific plugin must actively modify $_GET['_jsonp'] after validation.
  • Actual Output: A standard HTTP JSON response, albeit with a potentially unsanitized callback function.

Potential Implications

  • Data Integrity: The final output does not match the originally validated input.
  • Third-Party Plugin Behavior: Malicious plugins could abuse this to inject unexpected callback names.

Example Fix Code

Below is the updated version of the wp_is_jsonp_request function:

function wp_is_jsonp_request() {
    if (!isset($_GET['_jsonp'])) {
        return false;
    }

    $jsonp_callback = $_GET['_jsonp'];

    // Initial validation
    if (!wp_check_jsonp_callback($jsonp_callback)) {
        return false;
    }

    // Call filter
    $jsonp_enabled = apply_filters('rest_jsonp_enabled', true);

    // Revalidate after filter execution
    if ($jsonp_enabled) {
        $jsonp_callback_after_filter = $_GET['_jsonp'];
        if (!wp_check_jsonp_callback($jsonp_callback_after_filter)) {
            return false;
        }
    }

    return $jsonp_enabled;
}

Conclusion

This issue highlights a sanitization bug rather than a direct vulnerability. While the risk is low, fixing this behavior ensures that WordPress maintains robust input validation and output integrity, even in edge cases involving plugins and filters.

If JSONP functionality is no longer required, it is recommended to disable it entirely to mitigate any future risks.

Change History (2)

#1 follow-up: @johnbillion
3 weeks ago

  • Keywords changes-requested removed
  • Milestone Awaiting Review deleted
  • Resolution set to invalid
  • Status changed from new to closed
  • Version trunk deleted

Thanks for the report @samjhuseclab, but this issue depends on an attacker having the ability to insert malicious PHP code into a plugin. If they're able to do that then they're free to attack the site in any way they wish, which renders this issue moot. There are no doubt hundreds of places in WordPress where data and output passes through filters after sanitisation.

I'll close this ticket off. If you think there is another valid attack vector to this that doesn't involve the attacker having the ability to insert PHP that they control then please get in touch with the security team via HackerOne as per https://make.wordpress.org/core/handbook/testing/reporting-security-vulnerabilities/ . Thanks.

#2 in reply to: ↑ 1 @samjhuseclab
3 weeks ago

Replying to johnbillion:

Thanks for the report @samjhuseclab, but this issue depends on an attacker having the ability to insert malicious PHP code into a plugin. If they're able to do that then they're free to attack the site in any way they wish, which renders this issue moot. There are no doubt hundreds of places in WordPress where data and output passes through filters after sanitisation.

I'll close this ticket off. If you think there is another valid attack vector to this that doesn't involve the attacker having the ability to insert PHP that they control then please get in touch with the security team via HackerOne as per https://make.wordpress.org/core/handbook/testing/reporting-security-vulnerabilities/ . Thanks.

Hi John,

Thank you for your quick response and thoughtful explanation.

We understand your perspective that this issue assumes an attacker can insert malicious PHP code into a plugin. However, our primary concern is that the current WordPress core design might inadvertently enable scenarios where plugin developers—intentionally or unintentionally—introduce backdoors. This is because the triggering code appears benign within the plugin itself, while the actual sink functions that cause the issue reside in the Core code.

This creates a unique challenge: tools analyzing plugins in isolation are unlikely to detect such issues, as the problematic behavior only emerges when combined with the Core’s sink functions. This makes identifying and mitigating these risks significantly harder.

This issue can be addressed in the Core with just a few lines of additional code. By doing so, WordPress Core can become more robust against such scenarios, simplifying security audits for plugin developers.

Thank you again for your time and consideration!

Best regards,
Sam

Last edited 3 weeks ago by samjhuseclab (previous) (diff)
Note: See TracTickets for help on using tickets.