Opened 5 weeks ago
Last modified 13 days ago
#65054 assigned defect (bug)
$_GET['pagenow'] and $_GET['widget'] unsanitized in dashboard AJAX handler
| Reported by: |
|
Owned by: |
|
|---|---|---|---|
| Milestone: | Awaiting Review | Priority: | normal |
| Severity: | normal | Version: | trunk |
| Component: | Security | Keywords: | has-patch needs-testing has-test-info has-unit-tests |
| Focuses: | Cc: |
Attachments (1)
Change History (9)
This ticket was mentioned in PR #11540 on WordPress/wordpress-develop by @rajeshcp.
5 weeks ago
#1
#2
@
3 weeks ago
- Keywords has-test-info added
Test Report: Input Sanitization for pagenow in AJAX Actions
Summary
Verification of the sanitization vulnerability in wp_ajax_dashboard_widgets() where the pagenow parameter was being used without proper filtering. This report demonstrates the effectiveness of applying sanitize_key() to prevent variable pollution.
Environment
WordPress Version: 7.0-beta1-61709-src
PHP Version: 7.4 / 8.x
Area: AJAX / Dashboard
Reproduction Steps
Using the Browser Developer Tools (Console), a "polluted" request was sent to the dashboard-widgets action containing uppercase letters, special characters, and spaces.
Payload:
JavaScript
jQuery.get( ajaxurl, {
action: 'dashboard-widgets',
pagenow: 'DashBoard_!!!_For_Test',
widget: 'dashboard_primary'
});
Code Implementation (Testing Patch)
The following debug code was inserted into wp-admin/includes/ajax-actions.php to compare the raw input against the sanitized output:
PHP
<?php function wp_ajax_dashboard_widgets() { require_once ABSPATH . 'wp-admin/includes/dashboard.php'; $raw_pagenow = $_GET['pagenow']; $pagenow = isset( $_GET['pagenow'] ) ? sanitize_key( $_GET['pagenow'] ) : ''; error_log( "--- Audit Start ---" ); error_log( "Raw Input: [" . $raw_pagenow . "]" ); error_log( "Sanitized: [" . $pagenow . "]" ); error_log( "--- Audit End ---" ); // Subsequent logic... }
Test Results (debug.log)
The logs confirm that while the raw input contained unsafe characters, sanitize_key() correctly normalized the string according to WordPress standards.
Plaintext
[20-Apr-2026 05:01:41 UTC] --- Audit Start --- [20-Apr-2026 05:01:41 UTC] Raw Input: [DashBoard_!!!_For_Test] [20-Apr-2026 05:01:41 UTC] Sanitized: [dashboard__for_test] [20-Apr-2026 05:01:41 UTC] --- Audit End ---
Discussion & Conclusion
Variable Consistency: The sanitized value dashboardfor_test removes the risk of inconsistent logic handling caused by case sensitivity (e.g., DashBoard vs dashboard).
Security Posture: Removing special characters (!!!) prevents the variable from being used as a vector for path traversal or other injection attacks if the variable is passed to other core functions in the future.
Recommendation: The patch to include sanitize_key() should be merged to align this function with the defensive coding standards seen in other AJAX handlers like wp_ajax_meta_box_order().
The same on $widget
#3
@
3 weeks ago
Note on Defensive Coding:
While current logic employs validation via strict comparisons, applying sanitize_key() to pagenow and widget is a necessary Defense in Depth measure.
Unsanitized input creates several long-term risks:
Downstream Vulnerabilities: Prevents potential Reflected XSS if these variables are later used in logging, dynamic hooks, or UI output by core or third-party plugins.
Cache Pollution: Normalizing these inputs prevents "cache bloating" in environments using Object Caching (Redis/Memcached), where randomized strings could be used as keys to exhaust memory.
Attack Surface Reduction: Early sanitization ensures that the variables are "normalized" (lowercase and alphanumeric) before they enter the internal logic, mitigating risks like Path Traversal in future refactors.
This hardening aligns the function with the security standards seen in other AJAX handlers like wp_ajax_meta_box_order().
#4
@
3 weeks ago
- Severity changed from major to normal
Do not report "major" security issues in Trac. Use HackerOne instead.
Regardless, this seems to be a hardening not an exploitable vulnerability. (And if it is, do not disclose so here publicly.)
#5
@
3 weeks ago
See also: Reporting Security Vulnerabilities
#6
@
3 weeks ago
Understood.
The goal of this report is simply to provide test evidence for @rajeshcp's patch, ensuring consistent sanitization across AJAX handlers as a best practice. I will keep the HackerOne process in mind for any future security-related findings.
This ticket was mentioned in PR #11661 on WordPress/wordpress-develop by @liaison.
2 weeks ago
#7
Description
This PR improves the security and reliability of dashboard widget updates via AJAX.
Input Sanitization: Adds sanitize_key() to both pagenow and widget parameters in wp_ajax_dashboard_widgets(). This ensures that only valid keys are processed, preventing potential path traversal or unexpected input issues.
Consistent Global State: Explicitly calls set_current_screen( $_GETpagenow? ) before processing the widget logic. This is crucial because, in an AJAX context, the global screen state might be uninitialized or polluted by other global variables (like $post), which can cause certain dashboard widgets (especially those relying on RSS feeds) to fail or behave inconsistently.
These changes ensure that the AJAX request environment closely mirrors a standard dashboard page load, improving compatibility with various WordPress environments and preventing common failures in PHPUnit testing environments where global state pollution is frequent.
Trac ticket: https://core.trac.wordpress.org/ticket/65054
Use of AI Tools
AI assistance: Yes
Tool(s): Gemini
Model(s): Gemini 3 Flash
Used for: Assisted in debugging the PHPUnit test case, specifically regarding output buffering (ob_start) issues and WPAjaxDieException handling within the WP_Ajax_UnitTestCase framework. The final implementation and test logic were reviewed and manually adjusted by me to fit WordPress Core standards.
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

$_GETpagenow? and $_GETwidget? unsanitized in dashboard AJAX handler
Both values are read directly without sanitize_key(). While the switch/comparison limits damage, unsanitized
Trac ticket: https://core.trac.wordpress.org/ticket/65054
Fixes #65054
## Use of AI Tools