Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions WordPress/Helpers/ContextHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -355,9 +355,27 @@ public static function is_safe_casted( File $phpcsFile, $stackPtr ) {
return false;
}

$prev = $phpcsFile->findPrevious( Tokens::$emptyTokens, ( $stackPtr - 1 ), null, true );

return isset( self::$safe_casts[ $tokens[ $prev ]['code'] ] );
// Walk outward through surrounding grouping parentheses. A leading
// cast sanitizes the enclosed value whether or not there are
// intermediate parens / coalesce operators — e.g. both
// `(int) $_GET['x']` and `(int) ( $_GET['x'] ?? 0 )` yield an int.
// Stop at the first non-empty token that isn't an open parenthesis;
// function-call parens (preceded by T_STRING) fall through to the
// not-a-cast branch correctly.
$check = $stackPtr;
do {
$prev = $phpcsFile->findPrevious( Tokens::$emptyTokens, ( $check - 1 ), null, true );
if ( false === $prev ) {
return false;
}
if ( isset( self::$safe_casts[ $tokens[ $prev ]['code'] ] ) ) {
return true;
}
if ( \T_OPEN_PARENTHESIS !== $tokens[ $prev ]['code'] ) {
return false;
}
$check = $prev;
} while ( true );
}

/**
Expand Down
22 changes: 22 additions & 0 deletions WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc
Original file line number Diff line number Diff line change
Expand Up @@ -500,3 +500,25 @@ function test_in_match_condition_is_regarded_as_comparison() {
};
}
}

/*
* Type casts (int, float, bool) sanitize the enclosed value even when
* separated from the superglobal by grouping parentheses — e.g. the
* common `(int) ( $_GET['id'] ?? 0 )` idiom. Ref issue #2210.
*/
function test_cast_around_grouping_parens() {
$a = (int) ( $_POST['foo'] ?? 0 ); // OK.
$b = (int) ( $_GET['bar'] ?? 0 ); // OK.
$c = (bool) ( $_POST['flag'] ?? false ); // OK.
$d = (float) ( $_POST['rate'] ?? 0.0 ); // OK.
$e = (int) ( ( $_POST['n'] ?? 0 ) ); // OK — nested grouping parens.

// (string) is not in the safe-cast list, so this is still unsanitised.
$g = (string) ( $_POST['s'] ?? '' ); // Bad x 2 - unslash + sanitize.

// Array cast isn't treated as safe either.
$h = (array) ( $_POST['arr'] ?? array() ); // Bad x 2 - unslash + sanitize.

// Non-cast leading token: no rescue from the paren-walk.
$i = abs( $_POST['foo'] ?? 0 ); // Bad x 2 - unslash + sanitize.
}
3 changes: 3 additions & 0 deletions WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ public function getErrorList( $testFile = '' ) {
497 => 1,
498 => 1,
499 => 3,
517 => 2,
520 => 2,
523 => 2,
);

case 'ValidatedSanitizedInputUnitTest.2.inc':
Expand Down
Loading