diff --git a/tests/TaintTest.php b/tests/TaintTest.php
index 9ee55d4a1..42366bd10 100644
--- a/tests/TaintTest.php
+++ b/tests/TaintTest.php
@@ -7,1891 +7,1221 @@ use Psalm\Context;
class TaintTest extends TestCase
{
/**
+ * @dataProvider providerValidCodeParse
+ *
+ * @param string $code
+ *
* @return void
*/
- public function testTaintedInputFromMethodReturnTypeSimple()
+ public function testValidCode(string $code)
{
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
+ $test_name = $this->getTestName();
+ if (\strpos($test_name, 'SKIPPED-') !== false) {
+ $this->markTestSkipped('Skipped due to a bug.');
+ }
+
+ $file_path = self::$src_dir_path . 'somefile.php';
+
+ $this->addFile(
+ $file_path,
+ $code
+ );
$this->project_analyzer->trackTaintedInputs();
- $this->addFile(
- 'somefile.php',
- 'getUserId();
- }
-
- public function deleteUser(PDO $pdo) : void {
- $userId = $this->getAppendedUserId();
- $pdo->exec("delete from users where user_id = " . $userId);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
+ $this->analyzeFile($file_path, new Context(), false);
}
/**
+ * @dataProvider providerInvalidCodeParse
+ *
+ * @param string $code
+ * @param string $error_message
+ *
* @return void
*/
- public function testTaintedInputFromFunctionReturnType()
+ public function testInvalidCode(string $code, string $error_message)
{
+ if (\strpos($this->getTestName(), 'SKIPPED-') !== false) {
+ $this->markTestSkipped();
+ }
+
$this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput - somefile.php:6:22 - Detected tainted html in path: $_GET -> $_GET[\'name\'] (somefile.php:3:28) -> getname (somefile.php:6:22) -> call to echo (somefile.php:6:22) -> echo#1');
+ $this->expectExceptionMessageRegExp('/\b' . \preg_quote($error_message, '/') . '\b/');
+
+ $file_path = self::$src_dir_path . 'somefile.php';
+
+ $this->addFile(
+ $file_path,
+ $code
+ );
$this->project_analyzer->trackTaintedInputs();
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
+ $this->analyzeFile($file_path, new Context(), false);
}
/**
- * @return void
+ * @return array
*/
- public function testTaintedInputFromExplicitTaintSource()
+ public function providerValidCodeParse()
{
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
+ return [
+ 'taintedInputInCreatedArrayNotEchoed' => [
+ 'project_analyzer->trackTaintedInputs();
+ $data = ["name" => $name, "id" => $id];
- $this->addFile(
- 'somefile.php',
- '" . htmlentities($data["name"]) . "";
+ echo "
" . $data["id"] . "
";'
+ ],
+ 'taintedInputInAssignedArrayNotEchoed' => [
+ 'analyzeFile('somefile.php', new Context());
+ echo "" . htmlentities($data["name"]) . "
";
+ echo "" . $data["id"] . "
";'
+ ],
+ 'taintedInputDirectlySuppressed' => [
+ 'exec("delete from users where user_id = " . $userId);
+ }
+ }'
+ ],
+ 'taintedInputDirectlySuppressedWithOtherUse' => [
+ 'exec("delete from users where user_id = " . $userId);
+ }
+
+ public function deleteUserSafer(PDOWrapper $pdo) : void {
+ $userId = $this->getSafeId();
+ $pdo->exec("delete from users where user_id = " . $userId);
+ }
+
+ public function getSafeId() : string {
+ return "5";
+ }
+ }
+
+ class PDOWrapper {
+ /**
+ * @psalm-taint-sink sql $sql
+ */
+ public function exec(string $sql) : void {}
+ }'
+ ],
+ 'taintedInputToParamButSafe' => [
+ 'deleteUser(
+ $pdo,
+ $this->getAppendedUserId((string) $_GET["user_id"])
+ );
+ }
+
+ public function getAppendedUserId(string $user_id) : string {
+ return "aaa" . $user_id;
+ }
+
+ public function deleteUser(PDO $pdo, string $userId) : void {
+ $userId2 = strlen($userId);
+ $pdo->exec("delete from users where user_id = " . $userId2);
+ }
+ }'
+ ],
+ 'ValidatedInputFromParam' => [
+ 'getUserId();
+ validateUserId($userId);
+ $this->deleteUser($pdo, $userId);
+ }
+
+ public function deleteUser(PDO $pdo, string $userId) : void {
+ $pdo->exec("delete from users where user_id = " . $userId);
+ }
+ }'
+ ],
+ 'untaintedInput' => [
+ 'getUserId();
+ }
+
+ public function deleteUser(PDO $pdo) : void {
+ $userId = $this->getAppendedUserId();
+ $pdo->exec("delete from users where user_id = " . $userId);
+ }
+ }'
+ ],
+ 'specializedCoreFunctionCall' => [
+ ' [
+ ' [
+ ' [
+ 's = (string) $_GET["FOO"];
+ }
+ }
+
+ class V1 extends V {
+ public function foo(O1 $o) : void {
+ echo U::shorten($o->s);
+ }
+ }'
+ ],
+ 'taintOnPregReplaceCallRemovedInFunction' => [
+ 's = (string) $_GET["FOO"];
+ }
+ }
+
+ class V1 extends V {
+ public function foo(O1 $o) : void {
+ echo U::shorten($o->s);
+ }
+ }'
+ ],
+ 'taintOnStrReplaceCallRemovedInline' => [
+ 's = (string) $_GET["FOO"];
+ }
+ }
+
+ class V1 extends V {
+ public function foo(O1 $o) : void {
+ /**
+ * @psalm-taint-escape html
+ */
+ $a = str_replace("foo", "bar", $o->s);
+ echo $a;
+ }
+ }'
+ ],
+ 'NoTaintsOnSimilarPureCall' => [
+ 's = $s;
+ }
+ }
+
+ class O2 {
+ public string $t;
+
+ public function __construct() {
+ $this->t = (string) $_GET["FOO"];
+ }
+ }
+
+ class V1 {
+ public function foo() : void {
+ $o = new O1((string) $_GET["FOO"]);
+ echo U::escape(U::shorten($o->s));
+ }
+ }
+
+ class V2 {
+ public function foo(O2 $o) : void {
+ echo U::shorten(U::escape($o->t));
+ }
+ }'
+ ],
+ 'taintPropertyPassingObjectWithDifferentValue' => [
+ 'id = $userId;
+ }
+ }
+
+ class UserUpdater {
+ public static function doDelete(PDO $pdo, User $user) : void {
+ self::deleteUser($pdo, $user->name);
+ }
+
+ public static function deleteUser(PDO $pdo, string $userId) : void {
+ $pdo->exec("delete from users where user_id = " . $userId);
+ }
+ }
+
+ $userObj = new User((string) $_GET["user_id"]);
+ UserUpdater::doDelete(new PDO(), $userObj);'
+ ],
+ 'taintPropertyWithoutPassingObject' => [
+ 'id = $userId;
+ }
+ }
+
+ class UserUpdater {
+ public static function doDelete(PDO $pdo, User $user) : void {
+ self::deleteUser($pdo, $user->id);
+ }
+
+ public static function deleteUser(PDO $pdo, string $userId) : void {
+ $pdo->exec("delete from users where user_id = " . $userId);
+ }
+ }
+
+ $userObj = new User((string) $_GET["user_id"]);',
+ ],
+ 'specializeStaticMethod' => [
+ 'expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
+ return [
+ 'taintedInputFromMethodReturnTypeSimple' => [
+ 'project_analyzer->trackTaintedInputs();
+ public function getAppendedUserId() : string {
+ return "aaaa" . $this->getUserId();
+ }
- $this->addFile(
- 'somefile.php',
- 'getAppendedUserId();
+ $pdo->exec("delete from users where user_id = " . $userId);
+ }
+ }',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintedInputFromFunctionReturnType' => [
+ ' 'TaintedInput - src/somefile.php:6:26 - Detected tainted html in path: $_GET -> $_GET[\'name\'] (src/somefile.php:3:32) -> getname (src/somefile.php:6:26) -> call to echo (src/somefile.php:6:26) -> echo#1',
+ ],
+ 'taintedInputFromExplicitTaintSource' => [
+ 'analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputFromGetArray()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputFromReturnToInclude()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputFromReturnToEval()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputFromReturnTypeToEcho()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'getUserId();
- }
-
- public function deleteUser(PDO $pdo) : void {
- $userId = $this->getAppendedUserId();
- echo $userId;
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputInCreatedArrayNotEchoed()
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- ' $name, "id" => $id];
-
- echo "" . htmlentities($data["name"]) . "
";
- echo "" . $data["id"] . "
";'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputInCreatedArrayIsEchoed()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- ' $name];
-
- echo "" . $data["name"] . "
";'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputInAssignedArrayNotEchoed()
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- '" . htmlentities($data["name"]) . "";
- echo "" . $data["id"] . "
";'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputInAssignedArrayIsEchoed()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- '" . $data["name"] . "";'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputDirectly()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'exec("delete from users where user_id = " . $userId);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputDirectlySuppressed()
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'exec("delete from users where user_id = " . $userId);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputDirectlySuppressedWithOtherUse()
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- ' 'TaintedInput',
+ ],
+ 'taintedInputFromExplicitTaintSourceStaticMethod' => [
+ 'exec("delete from users where user_id = " . $userId);
+ public static function getName() : string {
+ return "";
+ }
}
- public function deleteUserSafer(PDOWrapper $pdo) : void {
- $userId = $this->getSafeId();
- $pdo->exec("delete from users where user_id = " . $userId);
+
+ echo Request::getName();',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintedInputFromGetArray' => [
+ 'analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputFromReturnTypeWithBranch()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'getUserId();
-
- if (rand(0, 1)) {
- $userId .= "aaa";
- } else {
- $userId .= "bb";
+ echo $name;',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintedInputFromReturnToInclude' => [
+ ' 'TaintedInput',
+ ],
+ 'taintedInputFromReturnToEval' => [
+ ' 'TaintedInput',
+ ],
+ 'taintedInputFromReturnTypeToEcho' => [
+ 'getUserId();
+ }
+
+ public function deleteUser(PDO $pdo) : void {
+ $userId = $this->getAppendedUserId();
+ echo $userId;
+ }
+ }',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintedInputInCreatedArrayIsEchoed' => [
+ ' $name];
+
+ echo "" . $data["name"] . "
";',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'testTaintedInputInAssignedArrayIsEchoed' => [
+ '" . $data["name"] . "";',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintedInputDirectly' => [
+ 'exec("delete from users where user_id = " . $userId);
+ }
+ }',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintedInputFromReturnTypeWithBranch' => [
+ 'getUserId();
+
+ if (rand(0, 1)) {
+ $userId .= "aaa";
+ } else {
+ $userId .= "bb";
+ }
+
+ return $userId;
+ }
+
+ public function deleteUser(PDO $pdo) : void {
+ $userId = $this->getAppendedUserId();
+ $pdo->exec("delete from users where user_id = " . $userId);
+ }
+ }',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'sinkAnnotation' => [
+ 'getUserId();
+ }
+
+ public function deleteUser(PDOWrapper $pdo) : void {
+ $userId = $this->getAppendedUserId();
+ $pdo->exec("delete from users where user_id = " . $userId);
+ }
}
- public function deleteUser(PDO $pdo) : void {
- $userId = $this->getAppendedUserId();
- $pdo->exec("delete from users where user_id = " . $userId);
- }
- }'
- );
+ class PDOWrapper {
+ /**
+ * @psalm-taint-sink sql $sql
+ */
+ public function exec(string $sql) : void {}
+ }',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintedInputFromParam' => [
+ 'analyzeFile('somefile.php', new Context());
- }
+ public function getAppendedUserId() : string {
+ return "aaaa" . $this->getUserId();
+ }
- /**
- * @return void
- */
- public function testSinkAnnotation()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
+ public function doDelete(PDO $pdo) : void {
+ $userId = $this->getAppendedUserId();
+ $this->deleteUser($pdo, $userId);
+ }
- $this->project_analyzer->trackTaintedInputs();
+ public function deleteUser(PDO $pdo, string $userId) : void {
+ $pdo->exec("delete from users where user_id = " . $userId);
+ }
+ }',
+ 'error_message' => 'TaintedInput - src/somefile.php:17:40 - Detected tainted sql in path: $_GET -> $_GET[\'user_id\'] (src/somefile.php:4:45) -> A::getUserId (src/somefile.php:3:55) -> concat (src/somefile.php:8:36) -> A::getAppendedUserId (src/somefile.php:7:63) -> $userId (src/somefile.php:12:29) -> call to A::deleteUser (src/somefile.php:13:53) -> A::deleteUser#2 (src/somefile.php:16:69) -> concat (src/somefile.php:17:40) -> call to PDO::exec (src/somefile.php:17:40) -> PDO::exec#1',
+ ],
+ 'taintedInputToParam' => [
+ 'deleteUser(
+ $pdo,
+ $this->getAppendedUserId((string) $_GET["user_id"])
+ );
+ }
- $this->addFile(
- 'somefile.php',
- 'getUserId();
- }
+ public function deleteUser(PDO $pdo, string $userId) : void {
+ $pdo->exec("delete from users where user_id = " . $userId);
+ }
+ }',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintedInputToParamAfterAssignment' => [
+ 'deleteUser(
+ $pdo,
+ $this->getAppendedUserId((string) $_GET["user_id"])
+ );
+ }
- public function deleteUser(PDOWrapper $pdo) : void {
- $userId = $this->getAppendedUserId();
- $pdo->exec("delete from users where user_id = " . $userId);
- }
- }
+ public function getAppendedUserId(string $user_id) : string {
+ return "aaa" . $user_id;
+ }
- class PDOWrapper {
- /**
- * @psalm-taint-sink sql $sql
- */
- public function exec(string $sql) : void {}
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputFromParam()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput - somefile.php:17:36 - Detected tainted sql in path: $_GET -> $_GET[\'user_id\'] (somefile.php:4:41) -> A::getUserId (somefile.php:3:51) -> concat (somefile.php:8:32) -> A::getAppendedUserId (somefile.php:7:59) -> $userId (somefile.php:12:25) -> call to A::deleteUser (somefile.php:13:49) -> A::deleteUser#2 (somefile.php:16:65) -> concat (somefile.php:17:36) -> call to PDO::exec (somefile.php:17:36) -> PDO::exec#1');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'getUserId();
- }
-
- public function doDelete(PDO $pdo) : void {
- $userId = $this->getAppendedUserId();
- $this->deleteUser($pdo, $userId);
- }
-
- public function deleteUser(PDO $pdo, string $userId) : void {
- $pdo->exec("delete from users where user_id = " . $userId);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputToParam()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'deleteUser(
- $pdo,
- $this->getAppendedUserId((string) $_GET["user_id"])
- );
- }
-
- public function getAppendedUserId(string $user_id) : string {
- return "aaa" . $user_id;
- }
-
- public function deleteUser(PDO $pdo, string $userId) : void {
- $pdo->exec("delete from users where user_id = " . $userId);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputToParamAfterAssignment()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'deleteUser(
- $pdo,
- $this->getAppendedUserId((string) $_GET["user_id"])
- );
- }
-
- public function getAppendedUserId(string $user_id) : string {
- return "aaa" . $user_id;
- }
-
- public function deleteUser(PDO $pdo, string $userId) : void {
- $userId2 = $userId;
- $pdo->exec("delete from users where user_id = " . $userId2);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputToParamButSafe()
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'deleteUser(
- $pdo,
- $this->getAppendedUserId((string) $_GET["user_id"])
- );
- }
-
- public function getAppendedUserId(string $user_id) : string {
- return "aaa" . $user_id;
- }
-
- public function deleteUser(PDO $pdo, string $userId) : void {
- $userId2 = strlen($userId);
- $pdo->exec("delete from users where user_id = " . $userId2);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputToParamAlternatePath()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput - somefile.php:23:40 - Detected tainted sql in path: $_GET -> $_GET[\'user_id\'] (somefile.php:7:63) -> call to A::getAppendedUserId (somefile.php:7:54) -> A::getAppendedUserId#1 (somefile.php:11:62) -> concat (somefile.php:12:32) -> A::getAppendedUserId (somefile.php:11:37) -> call to A::deleteUser (somefile.php:7:29) -> A::deleteUser#3 (somefile.php:19:81) -> concat (somefile.php:23:40) -> call to PDO::exec (somefile.php:23:40) -> PDO::exec#1');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'deleteUser(
- $pdo,
- self::doFoo(),
- $this->getAppendedUserId((string) $_GET["user_id"])
- );
- }
-
- public function getAppendedUserId(string $user_id) : string {
- return "aaa" . $user_id;
- }
-
- public static function doFoo() : string {
- return "hello";
- }
-
- public function deleteUser(PDO $pdo, string $userId, string $userId2) : void {
- $pdo->exec("delete from users where user_id = " . $userId);
-
- if (rand(0, 1)) {
+ public function deleteUser(PDO $pdo, string $userId) : void {
+ $userId2 = $userId;
$pdo->exec("delete from users where user_id = " . $userId2);
}
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInParentLoader()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput - somefile.php:16:40 - Detected tainted sql in path: $_GET -> $_GET[\'user_id\'] (somefile.php:28:39) -> call to C::foo (somefile.php:28:30) -> C::foo#1 (somefile.php:23:48) -> call to AGrandChild::loadFull (somefile.php:24:47) -> AGrandChild::loadFull#1 (somefile.php:5:60) -> A::loadFull#1 (somefile.php:24:47) -> call to A::loadPartial (somefile.php:6:45) -> A::loadPartial#1 (somefile.php:3:72) -> AChild::loadPartial#1 (somefile.php:6:45) -> concat (somefile.php:16:40) -> call to PDO::exec (somefile.php:16:40) -> PDO::exec#1');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'exec("select * from foo where bar = " . $sink);
- }
- }
-
- class AGrandChild extends AChild {}
-
- class C {
- public function foo(string $user_id) : void {
- AGrandChild::loadFull($user_id);
- }
- }
-
- (new C)->foo((string) $_GET["user_id"]);'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testValidatedInputFromParam()
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'getUserId();
- validateUserId($userId);
- $this->deleteUser($pdo, $userId);
- }
-
- public function deleteUser(PDO $pdo, string $userId) : void {
- $pdo->exec("delete from users where user_id = " . $userId);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testUntaintedInput()
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'getUserId();
- }
-
- public function deleteUser(PDO $pdo) : void {
- $userId = $this->getAppendedUserId();
- $pdo->exec("delete from users where user_id = " . $userId);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputFromProperty()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'userId = (string) $_GET["user_id"];
- }
-
- public function getAppendedUserId() : string {
- return "aaaa" . $this->userId;
- }
-
- public function doDelete(PDO $pdo) : void {
- $userId = $this->getAppendedUserId();
- $this->deleteUser($pdo, $userId);
- }
-
- public function deleteUser(PDO $pdo, string $userId) : void {
- $pdo->exec("delete from users where user_id = " . $userId);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testSpecializedCoreFunctionCall()
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputFromPropertyViaMixin()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'userId = (string) $_GET["user_id"];
- }
- }
-
- /** @mixin A */
- class B {
- private A $a;
-
- public function __construct(A $a) {
- $this->a = $a;
- }
-
- public function __get(string $name) {
- return $this->a->$name;
- }
- }
-
- class C {
- private B $b;
-
- public function __construct(B $b) {
- $this->b = $b;
- }
-
- public function getAppendedUserId() : string {
- return "aaaa" . $this->b->userId;
- }
-
- public function doDelete(PDO $pdo) : void {
- $userId = $this->getAppendedUserId();
- $this->deleteUser($pdo, $userId);
- }
-
- public function deleteUser(PDO $pdo, string $userId) : void {
- $pdo->exec("delete from users where user_id = " . $userId);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputViaStaticFunction()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testTaintedInputViaPureStaticFunction()
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testUntaintedInputViaStaticFunctionWithSafePath()
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- /**
- * @return void
- */
- public function testUntaintedInputViaStaticFunctionWithoutSafePath()
- {
- $this->project_analyzer->trackTaintedInputs();
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintedInputFromMagicProperty() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- ' */
- private $vars = [];
-
- public function __get(string $s) : string {
- return $this->vars[$s];
- }
-
- public function __set(string $s, string $t) {
- $this->vars[$s] = $t;
- }
- }
-
- function getAppendedUserId() : void {
- $a = new A();
- $a->userId = (string) $_GET["user_id"];
- echo $a->userId;
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintOverMixed() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintStrConversion() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintHtmlEntities() : void
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintIntoExec() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintIntoExecMultipleConcat() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintIntoNestedArrayUnnestedSeparately() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintIntoArrayAndThenOutAgain() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintAppendedToArray() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintOnSubstrCall() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 's = (string) $_GET["FOO"];
- }
- }
-
- class V1 extends V {
- public function foo(O1 $o) : void {
- echo U::shorten($o->s);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintOnStrReplaceCallSimple() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 's = (string) $_GET["FOO"];
- }
- }
-
- class V1 extends V {
- public function foo(O1 $o) : void {
- echo U::shorten($o->s);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintOnStrReplaceCallRemovedInFunction() : void
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 's = (string) $_GET["FOO"];
- }
- }
-
- class V1 extends V {
- public function foo(O1 $o) : void {
- echo U::shorten($o->s);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintOnPregReplaceCallRemovedInFunction() : void
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 's = (string) $_GET["FOO"];
- }
- }
-
- class V1 extends V {
- public function foo(O1 $o) : void {
- echo U::shorten($o->s);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintOnStrReplaceCallRemovedInline() : void
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 's = (string) $_GET["FOO"];
- }
- }
-
- class V1 extends V {
- public function foo(O1 $o) : void {
- /**
- * @psalm-taint-escape html
- */
- $a = str_replace("foo", "bar", $o->s);
- echo $a;
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintOnPregReplaceCall() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 's = (string) $_GET["FOO"];
- }
- }
-
- class V1 extends V {
- public function foo(O1 $o) : void {
- echo U::shorten($o->s);
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- public function testNoTaintsOnSimilarPureCall() : void
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 's = $s;
- }
- }
-
- class O2 {
- public string $t;
-
- public function __construct() {
- $this->t = (string) $_GET["FOO"];
- }
- }
-
- class V1 {
- public function foo() : void {
- $o = new O1((string) $_GET["FOO"]);
- echo U::escape(U::shorten($o->s));
- }
- }
-
- class V2 {
- public function foo(O2 $o) : void {
- echo U::shorten(U::escape($o->t));
- }
- }'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- public function testIndirectGetAssignment() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'name = $name;
- }
-
- /**
- * @psalm-specialize-call
- */
- public function getArg(string $method, string $type)
- {
- $arg = null;
-
- switch ($method) {
- case "post":
- if (isset($_POST[$this->name])) {
- $arg = $_POST[$this->name];
- }
- break;
-
- case "get":
- if (isset($_GET[$this->name])) {
- $arg = $_GET[$this->name];
- }
- break;
+ }',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintedInputToParamAlternatePath' => [
+ 'deleteUser(
+ $pdo,
+ self::doFoo(),
+ $this->getAppendedUserId((string) $_GET["user_id"])
+ );
}
- return $this->filterInput($type, $arg);
+ public function getAppendedUserId(string $user_id) : string {
+ return "aaa" . $user_id;
+ }
+
+ public static function doFoo() : string {
+ return "hello";
+ }
+
+ public function deleteUser(PDO $pdo, string $userId, string $userId2) : void {
+ $pdo->exec("delete from users where user_id = " . $userId);
+
+ if (rand(0, 1)) {
+ $pdo->exec("delete from users where user_id = " . $userId2);
+ }
+ }
+ }',
+ 'error_message' => 'TaintedInput - src/somefile.php:23:44 - Detected tainted sql in path: $_GET -> $_GET[\'user_id\'] (src/somefile.php:7:67) -> call to A::getAppendedUserId (src/somefile.php:7:58) -> A::getAppendedUserId#1 (src/somefile.php:11:66) -> concat (src/somefile.php:12:36) -> A::getAppendedUserId (src/somefile.php:11:41) -> call to A::deleteUser (src/somefile.php:7:33) -> A::deleteUser#3 (src/somefile.php:19:85) -> concat (src/somefile.php:23:44) -> call to PDO::exec (src/somefile.php:23:44) -> PDO::exec#1',
+ ],
+ 'taintedInParentLoader' => [
+ 'exec("select * from foo where bar = " . $sink);
+ }
+ }
+
+ class AGrandChild extends AChild {}
+
+ class C {
+ public function foo(string $user_id) : void {
+ AGrandChild::loadFull($user_id);
+ }
+ }
+
+ (new C)->foo((string) $_GET["user_id"]);',
+ 'error_message' => 'TaintedInput - src/somefile.php:16:44 - Detected tainted sql in path: $_GET -> $_GET[\'user_id\'] (src/somefile.php:28:43) -> call to C::foo (src/somefile.php:28:34) -> C::foo#1 (src/somefile.php:23:52) -> call to AGrandChild::loadFull (src/somefile.php:24:51) -> AGrandChild::loadFull#1 (src/somefile.php:5:64) -> A::loadFull#1 (src/somefile.php:24:51) -> call to A::loadPartial (src/somefile.php:6:49) -> A::loadPartial#1 (src/somefile.php:3:76) -> AChild::loadPartial#1 (src/somefile.php:6:49) -> concat (src/somefile.php:16:44) -> call to PDO::exec (src/somefile.php:16:44) -> PDO::exec#1',
+ ],
+ 'taintedInputFromProperty' => [
+ 'userId = (string) $_GET["user_id"];
+ }
+
+ public function getAppendedUserId() : string {
+ return "aaaa" . $this->userId;
+ }
+
+ public function doDelete(PDO $pdo) : void {
+ $userId = $this->getAppendedUserId();
+ $this->deleteUser($pdo, $userId);
+ }
+
+ public function deleteUser(PDO $pdo, string $userId) : void {
+ $pdo->exec("delete from users where user_id = " . $userId);
+ }
+ }',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintedInputFromPropertyViaMixin' => [
+ 'userId = (string) $_GET["user_id"];
+ }
+ }
+
+ /** @mixin A */
+ class B {
+ private A $a;
+
+ public function __construct(A $a) {
+ $this->a = $a;
+ }
+
+ public function __get(string $name) {
+ return $this->a->$name;
+ }
+ }
+
+ class C {
+ private B $b;
+
+ public function __construct(B $b) {
+ $this->b = $b;
+ }
+
+ public function getAppendedUserId() : string {
+ return "aaaa" . $this->b->userId;
+ }
+
+ public function doDelete(PDO $pdo) : void {
+ $userId = $this->getAppendedUserId();
+ $this->deleteUser($pdo, $userId);
+ }
+
+ public function deleteUser(PDO $pdo, string $userId) : void {
+ $pdo->exec("delete from users where user_id = " . $userId);
+ }
+ }',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintedInputViaStaticFunction' => [
+ ' 'TaintedInput',
+ ],
+ 'taintedInputViaPureStaticFunction' => [
+ ' 'TaintedInput',
+ ],
+ 'untaintedInputViaStaticFunctionWithoutSafePath' => [
+ ' 'TaintedInput',
+ ],
+ 'taintedInputFromMagicProperty' => [
+ ' */
+ private $vars = [];
+
+ public function __get(string $s) : string {
+ return $this->vars[$s];
+ }
+
+ public function __set(string $s, string $t) {
+ $this->vars[$s] = $t;
+ }
+ }
+
+ function getAppendedUserId() : void {
+ $a = new A();
+ $a->userId = (string) $_GET["user_id"];
+ echo $a->userId;
+ }',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintOverMixed' => [
+ ' 'TaintedInput',
+ ],
+ 'taintStrConversion' => [
+ ' 'TaintedInput',
+ ],
+ 'taintIntoExec' => [
+ ' 'TaintedInput',
+ ],
+ 'taintIntoExecMultipleConcat' => [
+ ' 'TaintedInput',
+ ],
+ 'taintIntoNestedArrayUnnestedSeparately' => [
+ ' 'TaintedInput',
+ ],
+ 'taintIntoArrayAndThenOutAgain' => [
+ ' 'TaintedInput',
+ ],
+ 'taintAppendedToArray' => [
+ ' 'TaintedInput',
+ ],
+ 'taintOnSubstrCall' => [
+ 's = (string) $_GET["FOO"];
+ }
+ }
+
+ class V1 extends V {
+ public function foo(O1 $o) : void {
+ echo U::shorten($o->s);
+ }
+ }',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintOnStrReplaceCallSimple' => [
+ 's = (string) $_GET["FOO"];
+ }
+ }
+
+ class V1 extends V {
+ public function foo(O1 $o) : void {
+ echo U::shorten($o->s);
+ }
+ }',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintOnPregReplaceCall' => [
+ 's = (string) $_GET["FOO"];
+ }
+ }
+
+ class V1 extends V {
+ public function foo(O1 $o) : void {
+ echo U::shorten($o->s);
+ }
+ }',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'IndirectGetAssignment' => [
+ 'name = $name;
+ }
+
+ /**
+ * @psalm-specialize-call
+ */
+ public function getArg(string $method, string $type)
+ {
+ $arg = null;
+
+ switch ($method) {
+ case "post":
+ if (isset($_POST[$this->name])) {
+ $arg = $_POST[$this->name];
+ }
+ break;
+
+ case "get":
+ if (isset($_GET[$this->name])) {
+ $arg = $_GET[$this->name];
+ }
+ break;
+ }
+
+ return $this->filterInput($type, $arg);
+ }
+
+ protected function filterInput(string $type, $arg)
+ {
+ // input is null
+ if ($arg === null) {
+ return null;
+ }
+
+ // set to null if sanitize clears arg
+ if ($arg === "") {
+ $arg = null;
+ }
+
+ // type casting
+ if ($arg !== null) {
+ $arg = $this->typeCastInput($type, $arg);
+ }
+
+ return $arg;
+ }
+
+ protected function typeCastInput(string $type, $arg) {
+ if ($type === "string") {
+ return (string) $arg;
+ }
+
return null;
}
+ }
- // set to null if sanitize clears arg
- if ($arg === "") {
- $arg = null;
+ echo (new InputFilter("hello"))->getArg("get", "string");',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintPropertyPassingObject' => [
+ 'id = $userId;
+ }
+ }
+
+ class UserUpdater {
+ public static function doDelete(PDO $pdo, User $user) : void {
+ self::deleteUser($pdo, $user->id);
}
- // type casting
- if ($arg !== null) {
- $arg = $this->typeCastInput($type, $arg);
+ public static function deleteUser(PDO $pdo, string $userId) : void {
+ $pdo->exec("delete from users where user_id = " . $userId);
+ }
+ }
+
+ $userObj = new User((string) $_GET["user_id"]);
+ UserUpdater::doDelete(new PDO(), $userObj);',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintPropertyPassingObjectSettingValueLater' => [
+ 'id = $userId;
}
- return $arg;
+ public function setId(string $userId) : void {
+ $this->id = $userId;
+ }
}
- protected function typeCastInput(string $type, $arg) {
- if ($type === "string") {
- return (string) $arg;
+ class UserUpdater {
+ public static function doDelete(PDO $pdo, User $user) : void {
+ self::deleteUser($pdo, $user->id);
}
- return null;
- }
- }
-
- echo (new InputFilter("hello"))->getArg("get", "string");'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintPropertyPassingObject() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'id = $userId;
- }
- }
-
- class UserUpdater {
- public static function doDelete(PDO $pdo, User $user) : void {
- self::deleteUser($pdo, $user->id);
+ public static function deleteUser(PDO $pdo, string $userId) : void {
+ $pdo->exec("delete from users where user_id = " . $userId);
+ }
}
- public static function deleteUser(PDO $pdo, string $userId) : void {
- $pdo->exec("delete from users where user_id = " . $userId);
- }
- }
+ $userObj = new User("5");
+ $userObj->setId((string) $_GET["user_id"]);
+ UserUpdater::doDelete(new PDO(), $userObj);',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'ImplodeExplode' => [
+ ' 'TaintedInput',
+ ],
+ 'taintThroughPregReplaceCallback' => [
+ 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintPropertyPassingObjectSettingValueLater() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'id = $userId;
- }
-
- public function setId(string $userId) : void {
- $this->id = $userId;
- }
- }
-
- class UserUpdater {
- public static function doDelete(PDO $pdo, User $user) : void {
- self::deleteUser($pdo, $user->id);
- }
-
- public static function deleteUser(PDO $pdo, string $userId) : void {
- $pdo->exec("delete from users where user_id = " . $userId);
- }
- }
-
- $userObj = new User("5");
- $userObj->setId((string) $_GET["user_id"]);
- UserUpdater::doDelete(new PDO(), $userObj);'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintPropertyPassingObjectWithDifferentValue() : void
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'id = $userId;
- }
- }
-
- class UserUpdater {
- public static function doDelete(PDO $pdo, User $user) : void {
- self::deleteUser($pdo, $user->name);
- }
-
- public static function deleteUser(PDO $pdo, string $userId) : void {
- $pdo->exec("delete from users where user_id = " . $userId);
- }
- }
-
- $userObj = new User((string) $_GET["user_id"]);
- UserUpdater::doDelete(new PDO(), $userObj);'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintPropertyWithoutPassingObject() : void
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'id = $userId;
- }
- }
-
- class UserUpdater {
- public static function doDelete(PDO $pdo, User $user) : void {
- self::deleteUser($pdo, $user->id);
- }
-
- public static function deleteUser(PDO $pdo, string $userId) : void {
- $pdo->exec("delete from users where user_id = " . $userId);
- }
- }
-
- $userObj = new User((string) $_GET["user_id"]);'
- );
-
- $this->analyzeFile('somefile.php', new Context());
- }
-
- public function testImplodeExplode() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testSpecializeStaticMethod() : void
- {
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintThroughPregReplaceCallback() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintedFunctionWithNoTypes() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintedStaticCallWithNoTypes() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- ' 'TaintedInput',
+ ],
+ 'taintedFunctionWithNoTypes' => [
+ 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintedInstanceCallWithNoTypes() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- ' 'TaintedInput',
+ ],
+ 'taintedStaticCallWithNoTypes' => [
+ 'rawinput();'
- );
+ echo A::rawinput();',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'taintedInstanceCallWithNoTypes' => [
+ 'analyzeFile('somefile.php', new Context());
- }
+ echo (new A())->rawinput();',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'encapsulatedString' => [
+ ' 'TaintedInput',
+ ],
+ 'namespacedFunction' => [
+ 'expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
+ function identity(string $s) : string {
+ return $s;
+ }
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testNamespacedFunction() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
- }
-
- public function testTaintedInstancePrint() : void
- {
- $this->expectException(\Psalm\Exception\CodeException::class);
- $this->expectExceptionMessage('TaintedInput - somefile.php:2:23 - Detected tainted html in path: $_GET -> $_GET[\'name\'] (somefile.php:2:23) -> call to print (somefile.php:2:23) -> print#1');
-
- $this->project_analyzer->trackTaintedInputs();
-
- $this->addFile(
- 'somefile.php',
- 'analyzeFile('somefile.php', new Context());
+ echo identity($_GET[\'userinput\']);',
+ 'error_message' => 'TaintedInput',
+ ],
+ 'namespacedFunction' => [
+ ' 'TaintedInput - src/somefile.php:2:27 - Detected tainted html in path: $_GET -> $_GET[\'name\'] (src/somefile.php:2:27) -> call to print (src/somefile.php:2:27) -> print#1',
+ ],
+ ];
}
}