mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
Merge pull request #3598 from asger-semmle/js/regexp-test
Approved by esbena
This commit is contained in:
@@ -1355,6 +1355,11 @@ class EqualityTest extends @equalitytest, Comparison {
|
||||
(this instanceof NEqExpr or this instanceof StrictNEqExpr) and
|
||||
result = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the equality operator is strict (`===` or `!==`).
|
||||
*/
|
||||
predicate isStrict() { this instanceof StrictEqExpr or this instanceof StrictNEqExpr }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -629,4 +629,153 @@ module StringOps {
|
||||
class HtmlConcatenationLeaf extends ConcatenationLeaf {
|
||||
HtmlConcatenationLeaf() { getRoot() instanceof HtmlConcatenationRoot }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node whose boolean value indicates whether a regexp matches a given string.
|
||||
*
|
||||
* For example, the condition of each of the following `if`-statements are `RegExpTest` nodes:
|
||||
* ```js
|
||||
* if (regexp.test(str)) { ... }
|
||||
* if (regexp.exec(str) != null) { ... }
|
||||
* if (str.matches(regexp)) { ... }
|
||||
* ```
|
||||
*
|
||||
* Note that `RegExpTest` represents a boolean-valued expression or one
|
||||
* that is coerced to a boolean, which is not always the same as the call that performs the
|
||||
* regexp-matching. For example, the `exec` call below is not itself a `RegExpTest`,
|
||||
* but the `match` variable in the condition is:
|
||||
* ```js
|
||||
* let match = regexp.exec(str);
|
||||
* if (!match) { ... } // <--- 'match' is the RegExpTest
|
||||
* ```
|
||||
*/
|
||||
class RegExpTest extends DataFlow::Node {
|
||||
RegExpTest::Range range;
|
||||
|
||||
RegExpTest() { this = range }
|
||||
|
||||
/**
|
||||
* Gets the AST of the regular expression used in the test, if it can be seen locally.
|
||||
*/
|
||||
RegExpTerm getRegExp() {
|
||||
result = getRegExpOperand().getALocalSource().(DataFlow::RegExpCreationNode).getRoot()
|
||||
or
|
||||
result = range.getRegExpOperand(true).asExpr().(StringLiteral).asRegExp()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data flow node corresponding to the regular expression object used in the test.
|
||||
*
|
||||
* In some cases this represents a string value being coerced to a RegExp object.
|
||||
*/
|
||||
DataFlow::Node getRegExpOperand() { result = range.getRegExpOperand(_) }
|
||||
|
||||
/**
|
||||
* Gets the data flow node corresponding to the string being tested against the regular expression.
|
||||
*/
|
||||
DataFlow::Node getStringOperand() { result = range.getStringOperand() }
|
||||
|
||||
/**
|
||||
* Gets the return value indicating that the string matched the regular expression.
|
||||
*
|
||||
* For example, for `regexp.exec(str) == null`, the polarity is `false`, and for
|
||||
* `regexp.exec(str) != null` the polarity is `true`.
|
||||
*/
|
||||
boolean getPolarity() { result = range.getPolarity() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Companion module to the `RegExpTest` class.
|
||||
*/
|
||||
module RegExpTest {
|
||||
/**
|
||||
* A data flow node whose boolean value indicates whether a regexp matches a given string.
|
||||
*
|
||||
* This class can be extended to contribute new kinds of `RegExpTest` nodes.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the data flow node corresponding to the regular expression object used in the test.
|
||||
*/
|
||||
abstract DataFlow::Node getRegExpOperand(boolean coerced);
|
||||
|
||||
/**
|
||||
* Gets the data flow node corresponding to the string being tested against the regular expression.
|
||||
*/
|
||||
abstract DataFlow::Node getStringOperand();
|
||||
|
||||
/**
|
||||
* Gets the return value indicating that the string matched the regular expression.
|
||||
*/
|
||||
boolean getPolarity() { result = true }
|
||||
}
|
||||
|
||||
private class TestCall extends Range, DataFlow::MethodCallNode {
|
||||
TestCall() { getMethodName() = "test" }
|
||||
|
||||
override DataFlow::Node getRegExpOperand(boolean coerced) {
|
||||
result = getReceiver() and coerced = false
|
||||
}
|
||||
|
||||
override DataFlow::Node getStringOperand() { result = getArgument(0) }
|
||||
}
|
||||
|
||||
private class MatchesCall extends Range, DataFlow::MethodCallNode {
|
||||
MatchesCall() { getMethodName() = "matches" }
|
||||
|
||||
override DataFlow::Node getRegExpOperand(boolean coerced) {
|
||||
result = getArgument(0) and coerced = true
|
||||
}
|
||||
|
||||
override DataFlow::Node getStringOperand() { result = getReceiver() }
|
||||
}
|
||||
|
||||
private class ExecCall extends DataFlow::MethodCallNode {
|
||||
ExecCall() { getMethodName() = "exec" }
|
||||
}
|
||||
|
||||
private predicate isCoercedToBoolean(Expr e) {
|
||||
e = any(ConditionGuardNode guard).getTest()
|
||||
or
|
||||
e = any(LogNotExpr n).getOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` evaluating to `polarity` implies that `operand` is not null.
|
||||
*/
|
||||
private predicate impliesNotNull(Expr e, Expr operand, boolean polarity) {
|
||||
exists(EqualityTest test, Expr other |
|
||||
e = test and
|
||||
polarity = test.getPolarity().booleanNot() and
|
||||
test.hasOperands(other, operand) and
|
||||
SyntacticConstants::isNullOrUndefined(other) and
|
||||
not (
|
||||
// 'exec() === undefined' doesn't work
|
||||
other instanceof SyntacticConstants::UndefinedConstant and
|
||||
test.isStrict()
|
||||
)
|
||||
)
|
||||
or
|
||||
isCoercedToBoolean(e) and
|
||||
operand = e and
|
||||
polarity = true
|
||||
}
|
||||
|
||||
private class ExecTest extends Range, DataFlow::ValueNode {
|
||||
ExecCall exec;
|
||||
boolean polarity;
|
||||
|
||||
ExecTest() {
|
||||
exists(Expr use | exec.flowsToExpr(use) | impliesNotNull(astNode, use, polarity))
|
||||
}
|
||||
|
||||
override DataFlow::Node getRegExpOperand(boolean coerced) {
|
||||
result = exec.getReceiver() and coerced = false
|
||||
}
|
||||
|
||||
override DataFlow::Node getStringOperand() { result = exec.getArgument(0) }
|
||||
|
||||
override boolean getPolarity() { result = polarity }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,18 +78,16 @@ module Shared {
|
||||
* A sanitizer guard that checks for the existence of HTML chars in a string.
|
||||
* E.g. `/["'&<>]/.exec(str)`.
|
||||
*/
|
||||
class ContainsHTMLGuard extends SanitizerGuard, DataFlow::MethodCallNode {
|
||||
DataFlow::RegExpCreationNode regExp;
|
||||
|
||||
class ContainsHTMLGuard extends SanitizerGuard, StringOps::RegExpTest {
|
||||
ContainsHTMLGuard() {
|
||||
this.getMethodName() = ["test", "exec"] and
|
||||
this.getReceiver().getALocalSource() = regExp and
|
||||
regExp.getRoot() instanceof RegExpCharacterClass and
|
||||
forall(string s | s = ["\"", "&", "<", ">"] | regExp.getRoot().getAMatchedString() = s)
|
||||
exists(RegExpCharacterClass regExp |
|
||||
regExp = getRegExp() and
|
||||
forall(string s | s = ["\"", "&", "<", ">"] | regExp.getAMatchedString() = s)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sanitizes(boolean outcome, Expr e) {
|
||||
outcome = false and e = this.getArgument(0).asExpr()
|
||||
outcome = getPolarity().booleanNot() and e = this.getStringOperand().asExpr()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
regexpTest
|
||||
| tst.js:6:9:6:28 | /^[a-z]+$/.test(str) |
|
||||
| tst.js:7:9:7:36 | /^[a-z] ... != null |
|
||||
| tst.js:8:9:8:28 | /^[a-z]+$/.exec(str) |
|
||||
| tst.js:9:9:9:31 | str.mat ... -z]+$/) |
|
||||
| tst.js:10:9:10:31 | str.mat ... -z]+$") |
|
||||
| tst.js:12:9:12:24 | regexp.test(str) |
|
||||
| tst.js:13:9:13:32 | regexp. ... != null |
|
||||
| tst.js:14:9:14:24 | regexp.exec(str) |
|
||||
| tst.js:15:9:15:27 | str.matches(regexp) |
|
||||
| tst.js:18:9:18:13 | match |
|
||||
| tst.js:19:10:19:14 | match |
|
||||
| tst.js:20:9:20:21 | match == null |
|
||||
| tst.js:21:9:21:21 | match != null |
|
||||
| tst.js:22:9:22:13 | match |
|
||||
| tst.js:25:23:25:27 | match |
|
||||
| tst.js:29:21:29:36 | regexp.test(str) |
|
||||
| tst.js:33:21:33:39 | str.matches(regexp) |
|
||||
| tst.js:40:9:40:37 | regexp. ... defined |
|
||||
#select
|
||||
| tst.js:6:9:6:28 | /^[a-z]+$/.test(str) | tst.js:6:10:6:17 | ^[a-z]+$ | tst.js:6:9:6:18 | /^[a-z]+$/ | tst.js:6:25:6:27 | str | true |
|
||||
| tst.js:7:9:7:36 | /^[a-z] ... != null | tst.js:7:10:7:17 | ^[a-z]+$ | tst.js:7:9:7:18 | /^[a-z]+$/ | tst.js:7:25:7:27 | str | true |
|
||||
| tst.js:8:9:8:28 | /^[a-z]+$/.exec(str) | tst.js:8:10:8:17 | ^[a-z]+$ | tst.js:8:9:8:18 | /^[a-z]+$/ | tst.js:8:25:8:27 | str | true |
|
||||
| tst.js:9:9:9:31 | str.mat ... -z]+$/) | tst.js:9:22:9:29 | ^[a-z]+$ | tst.js:9:21:9:30 | /^[a-z]+$/ | tst.js:9:9:9:11 | str | true |
|
||||
| tst.js:10:9:10:31 | str.mat ... -z]+$") | tst.js:10:22:10:29 | ^[a-z]+$ | tst.js:10:21:10:30 | "^[a-z]+$" | tst.js:10:9:10:11 | str | true |
|
||||
| tst.js:12:9:12:24 | regexp.test(str) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:12:9:12:14 | regexp | tst.js:12:21:12:23 | str | true |
|
||||
| tst.js:13:9:13:32 | regexp. ... != null | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:13:9:13:14 | regexp | tst.js:13:21:13:23 | str | true |
|
||||
| tst.js:14:9:14:24 | regexp.exec(str) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:14:9:14:14 | regexp | tst.js:14:21:14:23 | str | true |
|
||||
| tst.js:15:9:15:27 | str.matches(regexp) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:15:21:15:26 | regexp | tst.js:15:9:15:11 | str | true |
|
||||
| tst.js:18:9:18:13 | match | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true |
|
||||
| tst.js:19:10:19:14 | match | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true |
|
||||
| tst.js:20:9:20:21 | match == null | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | false |
|
||||
| tst.js:21:9:21:21 | match != null | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true |
|
||||
| tst.js:22:9:22:13 | match | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true |
|
||||
| tst.js:25:23:25:27 | match | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:17:17:17:22 | regexp | tst.js:17:29:17:31 | str | true |
|
||||
| tst.js:29:21:29:36 | regexp.test(str) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:29:21:29:26 | regexp | tst.js:29:33:29:35 | str | true |
|
||||
| tst.js:33:21:33:39 | str.matches(regexp) | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:33:33:33:38 | regexp | tst.js:33:21:33:23 | str | true |
|
||||
| tst.js:40:9:40:37 | regexp. ... defined | tst.js:3:17:3:24 | ^[a-z]+$ | tst.js:40:9:40:14 | regexp | tst.js:40:21:40:23 | str | false |
|
||||
@@ -0,0 +1,6 @@
|
||||
import javascript
|
||||
|
||||
query StringOps::RegExpTest regexpTest() { any() }
|
||||
|
||||
from StringOps::RegExpTest test
|
||||
select test, test.getRegExp(), test.getRegExpOperand(), test.getStringOperand(), test.getPolarity()
|
||||
42
javascript/ql/test/library-tests/StringOps/RegExpTest/tst.js
Normal file
42
javascript/ql/test/library-tests/StringOps/RegExpTest/tst.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import 'dummy';
|
||||
|
||||
const regexp = /^[a-z]+$/;
|
||||
|
||||
function f(str) {
|
||||
if (/^[a-z]+$/.test(str)) {}
|
||||
if (/^[a-z]+$/.exec(str) != null) {}
|
||||
if (/^[a-z]+$/.exec(str)) {}
|
||||
if (str.matches(/^[a-z]+$/)) {}
|
||||
if (str.matches("^[a-z]+$")) {}
|
||||
|
||||
if (regexp.test(str)) {}
|
||||
if (regexp.exec(str) != null) {}
|
||||
if (regexp.exec(str)) {}
|
||||
if (str.matches(regexp)) {}
|
||||
|
||||
let match = regexp.exec(str);
|
||||
if (match) {}
|
||||
if (!match) {}
|
||||
if (match == null) {}
|
||||
if (match != null) {}
|
||||
if (match && match[1] == "") {}
|
||||
|
||||
something({
|
||||
someOption: !!match
|
||||
});
|
||||
|
||||
something({
|
||||
someOption: regexp.test(str)
|
||||
});
|
||||
|
||||
something({
|
||||
someOption: str.matches(regexp)
|
||||
});
|
||||
|
||||
something({
|
||||
someOption: regexp.exec(str) // not recognized as RegExpTest
|
||||
})
|
||||
|
||||
if (regexp.exec(str) == undefined) {}
|
||||
if (regexp.exec(str) === undefined) {} // not recognized as RegExpTest
|
||||
}
|
||||
@@ -84,6 +84,24 @@ nodes
|
||||
| react-native.js:8:18:8:24 | tainted |
|
||||
| react-native.js:9:27:9:33 | tainted |
|
||||
| react-native.js:9:27:9:33 | tainted |
|
||||
| sanitiser.js:16:7:16:27 | tainted |
|
||||
| sanitiser.js:16:17:16:27 | window.name |
|
||||
| sanitiser.js:16:17:16:27 | window.name |
|
||||
| sanitiser.js:23:21:23:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:23:21:23:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:23:29:23:35 | tainted |
|
||||
| sanitiser.js:30:21:30:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:30:21:30:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:30:29:30:35 | tainted |
|
||||
| sanitiser.js:33:21:33:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:33:21:33:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:33:29:33:35 | tainted |
|
||||
| sanitiser.js:38:21:38:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:38:21:38:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:38:29:38:35 | tainted |
|
||||
| sanitiser.js:45:21:45:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:45:21:45:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:45:29:45:35 | tainted |
|
||||
| stored-xss.js:2:39:2:55 | document.location |
|
||||
| stored-xss.js:2:39:2:55 | document.location |
|
||||
| stored-xss.js:2:39:2:62 | documen ... .search |
|
||||
@@ -514,6 +532,23 @@ edges
|
||||
| react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted |
|
||||
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
|
||||
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
|
||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:23:29:23:35 | tainted |
|
||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:30:29:30:35 | tainted |
|
||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:33:29:33:35 | tainted |
|
||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:38:29:38:35 | tainted |
|
||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:45:29:45:35 | tainted |
|
||||
| sanitiser.js:16:17:16:27 | window.name | sanitiser.js:16:7:16:27 | tainted |
|
||||
| sanitiser.js:16:17:16:27 | window.name | sanitiser.js:16:7:16:27 | tainted |
|
||||
| sanitiser.js:23:29:23:35 | tainted | sanitiser.js:23:21:23:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:23:29:23:35 | tainted | sanitiser.js:23:21:23:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:30:29:30:35 | tainted | sanitiser.js:30:21:30:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:30:29:30:35 | tainted | sanitiser.js:30:21:30:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:33:29:33:35 | tainted | sanitiser.js:33:21:33:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:33:29:33:35 | tainted | sanitiser.js:33:21:33:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:38:29:38:35 | tainted | sanitiser.js:38:21:38:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:38:29:38:35 | tainted | sanitiser.js:38:21:38:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:45:29:45:35 | tainted | sanitiser.js:45:21:45:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:45:29:45:35 | tainted | sanitiser.js:45:21:45:44 | '<b>' + ... '</b>' |
|
||||
| stored-xss.js:2:39:2:55 | document.location | stored-xss.js:2:39:2:62 | documen ... .search |
|
||||
| stored-xss.js:2:39:2:55 | document.location | stored-xss.js:2:39:2:62 | documen ... .search |
|
||||
| stored-xss.js:2:39:2:62 | documen ... .search | stored-xss.js:5:20:5:52 | session ... ssion') |
|
||||
@@ -834,6 +869,11 @@ edges
|
||||
| optionalSanitizer.js:45:18:45:56 | sanitiz ... target | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value |
|
||||
| react-native.js:8:18:8:24 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:8:18:8:24 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value |
|
||||
| react-native.js:9:27:9:33 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:9:27:9:33 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value |
|
||||
| sanitiser.js:23:21:23:44 | '<b>' + ... '</b>' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:23:21:23:44 | '<b>' + ... '</b>' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value |
|
||||
| sanitiser.js:30:21:30:44 | '<b>' + ... '</b>' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:30:21:30:44 | '<b>' + ... '</b>' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value |
|
||||
| sanitiser.js:33:21:33:44 | '<b>' + ... '</b>' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:33:21:33:44 | '<b>' + ... '</b>' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value |
|
||||
| sanitiser.js:38:21:38:44 | '<b>' + ... '</b>' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:38:21:38:44 | '<b>' + ... '</b>' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value |
|
||||
| sanitiser.js:45:21:45:44 | '<b>' + ... '</b>' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:45:21:45:44 | '<b>' + ... '</b>' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value |
|
||||
| stored-xss.js:5:20:5:52 | session ... ssion') | stored-xss.js:2:39:2:55 | document.location | stored-xss.js:5:20:5:52 | session ... ssion') | Cross-site scripting vulnerability due to $@. | stored-xss.js:2:39:2:55 | document.location | user-provided value |
|
||||
| stored-xss.js:8:20:8:48 | localSt ... local') | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:8:20:8:48 | localSt ... local') | Cross-site scripting vulnerability due to $@. | stored-xss.js:3:35:3:51 | document.location | user-provided value |
|
||||
| stored-xss.js:12:20:12:54 | "<a hre ... ar</a>" | stored-xss.js:3:35:3:51 | document.location | stored-xss.js:12:20:12:54 | "<a hre ... ar</a>" | Cross-site scripting vulnerability due to $@. | stored-xss.js:3:35:3:51 | document.location | user-provided value |
|
||||
|
||||
@@ -84,6 +84,24 @@ nodes
|
||||
| react-native.js:8:18:8:24 | tainted |
|
||||
| react-native.js:9:27:9:33 | tainted |
|
||||
| react-native.js:9:27:9:33 | tainted |
|
||||
| sanitiser.js:16:7:16:27 | tainted |
|
||||
| sanitiser.js:16:17:16:27 | window.name |
|
||||
| sanitiser.js:16:17:16:27 | window.name |
|
||||
| sanitiser.js:23:21:23:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:23:21:23:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:23:29:23:35 | tainted |
|
||||
| sanitiser.js:30:21:30:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:30:21:30:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:30:29:30:35 | tainted |
|
||||
| sanitiser.js:33:21:33:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:33:21:33:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:33:29:33:35 | tainted |
|
||||
| sanitiser.js:38:21:38:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:38:21:38:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:38:29:38:35 | tainted |
|
||||
| sanitiser.js:45:21:45:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:45:21:45:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:45:29:45:35 | tainted |
|
||||
| stored-xss.js:2:39:2:55 | document.location |
|
||||
| stored-xss.js:2:39:2:55 | document.location |
|
||||
| stored-xss.js:2:39:2:62 | documen ... .search |
|
||||
@@ -518,6 +536,23 @@ edges
|
||||
| react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted |
|
||||
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
|
||||
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
|
||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:23:29:23:35 | tainted |
|
||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:30:29:30:35 | tainted |
|
||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:33:29:33:35 | tainted |
|
||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:38:29:38:35 | tainted |
|
||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:45:29:45:35 | tainted |
|
||||
| sanitiser.js:16:17:16:27 | window.name | sanitiser.js:16:7:16:27 | tainted |
|
||||
| sanitiser.js:16:17:16:27 | window.name | sanitiser.js:16:7:16:27 | tainted |
|
||||
| sanitiser.js:23:29:23:35 | tainted | sanitiser.js:23:21:23:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:23:29:23:35 | tainted | sanitiser.js:23:21:23:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:30:29:30:35 | tainted | sanitiser.js:30:21:30:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:30:29:30:35 | tainted | sanitiser.js:30:21:30:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:33:29:33:35 | tainted | sanitiser.js:33:21:33:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:33:29:33:35 | tainted | sanitiser.js:33:21:33:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:38:29:38:35 | tainted | sanitiser.js:38:21:38:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:38:29:38:35 | tainted | sanitiser.js:38:21:38:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:45:29:45:35 | tainted | sanitiser.js:45:21:45:44 | '<b>' + ... '</b>' |
|
||||
| sanitiser.js:45:29:45:35 | tainted | sanitiser.js:45:21:45:44 | '<b>' + ... '</b>' |
|
||||
| stored-xss.js:2:39:2:55 | document.location | stored-xss.js:2:39:2:62 | documen ... .search |
|
||||
| stored-xss.js:2:39:2:55 | document.location | stored-xss.js:2:39:2:62 | documen ... .search |
|
||||
| stored-xss.js:2:39:2:62 | documen ... .search | stored-xss.js:5:20:5:52 | session ... ssion') |
|
||||
|
||||
@@ -17,4 +17,31 @@ function test() {
|
||||
var elt = document.createElement();
|
||||
elt.innerHTML = "<a href=\"" + escapeAttr(tainted) + "\">" + escapeHtml(tainted) + "</a>"; // OK
|
||||
elt.innerHTML = "<div>" + escapeAttr(tainted) + "</div>"; // NOT OK, but not flagged
|
||||
|
||||
const regex = /[<>'"&]/;
|
||||
if (regex.test(tainted)) {
|
||||
elt.innerHTML = '<b>' + tainted + '</b>'; // NOT OK
|
||||
} else {
|
||||
elt.innerHTML = '<b>' + tainted + '</b>'; // OK
|
||||
}
|
||||
if (!regex.test(tainted)) {
|
||||
elt.innerHTML = '<b>' + tainted + '</b>'; // OK
|
||||
} else {
|
||||
elt.innerHTML = '<b>' + tainted + '</b>'; // NOT OK
|
||||
}
|
||||
if (regex.exec(tainted)) {
|
||||
elt.innerHTML = '<b>' + tainted + '</b>'; // NOT OK
|
||||
} else {
|
||||
elt.innerHTML = '<b>' + tainted + '</b>'; // OK
|
||||
}
|
||||
if (regex.exec(tainted) != null) {
|
||||
elt.innerHTML = '<b>' + tainted + '</b>'; // NOT OK
|
||||
} else {
|
||||
elt.innerHTML = '<b>' + tainted + '</b>'; // OK
|
||||
}
|
||||
if (regex.exec(tainted) == null) {
|
||||
elt.innerHTML = '<b>' + tainted + '</b>'; // OK
|
||||
} else {
|
||||
elt.innerHTML = '<b>' + tainted + '</b>'; // NOT OK
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user