diff --git a/WordPressVIPMinimum/Sniffs/Security/PHPFilterFunctionsSniff.php b/WordPressVIPMinimum/Sniffs/Security/PHPFilterFunctionsSniff.php index 32e9f7a9..77dd1f47 100644 --- a/WordPressVIPMinimum/Sniffs/Security/PHPFilterFunctionsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Security/PHPFilterFunctionsSniff.php @@ -12,6 +12,7 @@ use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Utils\PassedParameters; use WordPressCS\WordPress\AbstractFunctionParameterSniff; +use WordPressCS\WordPress\Helpers\RulesetPropertyHelper; /** * This sniff ensures that proper sanitization is occurring when PHP's filter_* functions are used. @@ -65,6 +66,28 @@ class PHPFilterFunctionsSniff extends AbstractFunctionParameterSniff { 'FILTER_UNSAFE_RAW' => true, ]; + /** + * Filter names to exclude from the list of restricted filters. + * + * This allows a developer who knowingly uses a non-sanitizing filter (for + * example, when they sanitize the value themselves afterwards) to prevent + * the sniff from flagging it, without having to redeclare the full list. + * + * Set this from a custom ruleset, for example to allow `FILTER_UNSAFE_RAW`: + * + * + * + * + * + * + * + * + * + * + * @var array + */ + public $exclude_filters = []; + /** * Process the parameters of a matched function. * @@ -118,7 +141,13 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p return; } - if ( isset( $this->restricted_filters[ $target_param['clean'] ] ) ) { + // Recalculated on each call so an inline change to the `exclude_filters` property is respected. + $restricted_filters = array_diff_key( + $this->restricted_filters, + RulesetPropertyHelper::merge_custom_array( $this->exclude_filters ) + ); + + if ( isset( $restricted_filters[ $target_param['clean'] ] ) ) { $first_non_empty = $this->phpcsFile->findNext( Tokens::$emptyTokens, $target_param['start'], ( $target_param['end'] + 1 ), true ); $message = 'Please use an appropriate filter to sanitize, as "%s" does no filtering, see: http://php.net/manual/en/filter.filters.sanitize.php.'; diff --git a/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.inc b/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.inc index 0159aac5..ee7c0927 100644 --- a/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.inc @@ -98,3 +98,13 @@ filter_input_array( ], ] ); + +/* + * Bug #753: the list of restricted filters can be reduced via the `exclude_filters` property. + */ +$excludable = filter_input( INPUT_POST, 'a', FILTER_UNSAFE_RAW ); // Warning RestrictedFilter. + +// phpcs:set WordPressVIPMinimum.Security.PHPFilterFunctions exclude_filters[] FILTER_UNSAFE_RAW +$excluded = filter_input( INPUT_POST, 'b', FILTER_UNSAFE_RAW ); // OK - excluded via the property. +$still_restricted = filter_var( $value, FILTER_DEFAULT ); // Warning RestrictedFilter - other defaults still apply. +// phpcs:set WordPressVIPMinimum.Security.PHPFilterFunctions exclude_filters[] diff --git a/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.php b/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.php index 1faa0728..7a53bcd3 100644 --- a/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.php @@ -32,24 +32,26 @@ public function getErrorList() { */ public function getWarningList() { return [ - 44 => 1, - 45 => 1, - 46 => 1, - 48 => 1, - 49 => 1, - 50 => 1, - 52 => 1, - 53 => 1, - 54 => 1, - 56 => 1, - 57 => 1, - 58 => 1, - 65 => 1, - 70 => 1, - 71 => 1, - 73 => 1, - 75 => 1, - 81 => 1, + 44 => 1, + 45 => 1, + 46 => 1, + 48 => 1, + 49 => 1, + 50 => 1, + 52 => 1, + 53 => 1, + 54 => 1, + 56 => 1, + 57 => 1, + 58 => 1, + 65 => 1, + 70 => 1, + 71 => 1, + 73 => 1, + 75 => 1, + 81 => 1, + 105 => 1, + 109 => 1, ]; } }