From 1822bbb4d43b5e4d64b40fecff886bb93b4b0715 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Fri, 12 Jun 2026 15:35:45 +0000 Subject: [PATCH] SanitizationHelperTrait: stop requiring unslash for functions that strip slashes The following functions implicitly strip backslashes from their input, so a preceding call to `wp_unslash()` (or a similar unslashing function) is not needed for the value to be safe: `esc_url_raw()`, `sanitize_email()`, `sanitize_file_name()`, `sanitize_hex_color()`, `sanitize_hex_color_no_hash()`, `sanitize_html_class()`, `sanitize_mime_type()`, `sanitize_sql_orderby()`, `sanitize_title()`, `sanitize_title_for_query()`, `sanitize_title_with_dashes()`, `sanitize_url()` and `wp_sanitize_redirect()`. They were previously listed in `$sanitizingFunctions`, which made the `WordPress.Security.ValidatedSanitizedInput` sniff incorrectly report a `MissingUnslash` error when one of them was used directly on superglobal data without unslashing it first. Moving them to `$unslashingSanitizingFunctions` fixes this false positive. Fixes 2516. --- WordPress/Helpers/SanitizationHelperTrait.php | 102 +++++++++--------- .../ValidatedSanitizedInputUnitTest.1.inc | 40 +++++++ 2 files changed, 91 insertions(+), 51 deletions(-) diff --git a/WordPress/Helpers/SanitizationHelperTrait.php b/WordPress/Helpers/SanitizationHelperTrait.php index 31661d169e..3361b18c55 100644 --- a/WordPress/Helpers/SanitizationHelperTrait.php +++ b/WordPress/Helpers/SanitizationHelperTrait.php @@ -78,47 +78,34 @@ trait SanitizationHelperTrait { * @var array */ private $sanitizingFunctions = array( - '_wp_handle_upload' => true, - 'esc_url_raw' => true, - 'filter_input' => true, - 'filter_var' => true, - 'hash_equals' => true, - 'is_email' => true, - 'number_format' => true, - 'sanitize_bookmark_field' => true, - 'sanitize_bookmark' => true, - 'sanitize_email' => true, - 'sanitize_file_name' => true, - 'sanitize_hex_color_no_hash' => true, - 'sanitize_hex_color' => true, - 'sanitize_html_class' => true, - 'sanitize_meta' => true, - 'sanitize_mime_type' => true, - 'sanitize_option' => true, - 'sanitize_sql_orderby' => true, - 'sanitize_term_field' => true, - 'sanitize_term' => true, - 'sanitize_text_field' => true, - 'sanitize_textarea_field' => true, - 'sanitize_title_for_query' => true, - 'sanitize_title_with_dashes' => true, - 'sanitize_title' => true, - 'sanitize_url' => true, - 'sanitize_user_field' => true, - 'sanitize_user' => true, - 'validate_file' => true, - 'wp_handle_sideload' => true, - 'wp_handle_upload' => true, - 'wp_kses_allowed_html' => true, - 'wp_kses_data' => true, - 'wp_kses_one_attr' => true, - 'wp_kses_post' => true, - 'wp_kses' => true, - 'wp_parse_id_list' => true, - 'wp_redirect' => true, - 'wp_safe_redirect' => true, - 'wp_sanitize_redirect' => true, - 'wp_strip_all_tags' => true, + '_wp_handle_upload' => true, + 'filter_input' => true, + 'filter_var' => true, + 'hash_equals' => true, + 'is_email' => true, + 'number_format' => true, + 'sanitize_bookmark_field' => true, + 'sanitize_bookmark' => true, + 'sanitize_meta' => true, + 'sanitize_option' => true, + 'sanitize_term_field' => true, + 'sanitize_term' => true, + 'sanitize_text_field' => true, + 'sanitize_textarea_field' => true, + 'sanitize_user_field' => true, + 'sanitize_user' => true, + 'validate_file' => true, + 'wp_handle_sideload' => true, + 'wp_handle_upload' => true, + 'wp_kses_allowed_html' => true, + 'wp_kses_data' => true, + 'wp_kses_one_attr' => true, + 'wp_kses_post' => true, + 'wp_kses' => true, + 'wp_parse_id_list' => true, + 'wp_redirect' => true, + 'wp_safe_redirect' => true, + 'wp_strip_all_tags' => true, ); /** @@ -137,16 +124,29 @@ trait SanitizationHelperTrait { * @var array */ private $unslashingSanitizingFunctions = array( - 'absint' => true, - 'boolval' => true, - 'count' => true, - 'doubleval' => true, - 'floatval' => true, - 'intval' => true, - 'rest_sanitize_boolean' => true, - 'sanitize_key' => true, - 'sanitize_locale_name' => true, - 'sizeof' => true, + 'absint' => true, + 'boolval' => true, + 'count' => true, + 'doubleval' => true, + 'esc_url_raw' => true, + 'floatval' => true, + 'intval' => true, + 'rest_sanitize_boolean' => true, + 'sanitize_email' => true, + 'sanitize_file_name' => true, + 'sanitize_hex_color_no_hash' => true, + 'sanitize_hex_color' => true, + 'sanitize_html_class' => true, + 'sanitize_key' => true, + 'sanitize_locale_name' => true, + 'sanitize_mime_type' => true, + 'sanitize_sql_orderby' => true, + 'sanitize_title_for_query' => true, + 'sanitize_title_with_dashes' => true, + 'sanitize_title' => true, + 'sanitize_url' => true, + 'sizeof' => true, + 'wp_sanitize_redirect' => true, ); /** diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc index e19f439248..06f50c99e2 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc @@ -624,3 +624,43 @@ function test_namespaced_unslashing_sanitizing_functions() { $key = namespace\Sub\sanitize_key( $_POST['unslash_sanitize5'] ); // Bad. } } + +/* + * Safeguard that sanitizing functions which implicitly unslash their input do not + * require an additional call to a dedicated unslashing function like wp_unslash(). + * + * See https://github.com/WordPress/WordPress-Coding-Standards/issues/2516 + */ +function test_sanitizing_functions_which_implicitly_unslash() { + if ( ! isset( + $_POST['esc_url_raw'], + $_POST['sanitize_email'], + $_POST['sanitize_file_name'], + $_POST['sanitize_hex_color'], + $_POST['sanitize_hex_color_no_hash'], + $_POST['sanitize_html_class'], + $_POST['sanitize_mime_type'], + $_POST['sanitize_sql_orderby'], + $_POST['sanitize_title'], + $_POST['sanitize_title_for_query'], + $_POST['sanitize_title_with_dashes'], + $_POST['sanitize_url'], + $_POST['wp_sanitize_redirect'] + ) ) { + return; + } + + echo esc_url_raw( $_POST['esc_url_raw'] ); // OK. + echo sanitize_email( $_POST['sanitize_email'] ); // OK. + echo sanitize_file_name( $_POST['sanitize_file_name'] ); // OK. + echo sanitize_hex_color( $_POST['sanitize_hex_color'] ); // OK. + echo sanitize_hex_color_no_hash( $_POST['sanitize_hex_color_no_hash'] ); // OK. + echo sanitize_html_class( $_POST['sanitize_html_class'] ); // OK. + echo sanitize_mime_type( $_POST['sanitize_mime_type'] ); // OK. + echo sanitize_sql_orderby( $_POST['sanitize_sql_orderby'] ); // OK. + echo sanitize_title( $_POST['sanitize_title'] ); // OK. + echo sanitize_title_for_query( $_POST['sanitize_title_for_query'] ); // OK. + echo sanitize_title_with_dashes( $_POST['sanitize_title_with_dashes'] ); // OK. + echo sanitize_url( $_POST['sanitize_url'] ); // OK. + echo wp_sanitize_redirect( $_POST['wp_sanitize_redirect'] ); // OK. +}