mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Break out TaintedInput issues into a lot of separate ones
This commit is contained in:
parent
fda2377812
commit
43af3b1a57
10
config.xsd
10
config.xsd
@ -371,7 +371,17 @@
|
||||
<xs:element name="ReferenceConstraintViolation" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="ReservedWord" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="StringIncrement" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="TaintedCustom" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="TaintedEval" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="TaintedHtml" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="TaintedInclude" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="TaintedInput" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="TaintedShell" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="TaintedSql" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="TaintedSystemSecret" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="TaintedText" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="TaintedUnserialize" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="TaintedUserSecret" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="TooFewArguments" type="ArgumentIssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="TooManyArguments" type="ArgumentIssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="TooManyTemplateParams" type="FunctionIssueHandlerType" minOccurs="0" />
|
||||
|
@ -4,12 +4,12 @@
|
||||
|
||||
return [
|
||||
'exec' => [['shell']],
|
||||
'create_function' => [['text'], ['text']],
|
||||
'create_function' => [['text'], ['eval']],
|
||||
'file_get_contents' => [['text']],
|
||||
'file_put_contents' => [['shell']],
|
||||
'fopen' => [['shell']],
|
||||
'header' => [['text']],
|
||||
'igbinary_unserialize' => [['text']],
|
||||
'igbinary_unserialize' => [['unserialize']],
|
||||
'ldap_search' => [['text']],
|
||||
'mysqli_query' => [[], ['sql']],
|
||||
'mysqli::query' => [['sql']],
|
||||
@ -38,7 +38,7 @@ return [
|
||||
'setcookie' => [['text'], ['text']],
|
||||
'shell_exec' => [['shell']],
|
||||
'system' => [['shell']],
|
||||
'unserialize' => [['text']],
|
||||
'unserialize' => [['unserialize']],
|
||||
'popen' => [['shell']],
|
||||
'proc_open' => [['shell']],
|
||||
];
|
||||
|
3
docs/running_psalm/issues/TaintedCustom.md
Normal file
3
docs/running_psalm/issues/TaintedCustom.md
Normal file
@ -0,0 +1,3 @@
|
||||
# TaintedCustom
|
||||
|
||||
Emitted when tainted input detection is turned on and custom-tainted data is detected.
|
17
docs/running_psalm/issues/TaintedEval.md
Normal file
17
docs/running_psalm/issues/TaintedEval.md
Normal file
@ -0,0 +1,17 @@
|
||||
# TaintedEval
|
||||
|
||||
Tainted input detected to an `eval` call.
|
||||
|
||||
Passing untrusted user input to `eval` calls is dangerous, as it allows arbitrary data to be executed on your server.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$name = $_GET["name"];
|
||||
|
||||
evalCode($name);
|
||||
|
||||
function evalCode(string $name) {
|
||||
eval($name);
|
||||
}
|
||||
```
|
15
docs/running_psalm/issues/TaintedHtml.md
Normal file
15
docs/running_psalm/issues/TaintedHtml.md
Normal file
@ -0,0 +1,15 @@
|
||||
# TaintedHtml
|
||||
|
||||
Emitted when tainted input detection is turned on and tainted HTML is detected.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$name = $_GET["name"];
|
||||
|
||||
printName($name);
|
||||
|
||||
function printName(string $name) {
|
||||
echo $name;
|
||||
}
|
||||
```
|
17
docs/running_psalm/issues/TaintedInclude.md
Normal file
17
docs/running_psalm/issues/TaintedInclude.md
Normal file
@ -0,0 +1,17 @@
|
||||
# TaintedInclude
|
||||
|
||||
Tainted input detected to an `include` or `require` call.
|
||||
|
||||
Passing untrusted user input to `include` calls is dangerous, as it can allow an attacker to execute arbitrary scripts on your server.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$name = $_GET["name"];
|
||||
|
||||
includeCode($name);
|
||||
|
||||
function includeCode(string $name) : void {
|
||||
include($name . '.php');
|
||||
}
|
||||
```
|
15
docs/running_psalm/issues/TaintedShell.md
Normal file
15
docs/running_psalm/issues/TaintedShell.md
Normal file
@ -0,0 +1,15 @@
|
||||
# TaintedShell
|
||||
|
||||
Emitted when tainted input detection is turned on and tainted shell code is detected.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$command = $_GET["command"];
|
||||
|
||||
runCode($command);
|
||||
|
||||
function runCode(string $command) {
|
||||
exec($command);
|
||||
}
|
||||
```
|
18
docs/running_psalm/issues/TaintedSql.md
Normal file
18
docs/running_psalm/issues/TaintedSql.md
Normal file
@ -0,0 +1,18 @@
|
||||
# TaintedSql
|
||||
|
||||
Emitted when tainted input detection is turned on and tainted SQL is detected.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
class A {
|
||||
public function deleteUser(PDO $pdo) : void {
|
||||
$userId = self::getUserId();
|
||||
$pdo->exec("delete from users where user_id = " . $userId);
|
||||
}
|
||||
|
||||
public static function getUserId() : string {
|
||||
return (string) $_GET["user_id"];
|
||||
}
|
||||
}
|
||||
```
|
16
docs/running_psalm/issues/TaintedSystemSecret.md
Normal file
16
docs/running_psalm/issues/TaintedSystemSecret.md
Normal file
@ -0,0 +1,16 @@
|
||||
# TaintedSystemSecret
|
||||
|
||||
Emitted when tainted input detection is turned on and data marked as a system secret is detected somewhere it shouldn’t be.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @psalm-taint-source system_secret
|
||||
*/
|
||||
function getConfigValue(string $data) {
|
||||
return "$omePa$$word";
|
||||
}
|
||||
|
||||
echo getConfigValue("secret");
|
||||
```
|
19
docs/running_psalm/issues/TaintedText.md
Normal file
19
docs/running_psalm/issues/TaintedText.md
Normal file
@ -0,0 +1,19 @@
|
||||
# TaintedText
|
||||
|
||||
Emitted when tainted input detection is turned on and tainted text is detected somewhere unexpected.
|
||||
|
||||
This can lead to dangerous situations, like running arbitrary functions.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$name = $_GET["name"];
|
||||
|
||||
evalCode($name);
|
||||
|
||||
function evalCode(string $name) {
|
||||
if (is_callable($name)) {
|
||||
$name();
|
||||
}
|
||||
}
|
||||
```
|
19
docs/running_psalm/issues/TaintedUnserialize.md
Normal file
19
docs/running_psalm/issues/TaintedUnserialize.md
Normal file
@ -0,0 +1,19 @@
|
||||
# TaintedUnserialize
|
||||
|
||||
Tainted input detected to an `unserialize` call.
|
||||
|
||||
Passing untrusted user input to `unserialize` calls is dangerous – from the [PHP documentation on unserialize](https://www.php.net/manual/en/function.unserialize.php):
|
||||
|
||||
> Do not pass untrusted user input to unserialize() regardless of the options value of allowed_classes. Unserialization can result in code being loaded and executed due to object instantiation and autoloading, and a malicious user may be able to exploit this. Use a safe, standard data interchange format such as JSON (via json_decode() and json_encode()) if you need to pass serialized data to the user.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$command = $_GET["data"];
|
||||
|
||||
getObject($command);
|
||||
|
||||
function getObject(string $data) : object {
|
||||
return unserialize($data);
|
||||
}
|
||||
```
|
20
docs/running_psalm/issues/TaintedUserSecret.md
Normal file
20
docs/running_psalm/issues/TaintedUserSecret.md
Normal file
@ -0,0 +1,20 @@
|
||||
# TaintedUserSecret
|
||||
|
||||
Emitted when tainted input detection is turned on and data marked as a user secret is detected somewhere it shouldn’t be.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
class User {
|
||||
/**
|
||||
* @psalm-taint-source user_secret
|
||||
*/
|
||||
public function getPassword() : string {
|
||||
return "$omePa$$word";
|
||||
}
|
||||
}
|
||||
|
||||
function showUserPassword(User $user) {
|
||||
echo $user->getPassword();
|
||||
}
|
||||
```
|
@ -741,6 +741,29 @@ class FunctionCallAnalyzer extends CallAnalyzer
|
||||
|
||||
return [false, null, null, null];
|
||||
}
|
||||
|
||||
if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph
|
||||
&& $stmt_name_type->parent_nodes
|
||||
&& !\in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())
|
||||
) {
|
||||
$arg_location = new CodeLocation($statements_analyzer->getSource(), $function_name);
|
||||
|
||||
$custom_call_sink = \Psalm\Internal\DataFlow\TaintSink::getForMethodArgument(
|
||||
'variable-call',
|
||||
'variable-call',
|
||||
0,
|
||||
$arg_location,
|
||||
$arg_location
|
||||
);
|
||||
|
||||
$custom_call_sink->taints = [\Psalm\Type\TaintKind::INPUT_TEXT];
|
||||
|
||||
$statements_analyzer->data_flow_graph->addSink($custom_call_sink);
|
||||
|
||||
foreach ($stmt_name_type->parent_nodes as $parent_node) {
|
||||
$statements_analyzer->data_flow_graph->addPath($parent_node, $custom_call_sink, 'call');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$statements_analyzer->node_data->getType($real_stmt)) {
|
||||
|
@ -38,7 +38,7 @@ class EvalAnalyzer
|
||||
$arg_location
|
||||
);
|
||||
|
||||
$eval_param_sink->taints = [\Psalm\Type\TaintKind::INPUT_TEXT];
|
||||
$eval_param_sink->taints = [\Psalm\Type\TaintKind::INPUT_EVAL];
|
||||
|
||||
$statements_analyzer->data_flow_graph->addSink($eval_param_sink);
|
||||
|
||||
|
@ -116,7 +116,7 @@ class IncludeAnalyzer
|
||||
$arg_location
|
||||
);
|
||||
|
||||
$include_param_sink->taints = [\Psalm\Type\TaintKind::INPUT_TEXT];
|
||||
$include_param_sink->taints = [\Psalm\Type\TaintKind::INPUT_INCLUDE];
|
||||
|
||||
$statements_analyzer->data_flow_graph->addSink($include_param_sink);
|
||||
|
||||
|
@ -3,11 +3,21 @@
|
||||
namespace Psalm\Internal\Codebase;
|
||||
|
||||
use Psalm\CodeLocation;
|
||||
use Psalm\Internal\DataFlow\DataFlowNode;
|
||||
use Psalm\Internal\DataFlow\TaintSink;
|
||||
use Psalm\Internal\DataFlow\TaintSource;
|
||||
use Psalm\Internal\DataFlow\DataFlowNode;
|
||||
use Psalm\Issue\TaintedCustom;
|
||||
use Psalm\Issue\TaintedEval;
|
||||
use Psalm\Issue\TaintedHtml;
|
||||
use Psalm\Issue\TaintedInclude;
|
||||
use Psalm\Issue\TaintedShell;
|
||||
use Psalm\Issue\TaintedSql;
|
||||
use Psalm\Issue\TaintedSystemSecret;
|
||||
use Psalm\Issue\TaintedText;
|
||||
use Psalm\Issue\TaintedUnserialize;
|
||||
use Psalm\Issue\TaintedUserSecret;
|
||||
use Psalm\IssueBuffer;
|
||||
use Psalm\Issue\TaintedInput;
|
||||
use Psalm\Type\TaintKind;
|
||||
use function array_merge;
|
||||
use function count;
|
||||
use function implode;
|
||||
@ -242,16 +252,103 @@ class TaintFlowGraph extends DataFlowGraph
|
||||
$issue_location = $generated_source->code_location;
|
||||
}
|
||||
|
||||
if (IssueBuffer::accepts(
|
||||
new TaintedInput(
|
||||
'Detected tainted ' . implode(', ', $matching_taints),
|
||||
$issue_location,
|
||||
$this->getIssueTrace($generated_source),
|
||||
$this->getPredecessorPath($generated_source)
|
||||
. ' -> ' . $this->getSuccessorPath($sinks[$to_id])
|
||||
)
|
||||
)) {
|
||||
// fall through
|
||||
$issue_trace = $this->getIssueTrace($generated_source);
|
||||
$path = $this->getPredecessorPath($generated_source)
|
||||
. ' -> ' . $this->getSuccessorPath($sinks[$to_id]);
|
||||
|
||||
foreach ($matching_taints as $matching_taint) {
|
||||
switch ($matching_taint) {
|
||||
case TaintKind::INPUT_TEXT:
|
||||
$issue = new TaintedText(
|
||||
'Detected tainted text',
|
||||
$issue_location,
|
||||
$issue_trace,
|
||||
$path
|
||||
);
|
||||
break;
|
||||
|
||||
case TaintKind::INPUT_UNSERIALIZE:
|
||||
$issue = new TaintedUnserialize(
|
||||
'Detected tainted code passed to unserialize or similar',
|
||||
$issue_location,
|
||||
$issue_trace,
|
||||
$path
|
||||
);
|
||||
break;
|
||||
|
||||
case TaintKind::INPUT_INCLUDE:
|
||||
$issue = new TaintedInclude(
|
||||
'Detected tainted code passed to include or similar',
|
||||
$issue_location,
|
||||
$issue_trace,
|
||||
$path
|
||||
);
|
||||
break;
|
||||
|
||||
case TaintKind::INPUT_EVAL:
|
||||
$issue = new TaintedEval(
|
||||
'Detected tainted code passed to eval or similar',
|
||||
$issue_location,
|
||||
$issue_trace,
|
||||
$path
|
||||
);
|
||||
break;
|
||||
|
||||
case TaintKind::INPUT_SQL:
|
||||
$issue = new TaintedSql(
|
||||
'Detected tainted SQL',
|
||||
$issue_location,
|
||||
$issue_trace,
|
||||
$path
|
||||
);
|
||||
break;
|
||||
|
||||
case TaintKind::INPUT_HTML:
|
||||
$issue = new TaintedHtml(
|
||||
'Detected tainted HTML',
|
||||
$issue_location,
|
||||
$issue_trace,
|
||||
$path
|
||||
);
|
||||
break;
|
||||
|
||||
case TaintKind::INPUT_SHELL:
|
||||
$issue = new TaintedShell(
|
||||
'Detected tainted shell code',
|
||||
$issue_location,
|
||||
$issue_trace,
|
||||
$path
|
||||
);
|
||||
break;
|
||||
|
||||
case TaintKind::USER_SECRET:
|
||||
$issue = new TaintedUserSecret(
|
||||
'Detected tainted user secret leaking',
|
||||
$issue_location,
|
||||
$issue_trace,
|
||||
$path
|
||||
);
|
||||
break;
|
||||
|
||||
case TaintKind::SYSTEM_SECRET:
|
||||
$issue = new TaintedSystemSecret(
|
||||
'Detected tainted system secret leaking',
|
||||
$issue_location,
|
||||
$issue_trace,
|
||||
$path
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
$issue = new TaintedCustom(
|
||||
'Detected tainted ' . $matching_taint,
|
||||
$issue_location,
|
||||
$issue_trace,
|
||||
$path
|
||||
);
|
||||
}
|
||||
|
||||
IssueBuffer::accepts($issue);
|
||||
}
|
||||
|
||||
continue;
|
||||
|
7
src/Psalm/Issue/TaintedCustom.php
Normal file
7
src/Psalm/Issue/TaintedCustom.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class TaintedCustom extends TaintedInput
|
||||
{
|
||||
public const SHORTCODE = 249;
|
||||
}
|
7
src/Psalm/Issue/TaintedEval.php
Normal file
7
src/Psalm/Issue/TaintedEval.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class TaintedEval extends TaintedInput
|
||||
{
|
||||
public const SHORTCODE = 252;
|
||||
}
|
7
src/Psalm/Issue/TaintedHtml.php
Normal file
7
src/Psalm/Issue/TaintedHtml.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class TaintedHtml extends TaintedInput
|
||||
{
|
||||
public const SHORTCODE = 245;
|
||||
}
|
7
src/Psalm/Issue/TaintedInclude.php
Normal file
7
src/Psalm/Issue/TaintedInclude.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class TaintedInclude extends TaintedInput
|
||||
{
|
||||
public const SHORTCODE = 251;
|
||||
}
|
@ -4,7 +4,7 @@ namespace Psalm\Issue;
|
||||
use Psalm\Internal\Analyzer\DataFlowNodeData;
|
||||
use Psalm\CodeLocation;
|
||||
|
||||
class TaintedInput extends CodeIssue
|
||||
abstract class TaintedInput extends CodeIssue
|
||||
{
|
||||
public const ERROR_LEVEL = -2;
|
||||
public const SHORTCODE = 205;
|
||||
|
7
src/Psalm/Issue/TaintedShell.php
Normal file
7
src/Psalm/Issue/TaintedShell.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class TaintedShell extends TaintedInput
|
||||
{
|
||||
public const SHORTCODE = 246;
|
||||
}
|
7
src/Psalm/Issue/TaintedSql.php
Normal file
7
src/Psalm/Issue/TaintedSql.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class TaintedSql extends TaintedInput
|
||||
{
|
||||
public const SHORTCODE = 244;
|
||||
}
|
7
src/Psalm/Issue/TaintedSystemSecret.php
Normal file
7
src/Psalm/Issue/TaintedSystemSecret.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class TaintedSystemSecret extends TaintedInput
|
||||
{
|
||||
public const SHORTCODE = 248;
|
||||
}
|
7
src/Psalm/Issue/TaintedText.php
Normal file
7
src/Psalm/Issue/TaintedText.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class TaintedText extends TaintedInput
|
||||
{
|
||||
public const SHORTCODE = 243;
|
||||
}
|
7
src/Psalm/Issue/TaintedUnserialize.php
Normal file
7
src/Psalm/Issue/TaintedUnserialize.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class TaintedUnserialize extends TaintedInput
|
||||
{
|
||||
public const SHORTCODE = 250;
|
||||
}
|
7
src/Psalm/Issue/TaintedUserSecret.php
Normal file
7
src/Psalm/Issue/TaintedUserSecret.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class TaintedUserSecret extends TaintedInput
|
||||
{
|
||||
public const SHORTCODE = 247;
|
||||
}
|
@ -104,7 +104,7 @@ class IssueBuffer
|
||||
|
||||
public static function addUnusedSuppression(string $file_path, int $offset, string $issue_type) : void
|
||||
{
|
||||
if ($issue_type === 'TaintedInput') {
|
||||
if (\substr($issue_type, 0, 7) === 'Tainted') {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -204,7 +204,9 @@ class IssueBuffer
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($project_analyzer->getCodebase()->taint_flow_graph && $issue_type !== 'TaintedInput') {
|
||||
$is_tainted = \substr($issue_type, 0, 7) === 'Tainted';
|
||||
|
||||
if ($project_analyzer->getCodebase()->taint_flow_graph && !$is_tainted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -227,7 +229,7 @@ class IssueBuffer
|
||||
. ' ' . $e->dupe_key;
|
||||
|
||||
if ($reporting_level === Config::REPORT_INFO) {
|
||||
if ($issue_type === 'TaintedInput' || !self::alreadyEmitted($emitted_key)) {
|
||||
if ($is_tainted || !self::alreadyEmitted($emitted_key)) {
|
||||
self::$issues_data[$e->getFilePath()][] = $e->toIssueData(Config::REPORT_INFO);
|
||||
|
||||
if ($is_fixable) {
|
||||
@ -253,7 +255,7 @@ class IssueBuffer
|
||||
);
|
||||
}
|
||||
|
||||
if ($issue_type === 'TaintedInput' || !self::alreadyEmitted($emitted_key)) {
|
||||
if ($is_tainted || !self::alreadyEmitted($emitted_key)) {
|
||||
++self::$error_count;
|
||||
self::$issues_data[$e->getFilePath()][] = $e->toIssueData(Config::REPORT_ERROR);
|
||||
|
||||
|
@ -8,6 +8,9 @@ namespace Psalm\Type;
|
||||
class TaintKind
|
||||
{
|
||||
public const INPUT_TEXT = 'text';
|
||||
public const INPUT_UNSERIALIZE = 'unserialize';
|
||||
public const INPUT_INCLUDE = 'include';
|
||||
public const INPUT_EVAL = 'eval';
|
||||
public const INPUT_SQL = 'sql';
|
||||
public const INPUT_HTML = 'html';
|
||||
public const INPUT_SHELL = 'shell';
|
||||
|
@ -12,5 +12,8 @@ class TaintKindGroup
|
||||
TaintKind::INPUT_SHELL,
|
||||
TaintKind::INPUT_SQL,
|
||||
TaintKind::INPUT_TEXT,
|
||||
TaintKind::INPUT_EVAL,
|
||||
TaintKind::INPUT_UNSERIALIZE,
|
||||
TaintKind::INPUT_INCLUDE,
|
||||
];
|
||||
}
|
||||
|
@ -131,6 +131,7 @@ class DocumentationTest extends TestCase
|
||||
$code_blocks['UnrecognizedStatement'] = true;
|
||||
$code_blocks['PluginIssue'] = true;
|
||||
$code_blocks['TaintedInput'] = true;
|
||||
$code_blocks['TaintedCustom'] = true;
|
||||
|
||||
$documented_issues = array_keys($code_blocks);
|
||||
sort($documented_issues);
|
||||
@ -159,6 +160,8 @@ class DocumentationTest extends TestCase
|
||||
$this->project_analyzer->trackUnusedSuppressions();
|
||||
}
|
||||
|
||||
$is_taint_test = strpos($error_message, 'Tainted') !== false;
|
||||
|
||||
$is_array_offset_test = strpos($error_message, 'ArrayOffset') && strpos($error_message, 'PossiblyUndefined') !== false;
|
||||
|
||||
$this->project_analyzer->getConfig()->ensure_array_string_offsets_exist = $is_array_offset_test;
|
||||
@ -178,6 +181,10 @@ class DocumentationTest extends TestCase
|
||||
|
||||
$this->addFile($file_path, $code);
|
||||
|
||||
if ($is_taint_test) {
|
||||
$this->project_analyzer->trackTaintedInputs();
|
||||
}
|
||||
|
||||
$this->analyzeFile($file_path, new Context());
|
||||
|
||||
if ($check_references) {
|
||||
|
@ -155,7 +155,7 @@ class PsalmEndToEndTest extends TestCase
|
||||
$this->runPsalmInit(1);
|
||||
$result = $this->runPsalm(['--taint-analysis'], self::$tmpDir, true);
|
||||
|
||||
$this->assertStringContainsString('TaintedInput', $result['STDOUT']);
|
||||
$this->assertStringContainsString('TaintedHtml', $result['STDOUT']);
|
||||
$this->assertStringContainsString('1 errors', $result['STDOUT']);
|
||||
$this->assertSame(1, $result['CODE']);
|
||||
}
|
||||
|
@ -506,7 +506,7 @@ class TaintTest extends TestCase
|
||||
$pdo->exec("delete from users where user_id = " . $userId);
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedSql',
|
||||
],
|
||||
'taintedInputFromFunctionReturnType' => [
|
||||
'<?php
|
||||
@ -515,7 +515,7 @@ class TaintTest extends TestCase
|
||||
}
|
||||
|
||||
echo getName();',
|
||||
'error_message' => 'TaintedInput - src' . DIRECTORY_SEPARATOR . 'somefile.php:6:26 - Detected tainted html in path: $_GET -> $_GET[\'name\'] (src/somefile.php:3:32) -> coalesce (src/somefile.php:3:32) -> getName (src/somefile.php:2:42) -> call to echo (src/somefile.php:6:26) -> echo#1',
|
||||
'error_message' => 'TaintedHtml - src' . DIRECTORY_SEPARATOR . 'somefile.php:6:26 - Detected tainted HTML in path: $_GET -> $_GET[\'name\'] (src/somefile.php:3:32) -> coalesce (src/somefile.php:3:32) -> getName (src/somefile.php:2:42) -> call to echo (src/somefile.php:6:26) -> echo#1',
|
||||
],
|
||||
'taintedInputFromExplicitTaintSource' => [
|
||||
'<?php
|
||||
@ -527,7 +527,7 @@ class TaintTest extends TestCase
|
||||
}
|
||||
|
||||
echo getName();',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintedInputFromExplicitTaintSourceStaticMethod' => [
|
||||
'<?php
|
||||
@ -542,7 +542,7 @@ class TaintTest extends TestCase
|
||||
|
||||
|
||||
echo Request::getName();',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintedInputFromGetArray' => [
|
||||
'<?php
|
||||
@ -553,20 +553,20 @@ class TaintTest extends TestCase
|
||||
$name = getName($_GET);
|
||||
|
||||
echo $name;',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintedInputFromReturnToInclude' => [
|
||||
'<?php
|
||||
$a = (string) $_GET["file"];
|
||||
$b = "hello" . $a;
|
||||
include str_replace("a", "b", $b);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedInclude',
|
||||
],
|
||||
'taintedInputFromReturnToEval' => [
|
||||
'<?php
|
||||
$a = $_GET["file"];
|
||||
eval("<?php" . $a);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedEval',
|
||||
],
|
||||
'taintedInputFromReturnTypeToEcho' => [
|
||||
'<?php
|
||||
@ -584,7 +584,7 @@ class TaintTest extends TestCase
|
||||
echo $userId;
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintedInputInCreatedArrayIsEchoed' => [
|
||||
'<?php
|
||||
@ -593,7 +593,7 @@ class TaintTest extends TestCase
|
||||
$data = ["name" => $name];
|
||||
|
||||
echo "<h1>" . $data["name"] . "</h1>";',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'testTaintedInputInAssignedArrayIsEchoed' => [
|
||||
'<?php
|
||||
@ -603,7 +603,7 @@ class TaintTest extends TestCase
|
||||
$data["name"] = $name;
|
||||
|
||||
echo "<h1>" . $data["name"] . "</h1>";',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintedInputDirectly' => [
|
||||
'<?php
|
||||
@ -613,7 +613,7 @@ class TaintTest extends TestCase
|
||||
$pdo->exec("delete from users where user_id = " . $userId);
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedSql',
|
||||
],
|
||||
'taintedInputFromReturnTypeWithBranch' => [
|
||||
'<?php
|
||||
@ -639,7 +639,7 @@ class TaintTest extends TestCase
|
||||
$pdo->exec("delete from users where user_id = " . $userId);
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedSql',
|
||||
],
|
||||
'sinkAnnotation' => [
|
||||
'<?php
|
||||
@ -664,7 +664,7 @@ class TaintTest extends TestCase
|
||||
*/
|
||||
public function exec(string $sql) : void {}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedSql',
|
||||
],
|
||||
'taintedInputFromParam' => [
|
||||
'<?php
|
||||
@ -686,7 +686,7 @@ class TaintTest extends TestCase
|
||||
$pdo->exec("delete from users where user_id = " . $userId);
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput - src' . DIRECTORY_SEPARATOR . '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) -> $userId (src/somefile.php:16:69) -> concat (src/somefile.php:17:40) -> call to PDO::exec (src/somefile.php:17:40) -> PDO::exec#1',
|
||||
'error_message' => 'TaintedSql - src' . DIRECTORY_SEPARATOR . '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) -> $userId (src/somefile.php:16:69) -> concat (src/somefile.php:17:40) -> call to PDO::exec (src/somefile.php:17:40) -> PDO::exec#1',
|
||||
],
|
||||
'taintedInputToParam' => [
|
||||
'<?php
|
||||
@ -706,7 +706,7 @@ class TaintTest extends TestCase
|
||||
$pdo->exec("delete from users where user_id = " . $userId);
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedSql',
|
||||
],
|
||||
'taintedInputToParamAfterAssignment' => [
|
||||
'<?php
|
||||
@ -727,7 +727,7 @@ class TaintTest extends TestCase
|
||||
$pdo->exec("delete from users where user_id = " . $userId2);
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedSql',
|
||||
],
|
||||
'taintedInputToParamAlternatePath' => [
|
||||
'<?php
|
||||
@ -756,7 +756,7 @@ class TaintTest extends TestCase
|
||||
}
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput - src' . DIRECTORY_SEPARATOR . '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) -> $user_id (src/somefile.php:11:66) -> concat (src/somefile.php:12:36) -> A::getAppendedUserId (src/somefile.php:11:78) -> call to A::deleteUser (src/somefile.php:7:33) -> A::deleteUser#3 (src/somefile.php:19:85) -> $userId2 (src/somefile.php:19:85) -> concat (src/somefile.php:23:44) -> call to PDO::exec (src/somefile.php:23:44) -> PDO::exec#1',
|
||||
'error_message' => 'TaintedSql - src' . DIRECTORY_SEPARATOR . '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) -> $user_id (src/somefile.php:11:66) -> concat (src/somefile.php:12:36) -> A::getAppendedUserId (src/somefile.php:11:78) -> call to A::deleteUser (src/somefile.php:7:33) -> A::deleteUser#3 (src/somefile.php:19:85) -> $userId2 (src/somefile.php:19:85) -> concat (src/somefile.php:23:44) -> call to PDO::exec (src/somefile.php:23:44) -> PDO::exec#1',
|
||||
],
|
||||
'taintedInParentLoader' => [
|
||||
'<?php
|
||||
@ -787,7 +787,7 @@ class TaintTest extends TestCase
|
||||
}
|
||||
|
||||
(new C)->foo((string) $_GET["user_id"]);',
|
||||
'error_message' => 'TaintedInput - src' . DIRECTORY_SEPARATOR . '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) -> $user_id (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) -> $sink (src/somefile.php:5:64) -> 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) -> $sink (src/somefile.php:15:67) -> concat (src/somefile.php:16:44) -> call to PDO::exec (src/somefile.php:16:44) -> PDO::exec#1',
|
||||
'error_message' => 'TaintedSql - src' . DIRECTORY_SEPARATOR . '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) -> $user_id (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) -> $sink (src/somefile.php:5:64) -> 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) -> $sink (src/somefile.php:15:67) -> concat (src/somefile.php:16:44) -> call to PDO::exec (src/somefile.php:16:44) -> PDO::exec#1',
|
||||
],
|
||||
'taintedInputFromProperty' => [
|
||||
'<?php
|
||||
@ -811,7 +811,7 @@ class TaintTest extends TestCase
|
||||
$pdo->exec("delete from users where user_id = " . $userId);
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedSql',
|
||||
],
|
||||
'taintedInputFromPropertyViaMixin' => [
|
||||
'<?php
|
||||
@ -856,7 +856,7 @@ class TaintTest extends TestCase
|
||||
$pdo->exec("delete from users where user_id = " . $userId);
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedSql',
|
||||
],
|
||||
'taintedInputViaStaticFunction' => [
|
||||
'<?php
|
||||
@ -871,7 +871,7 @@ class TaintTest extends TestCase
|
||||
echo(Utils::shorten((string) $_GET["user_id"]));
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintedInputViaPureStaticFunction' => [
|
||||
'<?php
|
||||
@ -889,7 +889,7 @@ class TaintTest extends TestCase
|
||||
echo(Utils::shorten((string) $_GET["user_id"]));
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'untaintedInputViaStaticFunctionWithoutSafePath' => [
|
||||
'<?php
|
||||
@ -911,7 +911,7 @@ class TaintTest extends TestCase
|
||||
echo(Utils::shorten("hello"));
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintedInputFromMagicProperty' => [
|
||||
'<?php
|
||||
@ -936,7 +936,7 @@ class TaintTest extends TestCase
|
||||
$a->userId = (string) $_GET["user_id"];
|
||||
echo $a->userId;
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintOverMixed' => [
|
||||
'<?php
|
||||
@ -948,7 +948,7 @@ class TaintTest extends TestCase
|
||||
$a = $_GET["bad"];
|
||||
echo $a;
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintStrConversion' => [
|
||||
'<?php
|
||||
@ -956,7 +956,7 @@ class TaintTest extends TestCase
|
||||
$a = strtoupper(strtolower((string) $_GET["bad"]));
|
||||
echo $a;
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintIntoExec' => [
|
||||
'<?php
|
||||
@ -964,7 +964,7 @@ class TaintTest extends TestCase
|
||||
$a = (string) $_GET["bad"];
|
||||
exec($a);
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedShell',
|
||||
],
|
||||
'taintIntoExecMultipleConcat' => [
|
||||
'<?php
|
||||
@ -972,7 +972,7 @@ class TaintTest extends TestCase
|
||||
$a = "9" . "a" . "b" . "c" . ((string) $_GET["bad"]) . "d" . "e" . "f";
|
||||
exec($a);
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedShell',
|
||||
],
|
||||
'taintIntoNestedArrayUnnestedSeparately' => [
|
||||
'<?php
|
||||
@ -980,7 +980,7 @@ class TaintTest extends TestCase
|
||||
$a = [[(string) $_GET["bad"]]];
|
||||
exec($a[0][0]);
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedShell',
|
||||
],
|
||||
'taintIntoArrayAndThenOutAgain' => [
|
||||
'<?php
|
||||
@ -994,7 +994,7 @@ class TaintTest extends TestCase
|
||||
exec(self::foo()[0]);
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedShell',
|
||||
],
|
||||
'taintAppendedToArray' => [
|
||||
'<?php
|
||||
@ -1009,7 +1009,7 @@ class TaintTest extends TestCase
|
||||
exec(self::foo()[0]);
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedShell',
|
||||
],
|
||||
'taintOnSubstrCall' => [
|
||||
'<?php
|
||||
@ -1035,7 +1035,7 @@ class TaintTest extends TestCase
|
||||
echo U::shorten($o->s);
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintOnStrReplaceCallSimple' => [
|
||||
'<?php
|
||||
@ -1061,7 +1061,7 @@ class TaintTest extends TestCase
|
||||
echo U::shorten($o->s);
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintOnPregReplaceCall' => [
|
||||
'<?php
|
||||
@ -1087,7 +1087,7 @@ class TaintTest extends TestCase
|
||||
echo U::shorten($o->s);
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'IndirectGetAssignment' => [
|
||||
'<?php
|
||||
@ -1152,7 +1152,7 @@ class TaintTest extends TestCase
|
||||
}
|
||||
|
||||
echo (new InputFilter("hello"))->getArg("get", "string");',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintPropertyPassingObject' => [
|
||||
'<?php
|
||||
@ -1177,7 +1177,7 @@ class TaintTest extends TestCase
|
||||
|
||||
$userObj = new User((string) $_GET["user_id"]);
|
||||
UserUpdater::doDelete(new PDO(), $userObj);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedSql',
|
||||
],
|
||||
'taintPropertyPassingObjectSettingValueLater' => [
|
||||
'<?php
|
||||
@ -1207,7 +1207,7 @@ class TaintTest extends TestCase
|
||||
$userObj = new User("5");
|
||||
$userObj->setId((string) $_GET["user_id"]);
|
||||
UserUpdater::doDelete(new PDO(), $userObj);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedSql',
|
||||
],
|
||||
'ImplodeExplode' => [
|
||||
'<?php
|
||||
@ -1215,14 +1215,14 @@ class TaintTest extends TestCase
|
||||
$b = explode(" ", $a);
|
||||
$c = implode(" ", $b);
|
||||
echo $c;',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'ImplodeIndirect' => [
|
||||
'<?php
|
||||
/** @var array $unsafe */
|
||||
$unsafe = $_GET[\'unsafe\'];
|
||||
echo implode(" ", $unsafe);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintThroughPregReplaceCallback' => [
|
||||
'<?php
|
||||
@ -1237,7 +1237,7 @@ class TaintTest extends TestCase
|
||||
);
|
||||
|
||||
echo $b;',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintedFunctionWithNoTypes' => [
|
||||
'<?php
|
||||
@ -1246,7 +1246,7 @@ class TaintTest extends TestCase
|
||||
}
|
||||
|
||||
echo rawinput();',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintedStaticCallWithNoTypes' => [
|
||||
'<?php
|
||||
@ -1257,7 +1257,7 @@ class TaintTest extends TestCase
|
||||
}
|
||||
|
||||
echo A::rawinput();',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintedInstanceCallWithNoTypes' => [
|
||||
'<?php
|
||||
@ -1268,25 +1268,25 @@ class TaintTest extends TestCase
|
||||
}
|
||||
|
||||
echo (new A())->rawinput();',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintStringObtainedUsingStrval' => [
|
||||
'<?php
|
||||
$unsafe = strval($_GET[\'unsafe\']);
|
||||
echo $unsafe',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintStringObtainedUsingSprintf' => [
|
||||
'<?php
|
||||
$unsafe = sprintf("%s", strval($_GET[\'unsafe\']));
|
||||
echo $unsafe;',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'encapsulatedString' => [
|
||||
'<?php
|
||||
$unsafe = $_GET[\'unsafe\'];
|
||||
echo "$unsafe";',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'encapsulatedToStringMagic' => [
|
||||
'<?php
|
||||
@ -1297,7 +1297,7 @@ class TaintTest extends TestCase
|
||||
}
|
||||
$unsafe = new MyClass();
|
||||
echo "unsafe: $unsafe";',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'castToStringMagic' => [
|
||||
'<?php
|
||||
@ -1308,7 +1308,7 @@ class TaintTest extends TestCase
|
||||
}
|
||||
$unsafe = new MyClass();
|
||||
echo $unsafe;',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'castToStringViaArgument' => [
|
||||
'<?php
|
||||
@ -1325,7 +1325,7 @@ class TaintTest extends TestCase
|
||||
$unsafe = new MyClass();
|
||||
|
||||
doesEcho($unsafe);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'toStringTaintInSubclass' => [
|
||||
'<?php // --taint-analysis
|
||||
@ -1338,7 +1338,7 @@ class TaintTest extends TestCase
|
||||
class TaintedSubclass extends TaintedBaseClass {}
|
||||
$x = new TaintedSubclass();
|
||||
echo "Caught: $x\n";',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'implicitToStringMagic' => [
|
||||
'<?php
|
||||
@ -1349,7 +1349,7 @@ class TaintTest extends TestCase
|
||||
}
|
||||
$unsafe = new MyClass();
|
||||
echo $unsafe;',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'namespacedFunction' => [
|
||||
'<?php
|
||||
@ -1360,12 +1360,12 @@ class TaintTest extends TestCase
|
||||
}
|
||||
|
||||
echo identity($_GET[\'userinput\']);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'print' => [
|
||||
'<?php
|
||||
print($_GET["name"]);',
|
||||
'error_message' => 'TaintedInput - src' . DIRECTORY_SEPARATOR . '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',
|
||||
'error_message' => 'TaintedHtml - src' . DIRECTORY_SEPARATOR . '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',
|
||||
],
|
||||
'unpackArgs' => [
|
||||
'<?php
|
||||
@ -1373,7 +1373,7 @@ class TaintTest extends TestCase
|
||||
echo $args[0];
|
||||
}
|
||||
test(...$_GET["other"]);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'foreachArg' => [
|
||||
'<?php
|
||||
@ -1382,7 +1382,7 @@ class TaintTest extends TestCase
|
||||
foreach ($a as $arg) {
|
||||
echo $arg;
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'magicPropertyType' => [
|
||||
'<?php
|
||||
@ -1401,7 +1401,7 @@ class TaintTest extends TestCase
|
||||
$m = new Magic();
|
||||
$m->taint = $_GET["input"];
|
||||
echo $m->taint;',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintNestedArrayWithOffsetAccessedInForeach' => [
|
||||
'<?php
|
||||
@ -1411,7 +1411,7 @@ class TaintTest extends TestCase
|
||||
foreach ($a as $m) {
|
||||
echo $m["a"];
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintNestedArrayWithOffsetAccessedExplicitly' => [
|
||||
'<?php
|
||||
@ -1419,39 +1419,39 @@ class TaintTest extends TestCase
|
||||
$a[] = ["a" => $_GET["name"], "b" => "foo"];
|
||||
|
||||
echo $a[0]["a"];',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintThroughArrayMapExplicitClosure' => [
|
||||
'<?php
|
||||
$get = array_map(function($str) { return trim($str);}, $_GET);
|
||||
echo $get["test"];',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintThroughArrayMapExplicitTypedClosure' => [
|
||||
'<?php
|
||||
$get = array_map(function(string $str) : string { return trim($str);}, $_GET);
|
||||
echo $get["test"];',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintThroughArrayMapExplicitArrowFunction' => [
|
||||
'<?php
|
||||
$get = array_map(fn($str) => trim($str), $_GET);
|
||||
echo $get["test"];',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintThroughArrayMapImplicitFunctionCall' => [
|
||||
'<?php
|
||||
$a = ["test" => $_GET["name"]];
|
||||
$get = array_map("trim", $a);
|
||||
echo $get["test"];',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintFilterVar' => [
|
||||
'<?php
|
||||
$get = filter_var($_GET, FILTER_CALLBACK, ["options" => "trim"]);
|
||||
|
||||
echo $get["test"];',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintAfterReconciledType' => [
|
||||
'<?php
|
||||
@ -1459,7 +1459,7 @@ class TaintTest extends TestCase
|
||||
if (is_string($input)) {
|
||||
echo "$input";
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintExit' => [
|
||||
'<?php
|
||||
@ -1468,7 +1468,7 @@ class TaintTest extends TestCase
|
||||
} else {
|
||||
die($_GET[\'b\']);
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintSpecializedMethod' => [
|
||||
'<?php
|
||||
@ -1480,7 +1480,7 @@ class TaintTest extends TestCase
|
||||
}
|
||||
$a = new Unsafe();
|
||||
echo $a->isUnsafe();',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintSpecializedInstanceProperty' => [
|
||||
'<?php
|
||||
@ -1496,23 +1496,23 @@ class TaintTest extends TestCase
|
||||
$b = new StringHolder($_GET["x"]);
|
||||
|
||||
echo $b->x;',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintUnserialize' => [
|
||||
'<?php
|
||||
$cb = unserialize($_POST[\'x\']);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedUnserialize',
|
||||
],
|
||||
'taintCreateFunction' => [
|
||||
'<?php
|
||||
$cb = create_function(\'$a\', $_GET[\'x\']);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedEval',
|
||||
],
|
||||
'taintException' => [
|
||||
'<?php
|
||||
$e = new Exception();
|
||||
echo $e;',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintError' => [
|
||||
'<?php
|
||||
@ -1522,7 +1522,7 @@ class TaintTest extends TestCase
|
||||
} catch (TypeError $e) {
|
||||
echo "Caught: {$e->getTraceAsString()}\n";
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintThrowable' => [
|
||||
'<?php
|
||||
@ -1532,7 +1532,7 @@ class TaintTest extends TestCase
|
||||
} catch (Throwable $e) {
|
||||
echo "Caught: $e"; // TODO: ("Caught" . $e) does not work.
|
||||
}',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintReturnedArray' => [
|
||||
'<?php
|
||||
@ -1547,7 +1547,7 @@ class TaintTest extends TestCase
|
||||
$params = processParams($_GET);
|
||||
|
||||
echo $params["foo"];',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintFlow' => [
|
||||
'<?php
|
||||
@ -1560,7 +1560,7 @@ class TaintTest extends TestCase
|
||||
$r = $_GET["untrusted"];
|
||||
|
||||
echo some_stub($r);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintFlowProxy' => [
|
||||
'<?php
|
||||
@ -1578,7 +1578,7 @@ class TaintTest extends TestCase
|
||||
$r = $_GET["untrusted"];
|
||||
|
||||
some_stub($r);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedText',
|
||||
],
|
||||
'taintFlowProxyAndReturn' => [
|
||||
'<?php
|
||||
@ -1595,7 +1595,7 @@ class TaintTest extends TestCase
|
||||
$r = $_GET["untrusted"];
|
||||
|
||||
echo some_stub($r);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintFlowMethodProxyAndReturn' => [
|
||||
'<?php
|
||||
@ -1614,17 +1614,17 @@ class TaintTest extends TestCase
|
||||
$r = $_GET["untrusted"];
|
||||
|
||||
echo some_stub($r);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
'taintPopen' => [
|
||||
'<?php
|
||||
$cb = popen($_POST[\'x\'], \'r\');',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedShell',
|
||||
],
|
||||
'taintProcOpen' => [
|
||||
'<?php
|
||||
$cb = proc_open($_POST[\'x\'], [], []);',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedShell',
|
||||
],
|
||||
/*
|
||||
// TODO: Stubs do not support this type of inference even with $this->message = $message.
|
||||
@ -1633,7 +1633,7 @@ class TaintTest extends TestCase
|
||||
'<?php
|
||||
$x = new Exception($_GET["x"]);
|
||||
echo $x->getMessage();',
|
||||
'error_message' => 'TaintedInput',
|
||||
'error_message' => 'TaintedHtml',
|
||||
],
|
||||
*/
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user