1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 13:51:54 +01:00

Merge pull request #10163 from cgocast/5.x

This commit is contained in:
Bruce Weirdan 2023-08-31 16:41:56 +02:00 committed by GitHub
commit 77650e7b15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 83 additions and 1 deletions

View File

@ -11,6 +11,8 @@
- [BC] The `TDependentListKey` type was removed and replaced with an optional property of the `TIntRange` type.
- [BC] Value of constant `Psalm\Type\TaintKindGroup::ALL_INPUT` changed to reflect a new `TaintKind::INPUT_XPATH` have been added. Accordingly, default values for `$taint` parameters of `Psalm\Codebase::addTaintSource()` and `Psalm\Codebase::addTaintSink()` have been changed as well.
- [BC] Property `Config::$shepherd_host` was replaced with `Config::$shepherd_endpoint`
- [BC] Methods `Codebase::getSymbolLocation()` and `Codebase::getSymbolInformation()` were replaced with `Codebase::getSymbolLocationByReference()`

View File

@ -444,6 +444,7 @@
<xs:element name="TaintedTextWithQuotes" type="IssueHandlerType" minOccurs="0" />
<xs:element name="TaintedUnserialize" type="IssueHandlerType" minOccurs="0" />
<xs:element name="TaintedUserSecret" type="IssueHandlerType" minOccurs="0" />
<xs:element name="TaintedXpath" 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" />

View File

@ -297,6 +297,7 @@ Level 5 and above allows a more non-verifiable code, and higher levels are even
- [TaintedSystemSecret](issues/TaintedSystemSecret.md)
- [TaintedUnserialize](issues/TaintedUnserialize.md)
- [TaintedUserSecret](issues/TaintedUserSecret.md)
- [TaintedXpath](issues/TaintedXpath.md)
- [UncaughtThrowInGlobalScope](issues/UncaughtThrowInGlobalScope.md)
- [UnevaluatedCode](issues/UnevaluatedCode.md)
- [UnnecessaryVarAnnotation](issues/UnnecessaryVarAnnotation.md)

View File

@ -246,6 +246,7 @@
- [TaintedTextWithQuotes](issues/TaintedTextWithQuotes.md)
- [TaintedUnserialize](issues/TaintedUnserialize.md)
- [TaintedUserSecret](issues/TaintedUserSecret.md)
- [TaintedXpath](issues/TaintedXpath.md)
- [TooFewArguments](issues/TooFewArguments.md)
- [TooManyArguments](issues/TooManyArguments.md)
- [TooManyTemplateParams](issues/TooManyTemplateParams.md)

View File

@ -0,0 +1,12 @@
# TaintedXpath
Emitted when user-controlled input can be passed into to a xpath query.
```php
<?php
function queryExpression(SimpleXMLElement $xml) : array|false|null {
$expression = $_GET["expression"];
return $xml->xpath($expression);
}
```

View File

@ -24,6 +24,7 @@ use Psalm\Issue\TaintedSystemSecret;
use Psalm\Issue\TaintedTextWithQuotes;
use Psalm\Issue\TaintedUnserialize;
use Psalm\Issue\TaintedUserSecret;
use Psalm\Issue\TaintedXpath;
use Psalm\IssueBuffer;
use Psalm\Type\TaintKind;
@ -449,6 +450,15 @@ class TaintFlowGraph extends DataFlowGraph
);
break;
case TaintKind::INPUT_XPATH:
$issue = new TaintedXpath(
'Detected tainted xpath query',
$issue_location,
$issue_trace,
$path,
);
break;
default:
$issue = new TaintedCustom(
'Detected tainted ' . $matching_taint,

View File

@ -0,0 +1,8 @@
<?php
namespace Psalm\Issue;
final class TaintedXpath extends TaintedInput
{
public const SHORTCODE = 322;
}

View File

@ -20,6 +20,7 @@ final class TaintKind
public const INPUT_FILE = 'file';
public const INPUT_COOKIE = 'cookie';
public const INPUT_HEADER = 'header';
public const INPUT_XPATH = 'xpath';
public const USER_SECRET = 'user_secret';
public const SYSTEM_SECRET = 'system_secret';
}

View File

@ -21,5 +21,6 @@ final class TaintKindGroup
TaintKind::INPUT_FILE,
TaintKind::INPUT_HEADER,
TaintKind::INPUT_COOKIE,
TaintKind::INPUT_XPATH,
];
}

View File

@ -972,10 +972,15 @@ class DOMXPath
public function __construct(DOMDocument $document, bool $registerNodeNS = true) {}
/**
* @return DOMNodeList<DOMNode>|false
* @psalm-taint-sink xpath $expression
*/
public function evaluate(string $expression, ?DOMNode $contextNode = null, bool $registerNodeNS = true): mixed {}
/**
* @return DOMNodeList<DOMNode>|false
* @psalm-taint-sink xpath $expression
*/
public function query(string $expression, ?DOMNode $contextNode = null, bool $registerNodeNS = true): mixed {}

View File

@ -29,7 +29,10 @@ function simplexml_import_dom(SimpleXMLElement|DOMNode $node, ?string $class_nam
*/
class SimpleXMLElement implements Traversable, Countable
{
/** @return array<array-key, SimpleXMLElement>|null|false */
/**
* @return array<array-key, SimpleXMLElement>|null|false
* @psalm-taint-sink xpath $expression
*/
public function xpath(string $expression) {}
public function registerXPathNamespace(string $prefix, string $namespace): bool {}

View File

@ -750,6 +750,19 @@ class TaintTest extends TestCase
$mysqli->query("$a$b$c$d");',
],
'querySimpleXMLElement' => [
'code' => '<?php
/**
* @psalm-taint-escape xpath
*/
function my_escaping_function_for_xpath(string input) : string {};
function queryExpression(SimpleXMLElement $xml) : array|false|null {
$expression = $_GET["expression"];
$expression = my_escaping_function_for_xpath($expression);
return $xml->xpath($expression);
}',
],
];
}
@ -2503,6 +2516,30 @@ class TaintTest extends TestCase
$function->invoke();',
'error_message' => 'TaintedCallable',
],
'querySimpleXMLElement' => [
'code' => '<?php
function queryExpression(SimpleXMLElement $xml) : array|false|null {
$expression = $_GET["expression"];
return $xml->xpath($expression);
}',
'error_message' => 'TaintedXpath',
],
'queryDOMXPath' => [
'code' => '<?php
function queryExpression(DOMXPath $xpath) : mixed {
$expression = $_GET["expression"];
return $xpath->query($expression);
}',
'error_message' => 'TaintedXpath',
],
'evaluateDOMXPath' => [
'code' => '<?php
function evaluateExpression(DOMXPath $xpath) : mixed {
$expression = $_GET["expression"];
return $xpath->evaluate($expression);
}',
'error_message' => 'TaintedXpath',
],
];
}