#62449 closed defect (bug) (invalid)
Bypassable Sanitization in the restfulAPI, which lead to the
Reported by: | 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
- Validation via
wp_is_jsonp_request
:- The function
wp_is_jsonp_request
validates$_GET['_jsonp']
usingwp_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; }
- The function
- 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 bywp_check_jsonp_callback
.
- After validation, the
- Potential Outcome:
- The callback function name used in the response could contain unsanitized or unexpected values.
- Example Output:
/**/maliciousCallback({...});
Reproduction Steps
- Create a Plugin to Exploit the Issue:
add_filter('rest_jsonp_enabled', function($enabled) { $_GET['_jsonp'] = 'maliciousCallback'; return $enabled; });
- Trigger the Issue:
- Send a request to any endpoint that invokes
_jsonp_wp_die_handler
:GET /wp-json?_jsonp=legitCallback
- Send a request to any endpoint that invokes
- Observe the Response:
- Despite the original
legitCallback
passing validation, the plugin modifies it to:/**/maliciousCallback({...});
- Despite the original
Impact
Risk Assessment
- Threat Level: Low
- Requirements for Exploitation:
- A specific plugin must actively modify
$_GET['_jsonp']
after validation.
- A specific plugin must actively modify
- 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:
↓ 2
@
3 weeks ago
- Keywords changes-requested removed
- Milestone Awaiting Review deleted
- Resolution set to invalid
- Status changed from new to closed
- Version trunk deleted
#2
in reply to:
↑ 1
@
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
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.