mirror of
https://github.com/github/codeql.git
synced 2025-12-17 09:13:20 +01:00
JS: introduce MembershipTests.qll and use in two locations
This commit is contained in:
@@ -10,6 +10,9 @@
|
|||||||
- [marsdb](https://www.npmjs.com/package/marsdb)
|
- [marsdb](https://www.npmjs.com/package/marsdb)
|
||||||
- [minimongo](https://www.npmjs.com/package/minimongo/)
|
- [minimongo](https://www.npmjs.com/package/minimongo/)
|
||||||
|
|
||||||
|
* The analysis of sanitizers has improved, leading to more accurate
|
||||||
|
results from the security queries.
|
||||||
|
|
||||||
## New queries
|
## New queries
|
||||||
|
|
||||||
| **Query** | **Tags** | **Purpose** |
|
| **Query** | **Tags** | **Purpose** |
|
||||||
|
|||||||
@@ -61,18 +61,11 @@ DataFlow::Node schemeCheck(DataFlow::Node nd, DangerousScheme scheme) {
|
|||||||
sw.getSubstring().mayHaveStringValue(scheme)
|
sw.getSubstring().mayHaveStringValue(scheme)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// check of the form `array.includes(getScheme(nd))`
|
exists(DataFlow::Node candidate, MembershipTest t |
|
||||||
exists(InclusionTest test, DataFlow::ArrayCreationNode array | test = result |
|
result = t and
|
||||||
schemeOf(nd).flowsTo(test.getContainedNode()) and
|
t.getCandidate() = candidate and
|
||||||
array.flowsTo(test.getContainerNode()) and
|
t.getAMemberString() = scheme.getWithOrWithoutColon() and
|
||||||
array.getAnElement().mayHaveStringValue(scheme.getWithOrWithoutColon())
|
schemeOf(nd).flowsTo(candidate)
|
||||||
)
|
|
||||||
or
|
|
||||||
// check of the form `getScheme(nd) === scheme`
|
|
||||||
exists(EqualityTest test, Expr op1, Expr op2 | test.flow() = result |
|
|
||||||
test.hasOperands(op1, op2) and
|
|
||||||
schemeOf(nd).flowsToExpr(op1) and
|
|
||||||
op2.mayHaveStringValue(scheme.getWithOrWithoutColon())
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// propagate through trimming, case conversion, and regexp replace
|
// propagate through trimming, case conversion, and regexp replace
|
||||||
|
|||||||
@@ -449,8 +449,10 @@ class BlacklistInclusionGuard extends DataFlow::LabeledBarrierGuardNode, Inclusi
|
|||||||
*/
|
*/
|
||||||
class WhitelistInclusionGuard extends DataFlow::LabeledBarrierGuardNode {
|
class WhitelistInclusionGuard extends DataFlow::LabeledBarrierGuardNode {
|
||||||
WhitelistInclusionGuard() {
|
WhitelistInclusionGuard() {
|
||||||
this instanceof TaintTracking::PositiveIndexOfSanitizer or
|
this instanceof TaintTracking::PositiveIndexOfSanitizer
|
||||||
this instanceof TaintTracking::InclusionSanitizer
|
or
|
||||||
|
this instanceof TaintTracking::MembershipTestSanitizer and
|
||||||
|
not this instanceof MembershipTest::ObjectPropertyNameMembershipTest // handled with more precision in `HasOwnPropertyGuard`
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel lbl) {
|
override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel lbl) {
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import semmle.javascript.JsonParsers
|
|||||||
import semmle.javascript.JSX
|
import semmle.javascript.JSX
|
||||||
import semmle.javascript.Lines
|
import semmle.javascript.Lines
|
||||||
import semmle.javascript.Locations
|
import semmle.javascript.Locations
|
||||||
|
import semmle.javascript.MembershipTests
|
||||||
import semmle.javascript.Modules
|
import semmle.javascript.Modules
|
||||||
import semmle.javascript.NodeJS
|
import semmle.javascript.NodeJS
|
||||||
import semmle.javascript.NPM
|
import semmle.javascript.NPM
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
private import javascript
|
private import javascript
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A expression that checks if an element is contained in an array
|
* An expression that checks if an element is contained in an array
|
||||||
* or is a substring of another string.
|
* or is a substring of another string.
|
||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
|
|||||||
257
javascript/ql/src/semmle/javascript/MembershipTests.qll
Normal file
257
javascript/ql/src/semmle/javascript/MembershipTests.qll
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
/**
|
||||||
|
* Provides classes for recognizing membership tests.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import javascript
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An expression that tests if a candidate is a member of a collection.
|
||||||
|
*
|
||||||
|
* Additional tests can be added by subclassing `MembershipTest::Range`
|
||||||
|
*/
|
||||||
|
class MembershipTest extends DataFlow::Node {
|
||||||
|
MembershipTest::Range range;
|
||||||
|
|
||||||
|
MembershipTest() { this = range }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the candidate of this test.
|
||||||
|
*/
|
||||||
|
DataFlow::Node tests() { result = range.tests() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string that is a member of the collection of this test, if
|
||||||
|
* it can be determined.
|
||||||
|
*/
|
||||||
|
string getAMemberString() { result = range.getAMemberString() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a node that is a member of the collection of this test, if
|
||||||
|
* it can be determined.
|
||||||
|
*/
|
||||||
|
DataFlow::Node getAMemberNode() { result = range.getAMemberNode() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the polarity of this test.
|
||||||
|
*
|
||||||
|
* If the polarity is `false` the test returns `true` if the
|
||||||
|
* collection does not contain the candidate.
|
||||||
|
*/
|
||||||
|
boolean getPolarity() { result = range.getPolarity() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides classes for recognizing membership tests.
|
||||||
|
*/
|
||||||
|
module MembershipTest {
|
||||||
|
/**
|
||||||
|
* An expression that tests if a candidate is a member of a collection.
|
||||||
|
*/
|
||||||
|
abstract class Range extends DataFlow::Node {
|
||||||
|
/**
|
||||||
|
* Gets the candidate of this test.
|
||||||
|
*/
|
||||||
|
abstract DataFlow::Node tests();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string that is a member of the collection of this test, if
|
||||||
|
* it can be determined.
|
||||||
|
*/
|
||||||
|
string getAMemberString() { this.getAMemberNode().mayHaveStringValue(result) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a node that is a member of the collection of this test, if
|
||||||
|
* it can be determined.
|
||||||
|
*/
|
||||||
|
DataFlow::Node getAMemberNode() { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the polarity of this test.
|
||||||
|
*
|
||||||
|
* If the polarity is `false` the test returns `true` if the
|
||||||
|
* collection does not contain the candidate.
|
||||||
|
*/
|
||||||
|
boolean getPolarity() { result = true }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An `InclusionTest` viewed as a `MembershipTest`.
|
||||||
|
*/
|
||||||
|
private class OrdinaryInclusionTest extends InclusionTest, MembershipTest::Range {
|
||||||
|
override DataFlow::Node tests() { result = this.getContainedNode() }
|
||||||
|
|
||||||
|
override boolean getPolarity() { result = InclusionTest.super.getPolarity() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test for whether a candidate is a member of an array.
|
||||||
|
*/
|
||||||
|
class ArrayMembershipTest extends OrdinaryInclusionTest {
|
||||||
|
DataFlow::ArrayCreationNode array;
|
||||||
|
|
||||||
|
ArrayMembershipTest() { array.flowsTo(this.getContainerNode()) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the array of this test.
|
||||||
|
*/
|
||||||
|
DataFlow::ArrayCreationNode getArray() { result = array }
|
||||||
|
|
||||||
|
override DataFlow::Node getAMemberNode() { result = array.getAnElement() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test for whether a candidate is a member of an array constructed
|
||||||
|
* from a call to `String.prototype.split`.
|
||||||
|
*/
|
||||||
|
private class ShorthandArrayMembershipTest extends OrdinaryInclusionTest {
|
||||||
|
DataFlow::MethodCallNode split;
|
||||||
|
|
||||||
|
ShorthandArrayMembershipTest() {
|
||||||
|
split.getMethodName() = "split" and
|
||||||
|
split.getNumArgument() = [1, 2] and
|
||||||
|
split.flowsTo(this.getContainerNode())
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getAMemberString() {
|
||||||
|
exists(string toSplit |
|
||||||
|
split.getReceiver().getStringValue() = toSplit and
|
||||||
|
result = toSplit.splitAt(split.getArgument(0).getStringValue())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An `EqualityTest` viewed as a `MembershipTest`.
|
||||||
|
*/
|
||||||
|
private class EqualityLeftMembershipTest extends MembershipTest::Range, DataFlow::ValueNode {
|
||||||
|
override EqualityTest astNode;
|
||||||
|
|
||||||
|
override DataFlow::Node tests() { astNode.getLeftOperand() = result.asExpr() }
|
||||||
|
|
||||||
|
override DataFlow::Node getAMemberNode() { result = astNode.getRightOperand().flow() }
|
||||||
|
|
||||||
|
override boolean getPolarity() { result = astNode.getPolarity() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An `EqualityTest` viewed as a `MembershipTest`.
|
||||||
|
*/
|
||||||
|
private class EqualityRightMembershipTest extends MembershipTest::Range, DataFlow::ValueNode {
|
||||||
|
override EqualityTest astNode;
|
||||||
|
|
||||||
|
override DataFlow::Node tests() { astNode.getRightOperand() = result.asExpr() }
|
||||||
|
|
||||||
|
override DataFlow::Node getAMemberNode() { result = astNode.getLeftOperand().flow() }
|
||||||
|
|
||||||
|
override boolean getPolarity() { result = astNode.getPolarity() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A regular expression that enumerates all of its matched strings.
|
||||||
|
*/
|
||||||
|
private class EnumerationRegExp extends RegExpTerm {
|
||||||
|
EnumerationRegExp() {
|
||||||
|
this.isRootTerm() and
|
||||||
|
RegExp::isFullyAnchoredTerm(this) and
|
||||||
|
exists(RegExpTerm child | this.getAChild*() = child |
|
||||||
|
child instanceof RegExpSequence or
|
||||||
|
child instanceof RegExpCaret or
|
||||||
|
child instanceof RegExpDollar or
|
||||||
|
child instanceof RegExpConstant or
|
||||||
|
child instanceof RegExpAlt or
|
||||||
|
child instanceof RegExpGroup
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a string matched by this regular expression.
|
||||||
|
*/
|
||||||
|
string getAMember() { result = this.getAChild*().getAMatchedString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test for whether a string is matched by a regular expression that
|
||||||
|
* enumerates all of its matched strings.
|
||||||
|
*/
|
||||||
|
private class RegExpEnumerationTest extends MembershipTest::Range, DataFlow::Node {
|
||||||
|
EnumerationRegExp enumeration;
|
||||||
|
DataFlow::Node candidateNode;
|
||||||
|
boolean polarity;
|
||||||
|
|
||||||
|
RegExpEnumerationTest() {
|
||||||
|
exists(
|
||||||
|
DataFlow::Node tests, DataFlow::MethodCallNode mcn, DataFlow::Node base, string m,
|
||||||
|
DataFlow::Node firstArg
|
||||||
|
|
|
||||||
|
(
|
||||||
|
this = tests and
|
||||||
|
any(ConditionGuardNode g).getTest() = tests.asExpr() and
|
||||||
|
polarity = true
|
||||||
|
or
|
||||||
|
exists(EqualityTest eq, Expr null |
|
||||||
|
eq.flow() = this and
|
||||||
|
polarity = eq.getPolarity().booleanNot() and
|
||||||
|
eq.hasOperands(tests.asExpr(), null) and
|
||||||
|
SyntacticConstants::isNull(null)
|
||||||
|
)
|
||||||
|
) and
|
||||||
|
mcn.flowsTo(tests) and
|
||||||
|
mcn.calls(base, m) and
|
||||||
|
firstArg = mcn.getArgument(0)
|
||||||
|
|
|
||||||
|
// /re/.test(u) or /re/.exec(u)
|
||||||
|
enumeration = RegExp::getRegExpObjectFromNode(base) and
|
||||||
|
(m = "test" or m = "exec") and
|
||||||
|
firstArg = candidateNode
|
||||||
|
or
|
||||||
|
// u.match(/re/) or u.match("re")
|
||||||
|
base = candidateNode and
|
||||||
|
m = "match" and
|
||||||
|
enumeration = RegExp::getRegExpFromNode(firstArg)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override DataFlow::Node tests() { result = candidateNode }
|
||||||
|
|
||||||
|
override string getAMemberString() { result = enumeration.getAMember() }
|
||||||
|
|
||||||
|
override boolean getPolarity() { result = polarity }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An expression that tests if a candidate is a member of a collection class, such as a map or set.
|
||||||
|
*/
|
||||||
|
class CollectionMembershipTest extends MembershipTest::Range, DataFlow::MethodCallNode {
|
||||||
|
CollectionMembershipTest() { getMethodName() = "has" }
|
||||||
|
|
||||||
|
override DataFlow::Node tests() { result = getArgument(0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An expression that tests if a candidate is a property name of an object.
|
||||||
|
*/
|
||||||
|
class ObjectPropertyNameMembershipTest extends MembershipTest::Range, DataFlow::ValueNode {
|
||||||
|
DataFlow::ValueNode candidateNode;
|
||||||
|
DataFlow::ValueNode membersNode;
|
||||||
|
|
||||||
|
ObjectPropertyNameMembershipTest() {
|
||||||
|
exists(InExpr inExpr |
|
||||||
|
astNode = inExpr and
|
||||||
|
inExpr.getLeftOperand() = candidateNode.asExpr() and
|
||||||
|
inExpr.getRightOperand() = membersNode.asExpr()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(DataFlow::MethodCallNode hasOwn |
|
||||||
|
this = hasOwn and
|
||||||
|
hasOwn.calls(membersNode, "hasOwnProperty") and
|
||||||
|
hasOwn.getArgument(0) = candidateNode
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override DataFlow::Node tests() { result = candidateNode }
|
||||||
|
|
||||||
|
override string getAMemberString() {
|
||||||
|
exists(membersNode.getALocalSource().getAPropertyWrite(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -825,18 +825,22 @@ module TaintTracking {
|
|||||||
override predicate appliesTo(Configuration cfg) { any() }
|
override predicate appliesTo(Configuration cfg) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DEPRECATED. This class has been renamed to `InclusionSanitizer`. */
|
/** DEPRECATED. This class has been renamed to `MembershipTestSanitizer`. */
|
||||||
deprecated class StringInclusionSanitizer = InclusionSanitizer;
|
deprecated class StringInclusionSanitizer = MembershipTestSanitizer;
|
||||||
|
|
||||||
/** A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch. */
|
/** DEPRECATED. This class has been renamed to `MembershipTestSanitizer`. */
|
||||||
class InclusionSanitizer extends AdditionalSanitizerGuardNode {
|
deprecated class InclusionSanitizer = MembershipTestSanitizer;
|
||||||
InclusionTest inclusion;
|
|
||||||
|
|
||||||
InclusionSanitizer() { this = inclusion }
|
/**
|
||||||
|
* A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch.
|
||||||
|
*/
|
||||||
|
class MembershipTestSanitizer extends AdditionalSanitizerGuardNode {
|
||||||
|
MembershipTest test;
|
||||||
|
|
||||||
|
MembershipTestSanitizer() { this = test }
|
||||||
|
|
||||||
override predicate sanitizes(boolean outcome, Expr e) {
|
override predicate sanitizes(boolean outcome, Expr e) {
|
||||||
outcome = inclusion.getPolarity() and
|
test.getCandidate() = e.flow() and test.getPolarity() = outcome
|
||||||
e = inclusion.getContainedNode().asExpr()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate appliesTo(Configuration cfg) { any() }
|
override predicate appliesTo(Configuration cfg) { any() }
|
||||||
@@ -871,8 +875,12 @@ module TaintTracking {
|
|||||||
/** Gets a variable that is defined exactly once. */
|
/** Gets a variable that is defined exactly once. */
|
||||||
private Variable singleDef() { strictcount(result.getADefinition()) = 1 }
|
private Variable singleDef() { strictcount(result.getADefinition()) = 1 }
|
||||||
|
|
||||||
/** A check of the form `if(x == 'some-constant')`, which sanitizes `x` in its "then" branch. */
|
/**
|
||||||
class ConstantComparison extends AdditionalSanitizerGuardNode, DataFlow::ValueNode {
|
* A check of the form `if(x == 'some-constant')`, which sanitizes `x` in its "then" branch.
|
||||||
|
*
|
||||||
|
* DEPRECATED: use `MembershipTests::MembershipTest` instead.
|
||||||
|
*/
|
||||||
|
deprecated class ConstantComparison extends SanitizerGuardNode, DataFlow::ValueNode {
|
||||||
Expr x;
|
Expr x;
|
||||||
override EqualityTest astNode;
|
override EqualityTest astNode;
|
||||||
|
|
||||||
@@ -890,7 +898,10 @@ module TaintTracking {
|
|||||||
outcome = astNode.getPolarity() and x = e
|
outcome = astNode.getPolarity() and x = e
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate appliesTo(Configuration cfg) { any() }
|
/**
|
||||||
|
* Holds if this guard applies to the flow in `cfg`.
|
||||||
|
*/
|
||||||
|
predicate appliesTo(Configuration cfg) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,16 +4,31 @@
|
|||||||
| tst.js:35:9:35:14 | v in o | ExampleConfiguration | true | tst.js:35:9:35:9 | v |
|
| tst.js:35:9:35:14 | v in o | ExampleConfiguration | true | tst.js:35:9:35:9 | v |
|
||||||
| tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | false | tst.js:47:11:47:11 | v |
|
| tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | false | tst.js:47:11:47:11 | v |
|
||||||
| tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | true | tst.js:47:9:47:12 | o[v] |
|
| tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | true | tst.js:47:9:47:12 | o[v] |
|
||||||
|
| tst.js:47:9:47:25 | o[v] == undefined | ExampleConfiguration | true | tst.js:47:17:47:25 | undefined |
|
||||||
| tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | false | tst.js:53:25:53:25 | v |
|
| tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | false | tst.js:53:25:53:25 | v |
|
||||||
|
| tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | true | tst.js:53:9:53:17 | undefined |
|
||||||
| tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | true | tst.js:53:23:53:26 | o[v] |
|
| tst.js:53:9:53:26 | undefined === o[v] | ExampleConfiguration | true | tst.js:53:23:53:26 | o[v] |
|
||||||
| tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | false | tst.js:59:9:59:12 | o[v] |
|
| tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | false | tst.js:59:9:59:12 | o[v] |
|
||||||
|
| tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | false | tst.js:59:18:59:26 | undefined |
|
||||||
| tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | true | tst.js:59:11:59:11 | v |
|
| tst.js:59:9:59:26 | o[v] !== undefined | ExampleConfiguration | true | tst.js:59:11:59:11 | v |
|
||||||
|
| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | false | tst.js:71:9:71:20 | o.indexOf(v) |
|
||||||
| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | false | tst.js:71:19:71:19 | v |
|
| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | false | tst.js:71:19:71:19 | v |
|
||||||
|
| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | false | tst.js:71:25:71:26 | -1 |
|
||||||
| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | true | tst.js:71:9:71:20 | o.indexOf(v) |
|
| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | true | tst.js:71:9:71:20 | o.indexOf(v) |
|
||||||
|
| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | true | tst.js:71:19:71:19 | v |
|
||||||
|
| tst.js:71:9:71:26 | o.indexOf(v) == -1 | ExampleConfiguration | true | tst.js:71:25:71:26 | -1 |
|
||||||
|
| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | false | tst.js:77:9:77:10 | -1 |
|
||||||
|
| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | false | tst.js:77:16:77:27 | o.indexOf(v) |
|
||||||
| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | false | tst.js:77:26:77:26 | v |
|
| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | false | tst.js:77:26:77:26 | v |
|
||||||
|
| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | true | tst.js:77:9:77:10 | -1 |
|
||||||
| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | true | tst.js:77:16:77:27 | o.indexOf(v) |
|
| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | true | tst.js:77:16:77:27 | o.indexOf(v) |
|
||||||
|
| tst.js:77:9:77:27 | -1 === o.indexOf(v) | ExampleConfiguration | true | tst.js:77:26:77:26 | v |
|
||||||
| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | false | tst.js:83:9:83:20 | o.indexOf(v) |
|
| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | false | tst.js:83:9:83:20 | o.indexOf(v) |
|
||||||
|
| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | false | tst.js:83:19:83:19 | v |
|
||||||
|
| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | false | tst.js:83:26:83:27 | -1 |
|
||||||
|
| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | true | tst.js:83:9:83:20 | o.indexOf(v) |
|
||||||
| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | true | tst.js:83:19:83:19 | v |
|
| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | true | tst.js:83:19:83:19 | v |
|
||||||
|
| tst.js:83:9:83:27 | o.indexOf(v) !== -1 | ExampleConfiguration | true | tst.js:83:26:83:27 | -1 |
|
||||||
| tst.js:95:9:95:21 | o.contains(v) | ExampleConfiguration | true | tst.js:95:20:95:20 | v |
|
| tst.js:95:9:95:21 | o.contains(v) | ExampleConfiguration | true | tst.js:95:20:95:20 | v |
|
||||||
| tst.js:107:9:107:16 | o.has(v) | ExampleConfiguration | true | tst.js:107:15:107:15 | v |
|
| tst.js:107:9:107:16 | o.has(v) | ExampleConfiguration | true | tst.js:107:15:107:15 | v |
|
||||||
| tst.js:119:9:119:21 | o.includes(v) | ExampleConfiguration | true | tst.js:119:20:119:20 | v |
|
| tst.js:119:9:119:21 | o.includes(v) | ExampleConfiguration | true | tst.js:119:20:119:20 | v |
|
||||||
@@ -65,4 +80,6 @@
|
|||||||
| tst.js:356:32:356:48 | x10 !== undefined | ExampleConfiguration | false | tst.js:356:32:356:34 | x10 |
|
| tst.js:356:32:356:48 | x10 !== undefined | ExampleConfiguration | false | tst.js:356:32:356:34 | x10 |
|
||||||
| tst.js:356:32:356:48 | x10 !== undefined | ExampleConfiguration | false | tst.js:356:40:356:48 | undefined |
|
| tst.js:356:32:356:48 | x10 !== undefined | ExampleConfiguration | false | tst.js:356:40:356:48 | undefined |
|
||||||
| tst.js:370:9:370:29 | o.p == ... listed" | ExampleConfiguration | true | tst.js:370:9:370:11 | o.p |
|
| tst.js:370:9:370:29 | o.p == ... listed" | ExampleConfiguration | true | tst.js:370:9:370:11 | o.p |
|
||||||
|
| tst.js:370:9:370:29 | o.p == ... listed" | ExampleConfiguration | true | tst.js:370:16:370:29 | "white-listed" |
|
||||||
| tst.js:377:11:377:32 | o[p] == ... listed" | ExampleConfiguration | true | tst.js:377:11:377:14 | o[p] |
|
| tst.js:377:11:377:32 | o[p] == ... listed" | ExampleConfiguration | true | tst.js:377:11:377:14 | o[p] |
|
||||||
|
| tst.js:377:11:377:32 | o[p] == ... listed" | ExampleConfiguration | true | tst.js:377:19:377:32 | "white-listed" |
|
||||||
|
|||||||
@@ -95,6 +95,9 @@ typeInferenceMismatch
|
|||||||
| sanitizer-guards.js:68:11:68:18 | source() | sanitizer-guards.js:75:8:75:8 | x |
|
| sanitizer-guards.js:68:11:68:18 | source() | sanitizer-guards.js:75:8:75:8 | x |
|
||||||
| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:81:8:81:8 | x |
|
| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:81:8:81:8 | x |
|
||||||
| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:84:10:84:10 | x |
|
| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:84:10:84:10 | x |
|
||||||
|
| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:93:8:93:8 | x |
|
||||||
|
| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:98:7:98:7 | x |
|
||||||
|
| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:104:7:104:7 | x |
|
||||||
| spread.js:2:15:2:22 | source() | spread.js:4:8:4:19 | { ...taint } |
|
| spread.js:2:15:2:22 | source() | spread.js:4:8:4:19 | { ...taint } |
|
||||||
| spread.js:2:15:2:22 | source() | spread.js:5:8:5:43 | { f: 'h ... orld' } |
|
| spread.js:2:15:2:22 | source() | spread.js:5:8:5:43 | { f: 'h ... orld' } |
|
||||||
| spread.js:2:15:2:22 | source() | spread.js:7:8:7:19 | [ ...taint ] |
|
| spread.js:2:15:2:22 | source() | spread.js:7:8:7:19 | [ ...taint ] |
|
||||||
|
|||||||
@@ -71,6 +71,11 @@
|
|||||||
| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:81:8:81:8 | x |
|
| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:81:8:81:8 | x |
|
||||||
| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:84:10:84:10 | x |
|
| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:84:10:84:10 | x |
|
||||||
| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:86:7:86:7 | x |
|
| sanitizer-guards.js:79:11:79:18 | source() | sanitizer-guards.js:86:7:86:7 | x |
|
||||||
|
| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:93:8:93:8 | x |
|
||||||
|
| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:96:10:96:10 | x |
|
||||||
|
| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:98:7:98:7 | x |
|
||||||
|
| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:102:10:102:10 | x |
|
||||||
|
| sanitizer-guards.js:91:11:91:18 | source() | sanitizer-guards.js:104:7:104:7 | x |
|
||||||
| thisAssignments.js:4:17:4:24 | source() | thisAssignments.js:5:10:5:18 | obj.field |
|
| thisAssignments.js:4:17:4:24 | source() | thisAssignments.js:5:10:5:18 | obj.field |
|
||||||
| thisAssignments.js:7:19:7:26 | source() | thisAssignments.js:8:10:8:20 | this.field2 |
|
| thisAssignments.js:7:19:7:26 | source() | thisAssignments.js:8:10:8:20 | this.field2 |
|
||||||
| tst.js:2:13:2:20 | source() | tst.js:4:10:4:10 | x |
|
| tst.js:2:13:2:20 | source() | tst.js:4:10:4:10 | x |
|
||||||
|
|||||||
@@ -86,3 +86,21 @@ function falsy() {
|
|||||||
sink(x); // NOT OK
|
sink(x); // NOT OK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function comparisons() {
|
||||||
|
let x = source();
|
||||||
|
|
||||||
|
sink(x); // NOT OK
|
||||||
|
|
||||||
|
if (x === "foo") {
|
||||||
|
sink(x); // OK
|
||||||
|
} else {
|
||||||
|
sink(x); // NOT OK
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x === something()) {
|
||||||
|
sink(x); // OK
|
||||||
|
} else {
|
||||||
|
sink(x); // NOT OK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,3 +4,9 @@
|
|||||||
| IncompleteUrlSchemeCheck.js:30:9:30:43 | badProt ... scheme) | This check does not consider vbscript:. |
|
| IncompleteUrlSchemeCheck.js:30:9:30:43 | badProt ... scheme) | This check does not consider vbscript:. |
|
||||||
| IncompleteUrlSchemeCheck.js:37:9:37:31 | scheme ... script" | This check does not consider data: and vbscript:. |
|
| IncompleteUrlSchemeCheck.js:37:9:37:31 | scheme ... script" | This check does not consider data: and vbscript:. |
|
||||||
| IncompleteUrlSchemeCheck.js:51:9:51:31 | scheme ... script" | This check does not consider data: and vbscript:. |
|
| IncompleteUrlSchemeCheck.js:51:9:51:31 | scheme ... script" | This check does not consider data: and vbscript:. |
|
||||||
|
| IncompleteUrlSchemeCheck.js:58:6:58:56 | "javasc ... !== -1 | This check does not consider vbscript:. |
|
||||||
|
| IncompleteUrlSchemeCheck.js:65:6:65:28 | "javasc ... scheme | This check does not consider vbscript:. |
|
||||||
|
| IncompleteUrlSchemeCheck.js:72:6:72:48 | /^(java ... == null | This check does not consider vbscript:. |
|
||||||
|
| IncompleteUrlSchemeCheck.js:79:6:79:48 | /^(java ... == null | This check does not consider vbscript:. |
|
||||||
|
| IncompleteUrlSchemeCheck.js:87:7:87:40 | /^(java ... scheme) | This check does not consider vbscript:. |
|
||||||
|
| IncompleteUrlSchemeCheck.js:104:6:104:39 | /^(java ... scheme) | This check does not consider vbscript:. |
|
||||||
|
|||||||
@@ -52,3 +52,56 @@ function test7(url) {
|
|||||||
return "about:blank";
|
return "about:blank";
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test8(url) {
|
||||||
|
let scheme = goog.uri.utils.getScheme(url);
|
||||||
|
if ("javascript|data".split("|").indexOf(scheme) !== -1) // NOT OK
|
||||||
|
return "about:blank";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function test9(url) {
|
||||||
|
let scheme = goog.uri.utils.getScheme(url);
|
||||||
|
if ("javascript" === scheme || "data" === scheme) // NOT OK
|
||||||
|
return "about:blank";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function test10(url) {
|
||||||
|
let scheme = goog.uri.utils.getScheme(url);
|
||||||
|
if (/^(javascript|data)$/.exec(scheme) !== null) // NOT OK
|
||||||
|
return "about:blank";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function test11(url) {
|
||||||
|
let scheme = goog.uri.utils.getScheme(url);
|
||||||
|
if (/^(javascript|data)$/.exec(scheme) === null) // NOT OK
|
||||||
|
return url;
|
||||||
|
return "about:blank";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function test12(url) {
|
||||||
|
let scheme = goog.uri.utils.getScheme(url);
|
||||||
|
if (!/^(javascript|data)$/.exec(scheme)) // NOT OK
|
||||||
|
return url;
|
||||||
|
return "about:blank";
|
||||||
|
}
|
||||||
|
|
||||||
|
function test13(url) {
|
||||||
|
let scheme = goog.uri.utils.getScheme(url);
|
||||||
|
switch (scheme) {
|
||||||
|
case "javascript": // NOT OK - but not detected due to lack of `switch` support
|
||||||
|
case "data":
|
||||||
|
return "about:blank";
|
||||||
|
default:
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function test14(url) {
|
||||||
|
let scheme = goog.uri.utils.getScheme(url);
|
||||||
|
if (/^(javascript|data)$/.exec(scheme)) // NOT OK
|
||||||
|
return "about:blank";
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user