Skip to content

Commit 5bbd1b9

Browse files
committed
Variables/ServerVariables: bug fix - faulty array key determination
The code to find the array index was flawed and could walk beyond the brackets of this array access. Additionally, array access keys comprised of multiple tokens were not handled correctly. Includes tests. Note: WordPressCS has helper functions to retrieve the array access name, but those are marked as internal, which is the reason to introduce a custom function.
1 parent d0362ed commit 5bbd1b9

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

WordPressVIPMinimum/Sniffs/Variables/ServerVariablesSniff.php

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,12 @@ public function process_token( $stackPtr ) {
6666
return;
6767
}
6868

69-
$indexPtr = $this->phpcsFile->findNext( [ T_CONSTANT_ENCAPSED_STRING ], $stackPtr + 1, null, false, null, true );
69+
$indexPtr = $this->get_array_access_key( $stackPtr );
70+
if ( $indexPtr === false ) {
71+
// Couldn't find an array index token usable for the purposes of this sniff. Bow out as undetermined.
72+
return;
73+
}
74+
7075
$indexName = TextStrings::stripQuotes( $this->tokens[ $indexPtr ]['content'] );
7176

7277
if ( isset( $this->restrictedVariables['authVariables'][ $indexName ] ) ) {
@@ -78,4 +83,45 @@ public function process_token( $stackPtr ) {
7883
$this->phpcsFile->addError( $message, $stackPtr, 'UserControlledHeaders', $data );
7984
}
8085
}
86+
87+
/**
88+
* Get the array access key.
89+
*
90+
* Find the array access key and check if it is:
91+
* - comprised of a single functional token.
92+
* - that token is a T_CONSTANT_ENCAPSED_STRING.
93+
*
94+
* @param int $stackPtr The position of either a variable or the close bracket of a previous array access.
95+
*
96+
* @return int|false Stack pointer to the index token; or FALSE for
97+
* live coding, non-indexed array assignment, or non plain text array keys.
98+
*/
99+
private function get_array_access_key( $stackPtr ) {
100+
$openBracket = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true );
101+
if ( $openBracket === false
102+
|| $this->tokens[ $openBracket ]['code'] !== T_OPEN_SQUARE_BRACKET
103+
|| isset( $this->tokens[ $openBracket ]['bracket_closer'] ) === false
104+
) {
105+
// If it isn't an open bracket, this isn't array access. And without closer, it is a parse error/live coding.
106+
return false;
107+
}
108+
109+
$closeBracket = $this->tokens[ $openBracket ]['bracket_closer'];
110+
111+
$indexPtr = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $openBracket + 1 ), $closeBracket, true );
112+
if ( $indexPtr === false
113+
|| $this->tokens[ $indexPtr ]['code'] !== T_CONSTANT_ENCAPSED_STRING
114+
) {
115+
// No array access (like for array assignment without key) or key is not plain text.
116+
return false;
117+
}
118+
119+
$hasOtherTokens = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $indexPtr + 1 ), $closeBracket, true );
120+
if ( $hasOtherTokens !== false ) {
121+
// The array index is comprised of multiple tokens. Bow out as undetermined.
122+
return false;
123+
}
124+
125+
return $indexPtr;
126+
}
81127
}

WordPressVIPMinimum/Tests/Variables/ServerVariablesUnitTest.inc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,9 @@ class PeopleDoSillyThings extends AllowedByPHP {
5555
var_export(OtherClass::$_SERVER['HTTP_X_IP_TRAIL']);
5656
}
5757
}
58+
59+
// Safeguard the sniff looks at the access key for the $_SERVER variable only and doesn't walk too far.
60+
echo $_SERVER[$other_key] . $NOT_SERVER['PHP_AUTH_PW'];
61+
62+
// Safeguard the sniff doesn't get confused over partially dynamic keys.
63+
echo $_SERVER[$other_key . 'PHP_AUTH_PW'];

0 commit comments

Comments
 (0)