mirror of
https://github.com/github/codeql.git
synced 2026-05-01 11:45:14 +02:00
Merge branch 'main' into js/madman-prep
This commit is contained in:
@@ -144,9 +144,9 @@ private module AccessPaths {
|
||||
not param = base.getReceiver()
|
||||
|
|
||||
result = param and
|
||||
name = param.getAnImmediateUse().asExpr().(Parameter).getName()
|
||||
name = param.asSource().asExpr().(Parameter).getName()
|
||||
or
|
||||
param.getAnImmediateUse().asExpr() instanceof DestructuringPattern and
|
||||
param.asSource().asExpr() instanceof DestructuringPattern and
|
||||
result = param.getMember(name)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/javascript-experimental-atm-lib
|
||||
version: 0.2.1
|
||||
version: 0.3.1
|
||||
extractor: javascript
|
||||
library: true
|
||||
groups:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/javascript-experimental-atm-model
|
||||
version: 0.1.1
|
||||
version: 0.2.1
|
||||
groups:
|
||||
- javascript
|
||||
- experimental
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
dependencies:
|
||||
codeql/javascript-experimental-atm-model:
|
||||
version: 0.1.0
|
||||
version: 0.2.0
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
*
|
||||
* Count the number of sinks and alerts for a particular dataflow config.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import evaluation.EndToEndEvaluation
|
||||
|
||||
query predicate countAlertsAndSinks(int numAlerts, int numSinks) {
|
||||
numAlerts =
|
||||
count(DataFlow::Configuration cfg, DataFlow::Node source, DataFlow::Node sink |
|
||||
cfg.hasFlow(source, sink) and not isFlowExcluded(source, sink)
|
||||
) and
|
||||
numSinks =
|
||||
count(DataFlow::Node sink |
|
||||
exists(DataFlow::Configuration cfg | cfg.isSink(sink) or cfg.isSink(sink, _))
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
*
|
||||
* Count the number of sinks and alerts for the `CodeInjection` security query.
|
||||
*/
|
||||
|
||||
import semmle.javascript.security.dataflow.CodeInjectionQuery
|
||||
import CountAlertsAndSinks
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
*
|
||||
* Count the number of sinks and alerts for the `NosqlInection` security query.
|
||||
*/
|
||||
|
||||
import semmle.javascript.security.dataflow.NosqlInjectionQuery
|
||||
import CountAlertsAndSinks
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
*
|
||||
* Count the number of sinks and alerts for the `SqlInection` security query.
|
||||
*/
|
||||
|
||||
import semmle.javascript.security.dataflow.SqlInjectionQuery
|
||||
import CountAlertsAndSinks
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
*
|
||||
* Count the number of sinks and alerts for the `TaintedPath` security query.
|
||||
*/
|
||||
|
||||
import semmle.javascript.security.dataflow.TaintedPathQuery
|
||||
import CountAlertsAndSinks
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
*
|
||||
* Count the number of sinks and alerts for the `DomBasedXss` security query.
|
||||
*/
|
||||
|
||||
import semmle.javascript.security.dataflow.DomBasedXssQuery
|
||||
import CountAlertsAndSinks
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* For internal use only.
|
||||
*
|
||||
*
|
||||
* Count the number of sinks and alerts for the `XssThroughDom` security query.
|
||||
*/
|
||||
|
||||
import semmle.javascript.security.dataflow.XssThroughDomQuery
|
||||
import CountAlertsAndSinks
|
||||
@@ -6,4 +6,4 @@ groups:
|
||||
- experimental
|
||||
dependencies:
|
||||
codeql/javascript-experimental-atm-lib: "*"
|
||||
codeql/javascript-experimental-atm-model: "0.1.0"
|
||||
codeql/javascript-experimental-atm-model: "0.2.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
dependencies:
|
||||
codeql/javascript-experimental-atm-model:
|
||||
version: 0.1.0
|
||||
version: 0.2.0
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: codeql/javascript-experimental-atm-queries
|
||||
language: javascript
|
||||
version: 0.2.1
|
||||
version: 0.3.1
|
||||
suites: codeql-suites
|
||||
defaultSuiteFile: codeql-suites/javascript-atm-code-scanning.qls
|
||||
groups:
|
||||
@@ -8,4 +8,4 @@ groups:
|
||||
- experimental
|
||||
dependencies:
|
||||
codeql/javascript-experimental-atm-lib: "*"
|
||||
codeql/javascript-experimental-atm-model: "0.1.0"
|
||||
codeql/javascript-experimental-atm-model: "0.2.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
dependencies:
|
||||
codeql/javascript-experimental-atm-model:
|
||||
version: 0.1.0
|
||||
version: 0.2.0
|
||||
compiled: false
|
||||
lockVersion: 1.0.0
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* All new ECMAScript 2022 features are now supported.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* Added support for TypeScript 4.7.
|
||||
@@ -2,11 +2,7 @@
|
||||
* Provides an implementation of _API graphs_, which are an abstract representation of the API
|
||||
* surface used and/or defined by a code base.
|
||||
*
|
||||
* The nodes of the API graph represent definitions and uses of API components. The edges are
|
||||
* directed and labeled; they specify how the components represented by nodes relate to each other.
|
||||
* For example, if one of the nodes represents a definition of an API function, then there
|
||||
* will be nodes corresponding to the function's parameters, which are connected to the function
|
||||
* node by edges labeled `parameter <i>`.
|
||||
* See `API::Node` for more in-depth documentation.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
@@ -14,50 +10,159 @@ private import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps
|
||||
private import internal.CachedStages
|
||||
|
||||
/**
|
||||
* Provides classes and predicates for working with APIs defined or used in a database.
|
||||
* Provides classes and predicates for working with the API boundary between the current
|
||||
* codebase and external libraries.
|
||||
*
|
||||
* See `API::Node` for more in-depth documentation.
|
||||
*/
|
||||
module API {
|
||||
/**
|
||||
* An abstract representation of a definition or use of an API component such as a function
|
||||
* exported by an npm package, a parameter of such a function, or its result.
|
||||
* A node in the API graph, representing a value that has crossed the boundary between this
|
||||
* codebase and an external library (or in general, any external codebase).
|
||||
*
|
||||
* ### Basic usage
|
||||
*
|
||||
* API graphs are typically used to identify "API calls", that is, calls to an external function
|
||||
* whose implementation is not necessarily part of the current codebase.
|
||||
*
|
||||
* The most basic use of API graphs is typically as follows:
|
||||
* 1. Start with `API::moduleImport` for the relevant library.
|
||||
* 2. Follow up with a chain of accessors such as `getMember` describing how to get to the relevant API function.
|
||||
* 3. Map the resulting API graph nodes to data-flow nodes, using `asSource` or `asSink`.
|
||||
*
|
||||
* For example, a simplified way to get arguments to `underscore.extend` would be
|
||||
* ```ql
|
||||
* API::moduleImport("underscore").getMember("extend").getParameter(0).asSink()
|
||||
* ```
|
||||
*
|
||||
* The most commonly used accessors are `getMember`, `getParameter`, and `getReturn`.
|
||||
*
|
||||
* ### API graph nodes
|
||||
*
|
||||
* There are two kinds of nodes in the API graphs, distinguished by who is "holding" the value:
|
||||
* - **Use-nodes** represent values held by the current codebase, which came from an external library.
|
||||
* (The current codebase is "using" a value that came from the library).
|
||||
* - **Def-nodes** represent values held by the external library, which came from this codebase.
|
||||
* (The current codebase "defines" the value seen by the library).
|
||||
*
|
||||
* API graph nodes are associated with data-flow nodes in the current codebase.
|
||||
* (Since external libraries are not part of the database, there is no way to associate with concrete
|
||||
* data-flow nodes from the external library).
|
||||
* - **Use-nodes** are associated with data-flow nodes where a value enters the current codebase,
|
||||
* such as the return value of a call to an external function.
|
||||
* - **Def-nodes** are associated with data-flow nodes where a value leaves the current codebase,
|
||||
* such as an argument passed in a call to an external function.
|
||||
*
|
||||
*
|
||||
* ### Access paths and edge labels
|
||||
*
|
||||
* Nodes in the API graph are associated with a set of access paths, describing a series of operations
|
||||
* that may be performed to obtain that value.
|
||||
*
|
||||
* For example, the access path `API::moduleImport("lodash").getMember("extend")` represents the action of
|
||||
* importing `lodash` and then accessing the member `extend` on the resulting object.
|
||||
* It would be associated with an expression such as `require("lodash").extend`.
|
||||
*
|
||||
* Each edge in the graph is labelled by such an "operation". For an edge `A->B`, the type of the `A` node
|
||||
* determines who is performing the operation, and the type of the `B` node determines who ends up holding
|
||||
* the result:
|
||||
* - An edge starting from a use-node describes what the current codebase is doing to a value that
|
||||
* came from a library.
|
||||
* - An edge starting from a def-node describes what the external library might do to a value that
|
||||
* came from the current codebase.
|
||||
* - An edge ending in a use-node means the result ends up in the current codebase (at its associated data-flow node).
|
||||
* - An edge ending in a def-node means the result ends up in external code (its associated data-flow node is
|
||||
* the place where it was "last seen" in the current codebase before flowing out)
|
||||
*
|
||||
* Because the implementation of the external library is not visible, it is not known exactly what operations
|
||||
* it will perform on values that flow there. Instead, the edges starting from a def-node are operations that would
|
||||
* lead to an observable effect within the current codebase; without knowing for certain if the library will actually perform
|
||||
* those operations. (When constructing these edges, we assume the library is somewhat well-behaved).
|
||||
*
|
||||
* For example, given this snippet:
|
||||
* ```js
|
||||
* require('foo')(x => { doSomething(x) })
|
||||
* ```
|
||||
* A callback is passed to the external function `foo`. We can't know if `foo` will actually invoke this callback.
|
||||
* But _if_ the library should decide to invoke the callback, then a value will flow into the current codebase via the `x` parameter.
|
||||
* For that reason, an edge is generated representing the argument-passing operation that might be performed by `foo`.
|
||||
* This edge is going from the def-node associated with the callback to the use-node associated with the parameter `x`.
|
||||
*
|
||||
* ### Thinking in operations versus code patterns
|
||||
*
|
||||
* Treating edges as "operations" helps avoid a pitfall in which library models become overly specific to certain code patterns.
|
||||
* Consider the following two equivalent calls to `foo`:
|
||||
* ```js
|
||||
* const foo = require('foo');
|
||||
*
|
||||
* foo({
|
||||
* myMethod(x) {...}
|
||||
* });
|
||||
*
|
||||
* foo({
|
||||
* get myMethod() {
|
||||
* return function(x) {...}
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
* If `foo` calls `myMethod` on its first parameter, either of the `myMethod` implementations will be invoked.
|
||||
* And indeed, the access path `API::moduleImport("foo").getParameter(0).getMember("myMethod").getParameter(0)` correctly
|
||||
* identifies both `x` parameters.
|
||||
*
|
||||
* Observe how `getMember("myMethod")` behaves when the member is defined via a getter. When thinking in code patterns,
|
||||
* it might seem obvious that `getMember` should have obtained a reference to the getter method itself.
|
||||
* But when seeing it as an access to `myMethod` performed by the library, we can deduce that the relevant expression
|
||||
* on the client side is actually the return-value of the getter.
|
||||
*
|
||||
* Although one may think of API graphs as a tool to find certain program elements in the codebase,
|
||||
* it can lead to some situations where intuition does not match what works best in practice.
|
||||
*/
|
||||
class Node extends Impl::TApiNode {
|
||||
/**
|
||||
* Gets a data-flow node corresponding to a use of the API component represented by this node.
|
||||
* Get a data-flow node where this value may flow after entering the current codebase.
|
||||
*
|
||||
* For example, `require('fs').readFileSync` is a use of the function `readFileSync` from the
|
||||
* `fs` module, and `require('fs').readFileSync(file)` is a use of the return of that function.
|
||||
*
|
||||
* This includes indirect uses found via data flow, meaning that in
|
||||
* `f(obj.foo); function f(x) {};` both `obj.foo` and `x` are uses of the `foo` member from `obj`.
|
||||
*
|
||||
* As another example, in the assignment `exports.plusOne = (x) => x+1` the two references to
|
||||
* `x` are uses of the first parameter of `plusOne`.
|
||||
* This is similar to `asSource()` but additionally includes nodes that are transitively reachable by data flow.
|
||||
* See `asSource()` for examples.
|
||||
*/
|
||||
pragma[inline]
|
||||
DataFlow::Node getAUse() {
|
||||
exists(DataFlow::SourceNode src | Impl::use(this, src) |
|
||||
Impl::trackUseNode(src).flowsTo(result)
|
||||
)
|
||||
DataFlow::Node getAValueReachableFromSource() {
|
||||
Impl::trackUseNode(this.asSource()).flowsTo(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an immediate use of the API component represented by this node.
|
||||
* Get a data-flow node where this value enters the current codebase.
|
||||
*
|
||||
* For example, `require('fs').readFileSync` is a an immediate use of the `readFileSync` member
|
||||
* from the `fs` module.
|
||||
* For example:
|
||||
* ```js
|
||||
* // API::moduleImport("fs").asSource()
|
||||
* require('fs');
|
||||
*
|
||||
* Unlike `getAUse()`, this predicate only gets the immediate references, not the indirect uses
|
||||
* found via data flow. This means that in `const x = fs.readFile` only `fs.readFile` is a reference
|
||||
* to the `readFile` member of `fs`, neither `x` nor any node that `x` flows to is a reference to
|
||||
* this API component.
|
||||
* // API::moduleImport("fs").getMember("readFile").asSource()
|
||||
* require('fs').readFile;
|
||||
*
|
||||
* // API::moduleImport("fs").getMember("readFile").getReturn().asSource()
|
||||
* require('fs').readFile();
|
||||
*
|
||||
* require('fs').readFile(
|
||||
* filename,
|
||||
* // 'y' matched by API::moduleImport("fs").getMember("readFile").getParameter(1).getParameter(0).asSource()
|
||||
* y => {
|
||||
* ...
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
DataFlow::SourceNode getAnImmediateUse() { Impl::use(this, result) }
|
||||
DataFlow::SourceNode asSource() { Impl::use(this, result) }
|
||||
|
||||
/** DEPRECATED. This predicate has been renamed to `asSource`. */
|
||||
deprecated DataFlow::SourceNode getAnImmediateUse() { result = this.asSource() }
|
||||
|
||||
/** DEPRECATED. This predicate has been renamed to `getAValueReachableFromSource`. */
|
||||
deprecated DataFlow::Node getAUse() { result = this.getAValueReachableFromSource() }
|
||||
|
||||
/**
|
||||
* Gets a call to the function represented by this API component.
|
||||
*/
|
||||
CallNode getACall() { result = this.getReturn().getAnImmediateUse() }
|
||||
CallNode getACall() { result = this.getReturn().asSource() }
|
||||
|
||||
/**
|
||||
* Gets a call to the function represented by this API component,
|
||||
@@ -72,7 +177,7 @@ module API {
|
||||
/**
|
||||
* Gets a `new` call to the function represented by this API component.
|
||||
*/
|
||||
NewNode getAnInstantiation() { result = this.getInstance().getAnImmediateUse() }
|
||||
NewNode getAnInstantiation() { result = this.getInstance().asSource() }
|
||||
|
||||
/**
|
||||
* Gets an invocation (with our without `new`) to the function represented by this API component.
|
||||
@@ -80,26 +185,38 @@ module API {
|
||||
InvokeNode getAnInvocation() { result = this.getACall() or result = this.getAnInstantiation() }
|
||||
|
||||
/**
|
||||
* Gets a data-flow node corresponding to the right-hand side of a definition of the API
|
||||
* component represented by this node.
|
||||
* Get a data-flow node where this value leaves the current codebase and flows into an
|
||||
* external library (or in general, any external codebase).
|
||||
*
|
||||
* For example, in the assignment `exports.plusOne = (x) => x+1`, the function expression
|
||||
* `(x) => x+1` is the right-hand side of the definition of the member `plusOne` of
|
||||
* the enclosing module, and the expression `x+1` is the right-had side of the definition of
|
||||
* its result.
|
||||
* Concretely, this is either an argument passed to a call to external code,
|
||||
* or the right-hand side of a property write on an object flowing into such a call.
|
||||
*
|
||||
* Note that for parameters, it is the arguments flowing into that parameter that count as
|
||||
* right-hand sides of the definition, not the declaration of the parameter itself.
|
||||
* Consequently, in `require('fs').readFileSync(file)`, `file` is the right-hand
|
||||
* side of a definition of the first parameter of `readFileSync` from the `fs` module.
|
||||
* For example:
|
||||
* ```js
|
||||
* // 'x' is matched by API::moduleImport("foo").getParameter(0).asSink()
|
||||
* require('foo')(x);
|
||||
*
|
||||
* // 'x' is matched by API::moduleImport("foo").getParameter(0).getMember("prop").asSink()
|
||||
* require('foo')({
|
||||
* prop: x
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
DataFlow::Node getARhs() { Impl::rhs(this, result) }
|
||||
DataFlow::Node asSink() { Impl::rhs(this, result) }
|
||||
|
||||
/**
|
||||
* Gets a data-flow node that may interprocedurally flow to the right-hand side of a definition
|
||||
* of the API component represented by this node.
|
||||
* Get a data-flow node that transitively flows to an external library (or in general, any external codebase).
|
||||
*
|
||||
* This is similar to `asSink()` but additionally includes nodes that transitively reach a sink by data flow.
|
||||
* See `asSink()` for examples.
|
||||
*/
|
||||
DataFlow::Node getAValueReachingRhs() { result = Impl::trackDefNode(this.getARhs()) }
|
||||
DataFlow::Node getAValueReachingSink() { result = Impl::trackDefNode(this.asSink()) }
|
||||
|
||||
/** DEPRECATED. This predicate has been renamed to `asSink`. */
|
||||
deprecated DataFlow::Node getARhs() { result = this.asSink() }
|
||||
|
||||
/** DEPRECATED. This predicate has been renamed to `getAValueReachingSink`. */
|
||||
deprecated DataFlow::Node getAValueReachingRhs() { result = this.getAValueReachingSink() }
|
||||
|
||||
/**
|
||||
* Gets a node representing member `m` of this API component.
|
||||
@@ -334,7 +451,7 @@ module API {
|
||||
* In other words, the value of a use of `that` may flow into the right-hand side of a
|
||||
* definition of this node.
|
||||
*/
|
||||
predicate refersTo(Node that) { this.getARhs() = that.getAUse() }
|
||||
predicate refersTo(Node that) { this.asSink() = that.getAValueReachableFromSource() }
|
||||
|
||||
/**
|
||||
* Gets the data-flow node that gives rise to this node, if any.
|
||||
@@ -445,11 +562,17 @@ module API {
|
||||
bindingset[this]
|
||||
EntryPoint() { any() }
|
||||
|
||||
/** Gets a data-flow node that uses this entry point. */
|
||||
abstract DataFlow::SourceNode getAUse();
|
||||
/** DEPRECATED. This predicate has been renamed to `getASource`. */
|
||||
deprecated DataFlow::SourceNode getAUse() { none() }
|
||||
|
||||
/** Gets a data-flow node that defines this entry point. */
|
||||
abstract DataFlow::Node getARhs();
|
||||
/** DEPRECATED. This predicate has been renamed to `getASink`. */
|
||||
deprecated DataFlow::SourceNode getARhs() { none() }
|
||||
|
||||
/** Gets a data-flow node where a value enters the current codebase through this entry-point. */
|
||||
DataFlow::SourceNode getASource() { none() }
|
||||
|
||||
/** Gets a data-flow node where a value leaves the current codebase through this entry-point. */
|
||||
DataFlow::Node getASink() { none() }
|
||||
|
||||
/** Gets an API-node for this entry point. */
|
||||
API::Node getANode() { result = root().getASuccessor(Label::entryPoint(this)) }
|
||||
@@ -567,7 +690,7 @@ module API {
|
||||
base = MkRoot() and
|
||||
exists(EntryPoint e |
|
||||
lbl = Label::entryPoint(e) and
|
||||
rhs = e.getARhs()
|
||||
rhs = e.getASink()
|
||||
)
|
||||
or
|
||||
exists(string m, string prop |
|
||||
@@ -744,7 +867,7 @@ module API {
|
||||
base = MkRoot() and
|
||||
exists(EntryPoint e |
|
||||
lbl = Label::entryPoint(e) and
|
||||
ref = e.getAUse()
|
||||
ref = e.getASource()
|
||||
)
|
||||
or
|
||||
// property reads
|
||||
@@ -1178,8 +1301,8 @@ module API {
|
||||
API::Node callee;
|
||||
|
||||
InvokeNode() {
|
||||
this = callee.getReturn().getAnImmediateUse() or
|
||||
this = callee.getInstance().getAnImmediateUse() or
|
||||
this = callee.getReturn().asSource() or
|
||||
this = callee.getInstance().asSource() or
|
||||
this = Impl::getAPromisifiedInvocation(callee, _, _)
|
||||
}
|
||||
|
||||
@@ -1194,7 +1317,7 @@ module API {
|
||||
* Gets an API node where a RHS of the node is the `i`th argument to this call.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private Node getAParameterCandidate(int i) { result.getARhs() = this.getArgument(i) }
|
||||
private Node getAParameterCandidate(int i) { result.asSink() = this.getArgument(i) }
|
||||
|
||||
/** Gets the API node for a parameter of this invocation. */
|
||||
Node getAParameter() { result = this.getParameter(_) }
|
||||
@@ -1205,13 +1328,13 @@ module API {
|
||||
/** Gets the API node for the return value of this call. */
|
||||
Node getReturn() {
|
||||
result = callee.getReturn() and
|
||||
result.getAnImmediateUse() = this
|
||||
result.asSource() = this
|
||||
}
|
||||
|
||||
/** Gets the API node for the object constructed by this invocation. */
|
||||
Node getInstance() {
|
||||
result = callee.getInstance() and
|
||||
result.getAnImmediateUse() = this
|
||||
result.asSource() = this
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ module ArrayTaintTracking {
|
||||
succ.(DataFlow::SourceNode).getAMethodCall("splice") = call
|
||||
or
|
||||
// `e = array.pop()`, `e = array.shift()`, or similar: if `array` is tainted, then so is `e`.
|
||||
call.(DataFlow::MethodCallNode).calls(pred, ["pop", "shift", "slice", "splice"]) and
|
||||
call.(DataFlow::MethodCallNode).calls(pred, ["pop", "shift", "slice", "splice", "at"]) and
|
||||
succ = call
|
||||
or
|
||||
// `e = Array.from(x)`: if `x` is tainted, then so is `e`.
|
||||
@@ -199,13 +199,13 @@ private module ArrayDataFlow {
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for retrieving an element from an array using `.pop()` or `.shift()`.
|
||||
* A step for retrieving an element from an array using `.pop()`, `.shift()`, or `.at()`.
|
||||
* E.g. `array.pop()`.
|
||||
*/
|
||||
private class ArrayPopStep extends DataFlow::SharedFlowStep {
|
||||
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
|
||||
exists(DataFlow::MethodCallNode call |
|
||||
call.getMethodName() = ["pop", "shift"] and
|
||||
call.getMethodName() = ["pop", "shift", "at"] and
|
||||
prop = arrayElement() and
|
||||
obj = call.getReceiver() and
|
||||
element = call
|
||||
|
||||
@@ -29,7 +29,7 @@ private class PlainJsonParserCall extends JsonParserCall {
|
||||
callee =
|
||||
DataFlow::moduleMember(["json3", "json5", "flatted", "teleport-javascript", "json-cycle"],
|
||||
"parse") or
|
||||
callee = API::moduleImport("replicator").getInstance().getMember("decode").getAnImmediateUse() or
|
||||
callee = API::moduleImport("replicator").getInstance().getMember("decode").asSource() or
|
||||
callee = DataFlow::moduleImport("parse-json") or
|
||||
callee = DataFlow::moduleImport("json-parse-better-errors") or
|
||||
callee = DataFlow::moduleImport("json-safe-parse") or
|
||||
|
||||
@@ -134,7 +134,7 @@ module JsonSchema {
|
||||
.ref()
|
||||
.getMember(["addSchema", "validate", "compile", "compileAsync"])
|
||||
.getParameter(0)
|
||||
.getARhs()
|
||||
.asSink()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,7 +184,7 @@ module JsonSchema {
|
||||
override boolean getPolarity() { none() }
|
||||
|
||||
override DataFlow::Node getAValidationResultAccess(boolean polarity) {
|
||||
result = this.getReturn().getMember("error").getAnImmediateUse() and
|
||||
result = this.getReturn().getMember("error").asSource() and
|
||||
polarity = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class JsonStringifyCall extends DataFlow::CallNode {
|
||||
callee =
|
||||
DataFlow::moduleMember(["json3", "json5", "flatted", "teleport-javascript", "json-cycle"],
|
||||
"stringify") or
|
||||
callee = API::moduleImport("replicator").getInstance().getMember("encode").getAnImmediateUse() or
|
||||
callee = API::moduleImport("replicator").getInstance().getMember("encode").asSource() or
|
||||
callee =
|
||||
DataFlow::moduleImport([
|
||||
"json-stringify-safe", "json-stable-stringify", "stringify-object",
|
||||
|
||||
@@ -229,10 +229,10 @@ module MembershipCandidate {
|
||||
membersNode = inExpr.getRightOperand()
|
||||
)
|
||||
or
|
||||
exists(MethodCallExpr hasOwn |
|
||||
this = hasOwn.getArgument(0).flow() and
|
||||
test = hasOwn and
|
||||
hasOwn.calls(membersNode, "hasOwnProperty")
|
||||
exists(HasOwnPropertyCall hasOwn |
|
||||
this = hasOwn.getProperty() and
|
||||
test = hasOwn.asExpr() and
|
||||
membersNode = hasOwn.getObject().asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -192,3 +192,35 @@ class StringSplitCall extends DataFlow::MethodCallNode {
|
||||
bindingset[i]
|
||||
DataFlow::Node getASubstringRead(int i) { result = this.getAPropertyRead(i.toString()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `Object.prototype.hasOwnProperty`, `Object.hasOwn`, or a library that implements
|
||||
* the same functionality.
|
||||
*/
|
||||
class HasOwnPropertyCall extends DataFlow::Node instanceof DataFlow::CallNode {
|
||||
DataFlow::Node object;
|
||||
DataFlow::Node property;
|
||||
|
||||
HasOwnPropertyCall() {
|
||||
// Make sure we handle reflective calls since libraries love to do that.
|
||||
super.getCalleeNode().getALocalSource().(DataFlow::PropRead).getPropertyName() =
|
||||
"hasOwnProperty" and
|
||||
object = super.getReceiver() and
|
||||
property = super.getArgument(0)
|
||||
or
|
||||
this =
|
||||
[
|
||||
DataFlow::globalVarRef("Object").getAMemberCall("hasOwn"), //
|
||||
DataFlow::moduleImport("has").getACall(), //
|
||||
LodashUnderscore::member("has").getACall()
|
||||
] and
|
||||
object = super.getArgument(0) and
|
||||
property = super.getArgument(1)
|
||||
}
|
||||
|
||||
/** Gets the object whose property is being checked. */
|
||||
DataFlow::Node getObject() { result = object }
|
||||
|
||||
/** Gets the property being checked. */
|
||||
DataFlow::Node getProperty() { result = property }
|
||||
}
|
||||
|
||||
@@ -1282,6 +1282,8 @@ class ExpressionWithTypeArguments extends @expression_with_type_arguments, Expr
|
||||
override ControlFlowNode getFirstControlFlowNode() {
|
||||
result = this.getExpression().getFirstControlFlowNode()
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ExpressionWithTypeArguments" }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1027,18 +1027,16 @@ module TaintTracking {
|
||||
class WhitelistContainmentCallSanitizer extends AdditionalSanitizerGuardNode,
|
||||
DataFlow::MethodCallNode {
|
||||
WhitelistContainmentCallSanitizer() {
|
||||
exists(string name |
|
||||
name = "contains" or
|
||||
name = "has" or
|
||||
name = "hasOwnProperty"
|
||||
|
|
||||
this.getMethodName() = name
|
||||
)
|
||||
this.getMethodName() = ["contains", "has", "hasOwnProperty", "hasOwn"]
|
||||
}
|
||||
|
||||
override predicate sanitizes(boolean outcome, Expr e) {
|
||||
outcome = true and
|
||||
e = this.getArgument(0).asExpr()
|
||||
exists(int propertyIndex |
|
||||
if this.getMethodName() = "hasOwn" then propertyIndex = 1 else propertyIndex = 0
|
||||
|
|
||||
outcome = true and
|
||||
e = this.getArgument(propertyIndex).asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate appliesTo(Configuration cfg) { any() }
|
||||
|
||||
@@ -198,7 +198,7 @@ module Babel {
|
||||
.getMember(["transform", "transformSync", "transformAsync"])
|
||||
.getACall() and
|
||||
pred = call.getArgument(0) and
|
||||
succ = [call, call.getParameter(2).getParameter(0).getAnImmediateUse()]
|
||||
succ = [call, call.getParameter(2).getParameter(0).asSource()]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ module Cheerio {
|
||||
}
|
||||
|
||||
/** Gets a reference to the `cheerio` function, possibly with a loaded DOM. */
|
||||
DataFlow::SourceNode cheerioRef() { result = cheerioApi().getAUse() }
|
||||
DataFlow::SourceNode cheerioRef() { result = cheerioApi().getAValueReachableFromSource() }
|
||||
|
||||
/**
|
||||
* A creation of `cheerio` object, a collection of virtual DOM elements
|
||||
|
||||
@@ -39,7 +39,8 @@ module ClassValidator {
|
||||
|
||||
/** Holds if the given field has a decorator that sanitizes its value for the purpose of taint tracking. */
|
||||
predicate isFieldSanitizedByDecorator(FieldDefinition field) {
|
||||
field.getADecorator().getExpression().flow() = sanitizingDecorator().getReturn().getAUse()
|
||||
field.getADecorator().getExpression().flow() =
|
||||
sanitizingDecorator().getReturn().getAValueReachableFromSource()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
|
||||
@@ -265,7 +265,7 @@ module ClientRequest {
|
||||
or
|
||||
responseType = this.getResponseType() and
|
||||
promise = false and
|
||||
result = this.getReturn().getPromisedError().getMember("response").getAnImmediateUse()
|
||||
result = this.getReturn().getPromisedError().getMember("response").asSource()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,7 +463,7 @@ module ClientRequest {
|
||||
*/
|
||||
private API::Node netSocketInstantiation(DataFlow::NewNode socket) {
|
||||
result = API::moduleImport("net").getMember("Socket").getInstance() and
|
||||
socket = result.getAnImmediateUse()
|
||||
socket = result.asSource()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -827,7 +827,7 @@ module ClientRequest {
|
||||
class ApolloClientRequest extends ClientRequest::Range, API::InvokeNode {
|
||||
ApolloClientRequest() { this = apolloUriCallee().getAnInvocation() }
|
||||
|
||||
override DataFlow::Node getUrl() { result = this.getParameter(0).getMember("uri").getARhs() }
|
||||
override DataFlow::Node getUrl() { result = this.getParameter(0).getMember("uri").asSink() }
|
||||
|
||||
override DataFlow::Node getHost() { none() }
|
||||
|
||||
@@ -848,10 +848,10 @@ module ClientRequest {
|
||||
|
||||
override DataFlow::Node getUrl() { result = this.getArgument(0) }
|
||||
|
||||
override DataFlow::Node getHost() { result = this.getParameter(0).getMember("host").getARhs() }
|
||||
override DataFlow::Node getHost() { result = this.getParameter(0).getMember("host").asSink() }
|
||||
|
||||
override DataFlow::Node getADataNode() {
|
||||
result = form.getMember("append").getACall().getParameter(1).getARhs()
|
||||
result = form.getMember("append").getACall().getParameter(1).asSink()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ private class CredentialsFromModel extends CredentialsExpr {
|
||||
string kind;
|
||||
|
||||
CredentialsFromModel() {
|
||||
this = ModelOutput::getASinkNode("credentials[" + kind + "]").getARhs().asExpr()
|
||||
this = ModelOutput::getASinkNode("credentials[" + kind + "]").asSink().asExpr()
|
||||
}
|
||||
|
||||
override string getCredentialsKind() { result = kind }
|
||||
|
||||
@@ -9,9 +9,7 @@ module D3 {
|
||||
private class D3GlobalEntry extends API::EntryPoint {
|
||||
D3GlobalEntry() { this = "D3GlobalEntry" }
|
||||
|
||||
override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("d3") }
|
||||
|
||||
override DataFlow::Node getARhs() { none() }
|
||||
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("d3") }
|
||||
}
|
||||
|
||||
/** Gets an API node referring to the `d3` module. */
|
||||
@@ -71,18 +69,18 @@ module D3 {
|
||||
D3XssSink() {
|
||||
exists(API::Node htmlArg |
|
||||
htmlArg = d3Selection().getMember("html").getParameter(0) and
|
||||
this = [htmlArg, htmlArg.getReturn()].getARhs()
|
||||
this = [htmlArg, htmlArg.getReturn()].asSink()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class D3DomValueSource extends DOM::DomValueSource::Range {
|
||||
D3DomValueSource() {
|
||||
this = d3Selection().getMember("each").getReceiver().getAnImmediateUse()
|
||||
this = d3Selection().getMember("each").getReceiver().asSource()
|
||||
or
|
||||
this = d3Selection().getMember("node").getReturn().getAnImmediateUse()
|
||||
this = d3Selection().getMember("node").getReturn().asSource()
|
||||
or
|
||||
this = d3Selection().getMember("nodes").getReturn().getUnknownMember().getAnImmediateUse()
|
||||
this = d3Selection().getMember("nodes").getReturn().getUnknownMember().asSource()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,13 +56,13 @@ module Electron {
|
||||
}
|
||||
}
|
||||
|
||||
private API::Node browserObject() { result.getAnImmediateUse() instanceof NewBrowserObject }
|
||||
private API::Node browserObject() { result.asSource() instanceof NewBrowserObject }
|
||||
|
||||
/**
|
||||
* A data flow node whose value may originate from a browser object instantiation.
|
||||
*/
|
||||
private class BrowserObjectByFlow extends BrowserObject {
|
||||
BrowserObjectByFlow() { browserObject().getAUse() = this }
|
||||
BrowserObjectByFlow() { browserObject().getAValueReachableFromSource() = this }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -89,7 +89,7 @@ private API::Node globbyFileNameSource() {
|
||||
* A file name or an array of file names from the `globby` library.
|
||||
*/
|
||||
private class GlobbyFileNameSource extends FileNameSource {
|
||||
GlobbyFileNameSource() { this = globbyFileNameSource().getAnImmediateUse() }
|
||||
GlobbyFileNameSource() { this = globbyFileNameSource().asSource() }
|
||||
}
|
||||
|
||||
/** Gets a file name or an array of file names from the `fast-glob` library. */
|
||||
@@ -116,7 +116,7 @@ private API::Node fastGlobFileName() {
|
||||
* A file name or an array of file names from the `fast-glob` library.
|
||||
*/
|
||||
private class FastGlobFileNameSource extends FileNameSource {
|
||||
FastGlobFileNameSource() { this = fastGlobFileName().getAnImmediateUse() }
|
||||
FastGlobFileNameSource() { this = fastGlobFileName().asSource() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,7 +200,7 @@ private class RecursiveReadDir extends FileSystemAccess, FileNameProducer, API::
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
|
||||
|
||||
override DataFlow::Node getAFileName() { result = this.trackFileSource().getAnImmediateUse() }
|
||||
override DataFlow::Node getAFileName() { result = this.trackFileSource().asSource() }
|
||||
|
||||
private API::Node trackFileSource() {
|
||||
result = this.getParameter([1 .. 2]).getParameter(1)
|
||||
@@ -223,7 +223,7 @@ private module JsonFile {
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
|
||||
|
||||
override DataFlow::Node getADataNode() { result = this.trackRead().getAnImmediateUse() }
|
||||
override DataFlow::Node getADataNode() { result = this.trackRead().asSource() }
|
||||
|
||||
private API::Node trackRead() {
|
||||
this.getCalleeName() = "readFile" and
|
||||
@@ -272,7 +272,7 @@ private class LoadJsonFile extends FileSystemReadAccess, API::CallNode {
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
|
||||
|
||||
override DataFlow::Node getADataNode() { result = this.trackRead().getAnImmediateUse() }
|
||||
override DataFlow::Node getADataNode() { result = this.trackRead().asSource() }
|
||||
|
||||
private API::Node trackRead() {
|
||||
this.getCalleeName() = "sync" and result = this.getReturn()
|
||||
@@ -310,7 +310,7 @@ private class WalkDir extends FileNameProducer, FileSystemAccess, API::CallNode
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
|
||||
|
||||
override DataFlow::Node getAFileName() { result = this.trackFileSource().getAnImmediateUse() }
|
||||
override DataFlow::Node getAFileName() { result = this.trackFileSource().asSource() }
|
||||
|
||||
private API::Node trackFileSource() {
|
||||
not this.getCalleeName() = ["sync", "async"] and
|
||||
|
||||
@@ -15,7 +15,7 @@ private class BusBoyRemoteFlow extends RemoteFlowSource {
|
||||
.getMember("on")
|
||||
.getParameter(1)
|
||||
.getAParameter()
|
||||
.getAnImmediateUse()
|
||||
.asSource()
|
||||
}
|
||||
|
||||
override string getSourceType() { result = "parsed user value from Busbuy" }
|
||||
@@ -49,12 +49,12 @@ private class MultipartyRemoteFlow extends RemoteFlowSource {
|
||||
MultipartyRemoteFlow() {
|
||||
exists(API::Node form | form = API::moduleImport("multiparty").getMember("Form").getInstance() |
|
||||
exists(API::CallNode parse | parse = form.getMember("parse").getACall() |
|
||||
this = parse.getParameter(1).getAParameter().getAnImmediateUse()
|
||||
this = parse.getParameter(1).getAParameter().asSource()
|
||||
)
|
||||
or
|
||||
exists(API::CallNode on | on = form.getMember("on").getACall() |
|
||||
on.getArgument(0).mayHaveStringValue(["part", "file", "field"]) and
|
||||
this = on.getParameter(1).getAParameter().getAnImmediateUse()
|
||||
this = on.getParameter(1).getAParameter().asSource()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,9 +8,7 @@ module History {
|
||||
private class HistoryGlobalEntry extends API::EntryPoint {
|
||||
HistoryGlobalEntry() { this = "HistoryLibrary" }
|
||||
|
||||
override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("HistoryLibrary") }
|
||||
|
||||
override DataFlow::Node getARhs() { none() }
|
||||
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("HistoryLibrary") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,11 +38,11 @@ module History {
|
||||
|
||||
HistoryLibraryRemoteFlow() {
|
||||
exists(API::Node loc | loc = [getBrowserHistory(), getHashHistory()].getMember("location") |
|
||||
this = loc.getMember("hash").getAnImmediateUse() and kind.isFragment()
|
||||
this = loc.getMember("hash").asSource() and kind.isFragment()
|
||||
or
|
||||
this = loc.getMember("pathname").getAnImmediateUse() and kind.isPath()
|
||||
this = loc.getMember("pathname").asSource() and kind.isPath()
|
||||
or
|
||||
this = loc.getMember("search").getAnImmediateUse() and kind.isQuery()
|
||||
this = loc.getMember("search").asSource() and kind.isQuery()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ private module HttpProxy {
|
||||
.getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() { result = getParameter(0).getMember("target").getARhs() }
|
||||
override DataFlow::Node getUrl() { result = getParameter(0).getMember("target").asSink() }
|
||||
|
||||
override DataFlow::Node getHost() {
|
||||
result = getParameter(0).getMember("target").getMember("host").getARhs()
|
||||
result = getParameter(0).getMember("target").getMember("host").asSink()
|
||||
}
|
||||
|
||||
override DataFlow::Node getADataNode() { none() }
|
||||
@@ -49,10 +49,10 @@ private module HttpProxy {
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() { result = getOptionsObject().getMember("target").getARhs() }
|
||||
override DataFlow::Node getUrl() { result = getOptionsObject().getMember("target").asSink() }
|
||||
|
||||
override DataFlow::Node getHost() {
|
||||
result = getOptionsObject().getMember("target").getMember("host").getARhs()
|
||||
result = getOptionsObject().getMember("target").getMember("host").asSink()
|
||||
}
|
||||
|
||||
override DataFlow::Node getADataNode() { none() }
|
||||
@@ -78,8 +78,8 @@ private module HttpProxy {
|
||||
ProxyListenerCallback() {
|
||||
exists(API::CallNode call |
|
||||
call = any(CreateServerCall server).getReturn().getMember(["on", "once"]).getACall() and
|
||||
call.getParameter(0).getARhs().mayHaveStringValue(event) and
|
||||
this = call.getParameter(1).getARhs().getAFunctionValue()
|
||||
call.getParameter(0).asSink().mayHaveStringValue(event) and
|
||||
this = call.getParameter(1).asSink().getAFunctionValue()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,7 @@ private module Immutable {
|
||||
private class ImmutableGlobalEntry extends API::EntryPoint {
|
||||
ImmutableGlobalEntry() { this = "ImmutableGlobalEntry" }
|
||||
|
||||
override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("Immutable") }
|
||||
|
||||
override DataFlow::Node getARhs() { none() }
|
||||
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("Immutable") }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -69,7 +69,7 @@ module Knex {
|
||||
private class KnexDatabaseAwait extends DatabaseAccess, DataFlow::ValueNode {
|
||||
KnexDatabaseAwait() {
|
||||
exists(AwaitExpr enclosingAwait | this = enclosingAwait.flow() |
|
||||
enclosingAwait.getOperand() = knexObject().getAUse().asExpr()
|
||||
enclosingAwait.getOperand() = knexObject().getAValueReachableFromSource().asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -61,10 +61,10 @@ module LdapJS {
|
||||
|
||||
SearchFilter() {
|
||||
options = ldapClient().getMember("search").getACall().getParameter(1) and
|
||||
this = options.getARhs()
|
||||
this = options.asSink()
|
||||
}
|
||||
|
||||
override DataFlow::Node getInput() { result = options.getMember("filter").getARhs() }
|
||||
override DataFlow::Node getInput() { result = options.getMember("filter").asSink() }
|
||||
|
||||
override DataFlow::Node getOutput() { result = this }
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ private module LiveServer {
|
||||
class ServerDefinition extends HTTP::Servers::StandardServerDefinition {
|
||||
ServerDefinition() { this = DataFlow::moduleImport("live-server").asExpr() }
|
||||
|
||||
API::Node getImportNode() { result.getAnImmediateUse().asExpr() = this }
|
||||
API::Node getImportNode() { result.asSource().asExpr() = this }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +41,7 @@ private module LiveServer {
|
||||
|
||||
override DataFlow::SourceNode getARouteHandler() {
|
||||
exists(DataFlow::SourceNode middleware |
|
||||
middleware = call.getParameter(0).getMember("middleware").getAValueReachingRhs()
|
||||
middleware = call.getParameter(0).getMember("middleware").getAValueReachingSink()
|
||||
|
|
||||
result = middleware.getAMemberCall(["push", "unshift"]).getArgument(0).getAFunctionValue()
|
||||
or
|
||||
|
||||
@@ -35,9 +35,7 @@ private module Console {
|
||||
private class ConsoleGlobalEntry extends API::EntryPoint {
|
||||
ConsoleGlobalEntry() { this = "ConsoleGlobalEntry" }
|
||||
|
||||
override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("console") }
|
||||
|
||||
override DataFlow::Node getARhs() { none() }
|
||||
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("console") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -352,7 +350,7 @@ private module Pino {
|
||||
// `pino` is installed as the "log" property on the request object in `Express` and similar libraries.
|
||||
// in `Hapi` the property is "logger".
|
||||
exists(HTTP::RequestExpr req, API::Node reqNode |
|
||||
reqNode.getAnImmediateUse() = req.flow().getALocalSource() and
|
||||
reqNode.asSource() = req.flow().getALocalSource() and
|
||||
result = reqNode.getMember(["log", "logger"])
|
||||
)
|
||||
}
|
||||
|
||||
@@ -163,14 +163,14 @@ module Markdown {
|
||||
or
|
||||
call = API::moduleImport("markdown-it").getMember("Markdown").getAnInvocation()
|
||||
|
|
||||
call.getParameter(0).getMember("html").getARhs().mayHaveBooleanValue(true) and
|
||||
call.getParameter(0).getMember("html").asSink().mayHaveBooleanValue(true) and
|
||||
result = call.getReturn()
|
||||
)
|
||||
or
|
||||
exists(API::CallNode call |
|
||||
call = markdownIt().getMember(["use", "set", "configure", "enable", "disable"]).getACall() and
|
||||
result = call.getReturn() and
|
||||
not call.getParameter(0).getAValueReachingRhs() =
|
||||
not call.getParameter(0).getAValueReachingSink() =
|
||||
DataFlow::moduleImport("markdown-it-sanitizer")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -140,11 +140,9 @@ module NestJS {
|
||||
private class ValidationNodeEntry extends API::EntryPoint {
|
||||
ValidationNodeEntry() { this = "ValidationNodeEntry" }
|
||||
|
||||
override DataFlow::SourceNode getAUse() {
|
||||
override DataFlow::SourceNode getASource() {
|
||||
result.(DataFlow::ClassNode).getName() = "ValidationPipe"
|
||||
}
|
||||
|
||||
override DataFlow::Node getARhs() { none() }
|
||||
}
|
||||
|
||||
/** Gets an API node referring to the constructor of `ValidationPipe` */
|
||||
@@ -181,7 +179,7 @@ module NestJS {
|
||||
predicate hasGlobalValidationPipe(Folder folder) {
|
||||
exists(DataFlow::CallNode call |
|
||||
call.getCalleeName() = "useGlobalPipes" and
|
||||
call.getArgument(0) = validationPipe().getInstance().getAUse() and
|
||||
call.getArgument(0) = validationPipe().getInstance().getAValueReachableFromSource() and
|
||||
folder = call.getFile().getParentContainer()
|
||||
)
|
||||
or
|
||||
@@ -193,7 +191,7 @@ module NestJS {
|
||||
.getAMember()
|
||||
.getMember("useFactory")
|
||||
.getReturn()
|
||||
.getARhs() = validationPipe().getInstance().getAUse() and
|
||||
.asSink() = validationPipe().getInstance().getAValueReachableFromSource() and
|
||||
folder = decorator.getFile().getParentContainer()
|
||||
)
|
||||
or
|
||||
@@ -204,7 +202,7 @@ module NestJS {
|
||||
* Holds if `param` is affected by a pipe that sanitizes inputs.
|
||||
*/
|
||||
private predicate hasSanitizingPipe(NestJSRequestInput param, boolean dependsOnType) {
|
||||
param.getAPipe() = sanitizingPipe(dependsOnType).getAUse()
|
||||
param.getAPipe() = sanitizingPipe(dependsOnType).getAValueReachableFromSource()
|
||||
or
|
||||
hasGlobalValidationPipe(param.getFile().getParentContainer()) and
|
||||
dependsOnType = true
|
||||
@@ -395,11 +393,11 @@ module NestJS {
|
||||
|
||||
/** Gets a parameter with this decorator applied. */
|
||||
DataFlow::ParameterNode getADecoratedParameter() {
|
||||
result.getADecorator() = getReturn().getReturn().getAUse()
|
||||
result.getADecorator() = getReturn().getReturn().getAValueReachableFromSource()
|
||||
}
|
||||
|
||||
/** Gets a value returned by the decorator's callback, which becomes the value of the decorated parameter. */
|
||||
DataFlow::Node getResult() { result = getParameter(0).getReturn().getARhs() }
|
||||
DataFlow::Node getResult() { result = getParameter(0).getReturn().asSink() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -427,7 +425,7 @@ module NestJS {
|
||||
private class ExpressRequestSource extends Express::RequestSource {
|
||||
ExpressRequestSource() {
|
||||
this.(DataFlow::ParameterNode).getADecorator() =
|
||||
nestjs().getMember(["Req", "Request"]).getReturn().getAnImmediateUse()
|
||||
nestjs().getMember(["Req", "Request"]).getReturn().asSource()
|
||||
or
|
||||
this =
|
||||
executionContext()
|
||||
@@ -435,7 +433,7 @@ module NestJS {
|
||||
.getReturn()
|
||||
.getMember("getRequest")
|
||||
.getReturn()
|
||||
.getAnImmediateUse()
|
||||
.asSource()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -452,7 +450,7 @@ module NestJS {
|
||||
private class ExpressResponseSource extends Express::ResponseSource {
|
||||
ExpressResponseSource() {
|
||||
this.(DataFlow::ParameterNode).getADecorator() =
|
||||
nestjs().getMember(["Res", "Response"]).getReturn().getAnImmediateUse()
|
||||
nestjs().getMember(["Res", "Response"]).getReturn().asSource()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -252,6 +252,6 @@ module NextJS {
|
||||
.getParameter(0)
|
||||
.getParameter(0)
|
||||
.getMember("router")
|
||||
.getAnImmediateUse()
|
||||
.asSource()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ deprecated module NoSQL = NoSql;
|
||||
* Gets a value that has been assigned to the "$where" property of an object that flows to `queryArg`.
|
||||
*/
|
||||
private DataFlow::Node getADollarWhereProperty(API::Node queryArg) {
|
||||
result = queryArg.getMember("$where").getARhs()
|
||||
result = queryArg.getMember("$where").asSink()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -418,7 +418,7 @@ private module Mongoose {
|
||||
param = f.getParameter(0).getParameter(1)
|
||||
|
|
||||
exists(DataFlow::MethodCallNode pred |
|
||||
// limitation: look at the previous method call
|
||||
// limitation: look at the previous method call
|
||||
Query::MethodSignatures::returnsDocumentQuery(pred.getMethodName(), asArray) and
|
||||
pred.getAMethodCall() = f.getACall()
|
||||
)
|
||||
@@ -501,7 +501,7 @@ private module Mongoose {
|
||||
|
||||
Credentials() {
|
||||
exists(string prop |
|
||||
this = createConnection().getParameter(3).getMember(prop).getARhs().asExpr()
|
||||
this = createConnection().getParameter(3).getMember(prop).asSink().asExpr()
|
||||
|
|
||||
prop = "user" and kind = "user name"
|
||||
or
|
||||
@@ -518,7 +518,7 @@ private module Mongoose {
|
||||
class MongoDBQueryPart extends NoSql::Query {
|
||||
MongooseFunction f;
|
||||
|
||||
MongoDBQueryPart() { this = f.getQueryArgument().getARhs().asExpr() }
|
||||
MongoDBQueryPart() { this = f.getQueryArgument().asSink().asExpr() }
|
||||
|
||||
override DataFlow::Node getACodeOperator() {
|
||||
result = getADollarWhereProperty(f.getQueryArgument())
|
||||
@@ -540,7 +540,7 @@ private module Mongoose {
|
||||
|
||||
override DataFlow::Node getAQueryArgument() {
|
||||
// NB: the complete information is not easily accessible for deeply chained calls
|
||||
f.getQueryArgument().getARhs() = result
|
||||
f.getQueryArgument().asSink() = result
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResult() {
|
||||
@@ -770,7 +770,7 @@ private module Redis {
|
||||
RedisKeyArgument() {
|
||||
exists(string method, int argIndex |
|
||||
QuerySignatures::argumentIsAmbiguousKey(method, argIndex) and
|
||||
this = redis().getMember(method).getParameter(argIndex).getARhs().asExpr()
|
||||
this = redis().getMember(method).getParameter(argIndex).asSink().asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -739,7 +739,7 @@ module NodeJSLib {
|
||||
methodName = ["execFile", "execFileSync", "spawn", "spawnSync", "fork"]
|
||||
) and
|
||||
// all of the above methods take the command as their first argument
|
||||
result = this.getParameter(0).getARhs()
|
||||
result = this.getParameter(0).asSink()
|
||||
}
|
||||
|
||||
override DataFlow::Node getACommandArgument() { result = this.getACommandArgument(_) }
|
||||
@@ -751,7 +751,7 @@ module NodeJSLib {
|
||||
override DataFlow::Node getArgumentList() {
|
||||
methodName = ["execFile", "execFileSync", "fork", "spawn", "spawnSync"] and
|
||||
// all of the above methods take the argument list as their second argument
|
||||
result = this.getParameter(1).getARhs()
|
||||
result = this.getParameter(1).asSink()
|
||||
}
|
||||
|
||||
override predicate isSync() { methodName.matches("%Sync") }
|
||||
@@ -759,7 +759,7 @@ module NodeJSLib {
|
||||
override DataFlow::Node getOptionsArg() {
|
||||
not result.getALocalSource() instanceof DataFlow::FunctionNode and // looks like callback
|
||||
not result.getALocalSource() instanceof DataFlow::ArrayCreationNode and // looks like argumentlist
|
||||
not result = this.getParameter(0).getARhs() and
|
||||
not result = this.getParameter(0).asSink() and
|
||||
// fork/spawn and all sync methos always has options as the last argument
|
||||
if
|
||||
methodName.matches("fork%") or
|
||||
@@ -768,7 +768,7 @@ module NodeJSLib {
|
||||
then result = this.getLastArgument()
|
||||
else
|
||||
// the rest (exec/execFile) has the options argument as their second last.
|
||||
result = this.getParameter(this.getNumArgument() - 2).getARhs()
|
||||
result = this.getParameter(this.getNumArgument() - 2).asSink()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1070,7 +1070,7 @@ module NodeJSLib {
|
||||
*/
|
||||
private class EventEmitterSubClass extends DataFlow::ClassNode {
|
||||
EventEmitterSubClass() {
|
||||
this.getASuperClassNode() = getAnEventEmitterImport().getAUse() or
|
||||
this.getASuperClassNode() = getAnEventEmitterImport().getAValueReachableFromSource() or
|
||||
this.getADirectSuperClass() instanceof EventEmitterSubClass
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ private module Prettier {
|
||||
call = API::moduleImport("prettier").getMember("formatWithCursor").getACall()
|
||||
|
|
||||
pred = call.getArgument(0) and
|
||||
succ = call.getReturn().getMember("formatted").getAnImmediateUse()
|
||||
succ = call.getReturn().getMember("formatted").asSource()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ module Puppeteer {
|
||||
this = page().getMember(["addStyleTag", "addScriptTag"]).getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() { result = getParameter(0).getMember("url").getARhs() }
|
||||
override DataFlow::Node getUrl() { result = getParameter(0).getMember("url").asSink() }
|
||||
|
||||
override DataFlow::Node getHost() { none() }
|
||||
|
||||
|
||||
@@ -58,10 +58,10 @@ module Redux {
|
||||
*/
|
||||
class StoreCreation extends DataFlow::SourceNode instanceof StoreCreation::Range {
|
||||
/** Gets a reference to the store. */
|
||||
DataFlow::SourceNode ref() { result = asApiNode().getAUse() }
|
||||
DataFlow::SourceNode ref() { result = asApiNode().getAValueReachableFromSource() }
|
||||
|
||||
/** Gets an API node that refers to this store creation. */
|
||||
API::Node asApiNode() { result.getAnImmediateUse() = this }
|
||||
API::Node asApiNode() { result.asSource() = this }
|
||||
|
||||
/** Gets the data flow node holding the root reducer for this store. */
|
||||
DataFlow::Node getReducerArg() { result = super.getReducerArg() }
|
||||
@@ -94,7 +94,7 @@ module Redux {
|
||||
}
|
||||
|
||||
override DataFlow::Node getReducerArg() {
|
||||
result = getParameter(0).getMember("reducer").getARhs()
|
||||
result = getParameter(0).getMember("reducer").asSink()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ module Redux {
|
||||
private API::Node rootState() {
|
||||
result instanceof RootStateSource
|
||||
or
|
||||
stateStep(rootState().getAUse(), result.getAnImmediateUse())
|
||||
stateStep(rootState().getAValueReachableFromSource(), result.asSource())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,7 +120,7 @@ module Redux {
|
||||
accessPath = joinAccessPaths(base, prop)
|
||||
)
|
||||
or
|
||||
stateStep(rootStateAccessPath(accessPath).getAUse(), result.getAnImmediateUse())
|
||||
stateStep(rootStateAccessPath(accessPath).getAValueReachableFromSource(), result.asSource())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,7 +193,7 @@ module Redux {
|
||||
CombineReducers() { this = combineReducers().getACall() }
|
||||
|
||||
override DataFlow::Node getStateHandlerArg(string prop) {
|
||||
result = getParameter(0).getMember(prop).getARhs()
|
||||
result = getParameter(0).getMember(prop).asSink()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ module Redux {
|
||||
*/
|
||||
private class NestedCombineReducers extends DelegatingReducer, DataFlow::ObjectLiteralNode {
|
||||
NestedCombineReducers() {
|
||||
this = combineReducers().getParameter(0).getAMember+().getAValueReachingRhs()
|
||||
this = combineReducers().getParameter(0).getAMember+().getAValueReachingSink()
|
||||
}
|
||||
|
||||
override DataFlow::Node getStateHandlerArg(string prop) {
|
||||
@@ -235,7 +235,7 @@ module Redux {
|
||||
|
||||
override DataFlow::Node getActionHandlerArg(DataFlow::Node actionType) {
|
||||
exists(DataFlow::PropWrite write |
|
||||
result = getParameter(0).getAMember().getARhs() and
|
||||
result = getParameter(0).getAMember().asSink() and
|
||||
write.getRhs() = result and
|
||||
actionType = write.getPropertyNameExpr().flow()
|
||||
)
|
||||
@@ -374,7 +374,7 @@ module Redux {
|
||||
|
||||
CreateSliceReducer() {
|
||||
call = API::moduleImport("@reduxjs/toolkit").getMember("createSlice").getACall() and
|
||||
this = call.getReturn().getMember("reducer").getAnImmediateUse()
|
||||
this = call.getReturn().getMember("reducer").asSource()
|
||||
}
|
||||
|
||||
private API::Node getABuilderRef() {
|
||||
@@ -385,14 +385,14 @@ module Redux {
|
||||
|
||||
override DataFlow::Node getActionHandlerArg(DataFlow::Node actionType) {
|
||||
exists(string name |
|
||||
result = call.getParameter(0).getMember("reducers").getMember(name).getARhs() and
|
||||
actionType = call.getReturn().getMember("actions").getMember(name).getAnImmediateUse()
|
||||
result = call.getParameter(0).getMember("reducers").getMember(name).asSink() and
|
||||
actionType = call.getReturn().getMember("actions").getMember(name).asSource()
|
||||
)
|
||||
or
|
||||
// Properties of 'extraReducers':
|
||||
// { extraReducers: { [action]: reducer }}
|
||||
exists(DataFlow::PropWrite write |
|
||||
result = call.getParameter(0).getMember("extraReducers").getAMember().getARhs() and
|
||||
result = call.getParameter(0).getMember("extraReducers").getAMember().asSink() and
|
||||
write.getRhs() = result and
|
||||
actionType = write.getPropertyNameExpr().flow()
|
||||
)
|
||||
@@ -444,8 +444,8 @@ module Redux {
|
||||
or
|
||||
// x -> bindActionCreators({ x, ... })
|
||||
exists(BindActionCreatorsCall bind, string prop |
|
||||
ref(t.continue()).flowsTo(bind.getParameter(0).getMember(prop).getARhs()) and
|
||||
result = bind.getReturn().getMember(prop).getAnImmediateUse()
|
||||
ref(t.continue()).flowsTo(bind.getParameter(0).getMember(prop).asSink()) and
|
||||
result = bind.getReturn().getMember(prop).asSource()
|
||||
)
|
||||
or
|
||||
// x -> combineActions(x, ...)
|
||||
@@ -580,11 +580,11 @@ module Redux {
|
||||
|
||||
MultiAction() {
|
||||
createActions = API::moduleImport("redux-actions").getMember("createActions").getACall() and
|
||||
this = createActions.getReturn().getMember(name).getAnImmediateUse()
|
||||
this = createActions.getReturn().getMember(name).asSource()
|
||||
}
|
||||
|
||||
override DataFlow::FunctionNode getMiddlewareFunction(boolean async) {
|
||||
result.flowsTo(createActions.getParameter(0).getMember(getTypeTag()).getARhs()) and
|
||||
result.flowsTo(createActions.getParameter(0).getMember(getTypeTag()).asSink()) and
|
||||
async = false
|
||||
}
|
||||
|
||||
@@ -614,12 +614,12 @@ module Redux {
|
||||
|
||||
CreateSliceAction() {
|
||||
call = API::moduleImport("@reduxjs/toolkit").getMember("createSlice").getACall() and
|
||||
this = call.getReturn().getMember("actions").getMember(actionName).getAnImmediateUse()
|
||||
this = call.getReturn().getMember("actions").getMember(actionName).asSource()
|
||||
}
|
||||
|
||||
override string getTypeTag() {
|
||||
exists(string prefix |
|
||||
call.getParameter(0).getMember("name").getARhs().mayHaveStringValue(prefix) and
|
||||
call.getParameter(0).getMember("name").asSink().mayHaveStringValue(prefix) and
|
||||
result = prefix + "/" + actionName
|
||||
)
|
||||
}
|
||||
@@ -640,7 +640,7 @@ module Redux {
|
||||
|
||||
override DataFlow::FunctionNode getMiddlewareFunction(boolean async) {
|
||||
async = true and
|
||||
result = getParameter(1).getAValueReachingRhs()
|
||||
result = getParameter(1).getAValueReachingSink()
|
||||
}
|
||||
|
||||
override string getTypeTag() { getArgument(0).mayHaveStringValue(result) }
|
||||
@@ -885,12 +885,12 @@ module Redux {
|
||||
accessPath = getAffectedStateAccessPath(reducer)
|
||||
|
|
||||
pred = function.getReturnNode() and
|
||||
succ = rootStateAccessPath(accessPath).getAnImmediateUse()
|
||||
succ = rootStateAccessPath(accessPath).asSource()
|
||||
or
|
||||
exists(string suffix, DataFlow::SourceNode base |
|
||||
base = [function.getParameter(0), function.getReturnNode().getALocalSource()] and
|
||||
pred = AccessPath::getAnAssignmentTo(base, suffix) and
|
||||
succ = rootStateAccessPath(accessPath + "." + suffix).getAnImmediateUse()
|
||||
succ = rootStateAccessPath(accessPath + "." + suffix).asSource()
|
||||
)
|
||||
)
|
||||
or
|
||||
@@ -901,7 +901,7 @@ module Redux {
|
||||
reducer.isRootStateHandler() and
|
||||
base = [function.getParameter(0), function.getReturnNode().getALocalSource()] and
|
||||
pred = AccessPath::getAnAssignmentTo(base, suffix) and
|
||||
succ = rootStateAccessPath(suffix).getAnImmediateUse()
|
||||
succ = rootStateAccessPath(suffix).asSource()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -916,7 +916,7 @@ module Redux {
|
||||
*/
|
||||
private DataFlow::ObjectLiteralNode getAManuallyDispatchedValue(string actionType) {
|
||||
result.getAPropertyWrite("type").getRhs().mayHaveStringValue(actionType) and
|
||||
result = getADispatchedValueNode().getAValueReachingRhs()
|
||||
result = getADispatchedValueNode().getAValueReachingSink()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -994,7 +994,7 @@ module Redux {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(API::CallNode call |
|
||||
call = useSelector().getACall() and
|
||||
pred = call.getParameter(0).getReturn().getARhs() and
|
||||
pred = call.getParameter(0).getReturn().asSink() and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
@@ -1046,19 +1046,19 @@ module Redux {
|
||||
//
|
||||
// const mapDispatchToProps = { foo }
|
||||
//
|
||||
result = getMapDispatchToProps().getMember(name).getARhs()
|
||||
result = getMapDispatchToProps().getMember(name).asSink()
|
||||
or
|
||||
//
|
||||
// const mapDispatchToProps = dispatch => ( { foo } )
|
||||
//
|
||||
result = getMapDispatchToProps().getReturn().getMember(name).getARhs()
|
||||
result = getMapDispatchToProps().getReturn().getMember(name).asSink()
|
||||
or
|
||||
// Explicitly bound by bindActionCreators:
|
||||
//
|
||||
// const mapDispatchToProps = dispatch => bindActionCreators({ foo }, dispatch);
|
||||
//
|
||||
exists(BindActionCreatorsCall bind |
|
||||
bind.flowsTo(getMapDispatchToProps().getReturn().getARhs()) and
|
||||
bind.flowsTo(getMapDispatchToProps().getReturn().asSink()) and
|
||||
result = bind.getOptionArgument(0, name)
|
||||
)
|
||||
}
|
||||
@@ -1096,9 +1096,7 @@ module Redux {
|
||||
private class HeuristicConnectEntryPoint extends API::EntryPoint {
|
||||
HeuristicConnectEntryPoint() { this = "react-redux-connect" }
|
||||
|
||||
override DataFlow::Node getARhs() { none() }
|
||||
|
||||
override DataFlow::SourceNode getAUse() {
|
||||
override DataFlow::SourceNode getASource() {
|
||||
exists(DataFlow::CallNode call |
|
||||
call.getAnArgument().asExpr().(Identifier).getName() =
|
||||
["mapStateToProps", "mapDispatchToProps"] and
|
||||
@@ -1115,12 +1113,12 @@ module Redux {
|
||||
|
||||
override API::Node getMapStateToProps() {
|
||||
result = getAParameter() and
|
||||
result.getARhs().asExpr().(Identifier).getName() = "mapStateToProps"
|
||||
result.asSink().asExpr().(Identifier).getName() = "mapStateToProps"
|
||||
}
|
||||
|
||||
override API::Node getMapDispatchToProps() {
|
||||
result = getAParameter() and
|
||||
result.getARhs().asExpr().(Identifier).getName() = "mapDispatchToProps"
|
||||
result.asSink().asExpr().(Identifier).getName() = "mapDispatchToProps"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1130,7 +1128,7 @@ module Redux {
|
||||
private class StateToPropsStep extends StateStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(ConnectCall call |
|
||||
pred = call.getMapStateToProps().getReturn().getARhs() and
|
||||
pred = call.getMapStateToProps().getReturn().asSink() and
|
||||
succ = call.getReactComponent().getADirectPropsAccess()
|
||||
)
|
||||
}
|
||||
@@ -1205,7 +1203,7 @@ module Redux {
|
||||
// Selector functions may be given as an array
|
||||
exists(DataFlow::ArrayCreationNode array |
|
||||
array.flowsTo(getArgument(0)) and
|
||||
result.getAUse() = array.getElement(i)
|
||||
result.getAValueReachableFromSource() = array.getElement(i)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1221,13 +1219,13 @@ module Redux {
|
||||
// Return value of `i`th callback flows to the `i`th parameter of the last callback.
|
||||
exists(CreateSelectorCall call, int index |
|
||||
call.getNumArgument() > 1 and
|
||||
pred = call.getSelectorFunction(index).getReturn().getARhs() and
|
||||
succ = call.getLastParameter().getParameter(index).getAnImmediateUse()
|
||||
pred = call.getSelectorFunction(index).getReturn().asSink() and
|
||||
succ = call.getLastParameter().getParameter(index).asSource()
|
||||
)
|
||||
or
|
||||
// The result of the last callback is the final result
|
||||
exists(CreateSelectorCall call |
|
||||
pred = call.getLastParameter().getReturn().getARhs() and
|
||||
pred = call.getLastParameter().getReturn().asSink() and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ module SQL {
|
||||
abstract class SqlString extends Expr { }
|
||||
|
||||
private class SqlStringFromModel extends SqlString {
|
||||
SqlStringFromModel() { this = ModelOutput::getASinkNode("sql-injection").getARhs().asExpr() }
|
||||
SqlStringFromModel() { this = ModelOutput::getASinkNode("sql-injection").asSink().asExpr() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,7 +109,7 @@ private module MySql {
|
||||
Credentials() {
|
||||
exists(API::Node callee, string prop |
|
||||
callee in [createConnection(), createPool()] and
|
||||
this = callee.getParameter(0).getMember(prop).getARhs().asExpr() and
|
||||
this = callee.getParameter(0).getMember(prop).asSink().asExpr() and
|
||||
(
|
||||
prop = "user" and kind = "user name"
|
||||
or
|
||||
@@ -200,7 +200,7 @@ private module Postgres {
|
||||
QueryString() {
|
||||
this = any(QueryCall qc).getAQueryArgument().asExpr()
|
||||
or
|
||||
this = API::moduleImport("pg-cursor").getParameter(0).getARhs().asExpr()
|
||||
this = API::moduleImport("pg-cursor").getParameter(0).asSink().asExpr()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,9 +210,9 @@ private module Postgres {
|
||||
|
||||
Credentials() {
|
||||
exists(string prop |
|
||||
this = [newClient(), newPool()].getParameter(0).getMember(prop).getARhs().asExpr()
|
||||
this = [newClient(), newPool()].getParameter(0).getMember(prop).asSink().asExpr()
|
||||
or
|
||||
this = pgPromise().getParameter(0).getMember(prop).getARhs().asExpr()
|
||||
this = pgPromise().getParameter(0).getMember(prop).asSink().asExpr()
|
||||
|
|
||||
prop = "user" and kind = "user name"
|
||||
or
|
||||
@@ -383,7 +383,7 @@ private module Sqlite {
|
||||
/** A call to a Sqlite query method. */
|
||||
private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode {
|
||||
QueryCall() {
|
||||
this = getAChainingQueryCall().getAnImmediateUse()
|
||||
this = getAChainingQueryCall().asSource()
|
||||
or
|
||||
this = database().getMember("prepare").getACall()
|
||||
}
|
||||
@@ -440,7 +440,8 @@ private module MsSql {
|
||||
override TaggedTemplateExpr astNode;
|
||||
|
||||
QueryTemplateExpr() {
|
||||
mssql().getMember("query").getAUse() = DataFlow::valueNode(astNode.getTag())
|
||||
mssql().getMember("query").getAValueReachableFromSource() =
|
||||
DataFlow::valueNode(astNode.getTag())
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResult() {
|
||||
@@ -494,7 +495,7 @@ private module MsSql {
|
||||
or
|
||||
callee = mssql().getMember("ConnectionPool")
|
||||
) and
|
||||
this = callee.getParameter(0).getMember(prop).getARhs().asExpr() and
|
||||
this = callee.getParameter(0).getMember(prop).asSink().asExpr() and
|
||||
(
|
||||
prop = "user" and kind = "user name"
|
||||
or
|
||||
|
||||
@@ -27,7 +27,7 @@ private module Snapdragon {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(string methodName, API::CallNode set, API::CallNode call, API::Node base |
|
||||
// the handler, registered with a call to `.set`.
|
||||
set = getSetCall+(base.getMember(methodName + "r")).getAnImmediateUse() and
|
||||
set = getSetCall+(base.getMember(methodName + "r")).asSource() and
|
||||
// the snapdragon instance. The API is chaining, you can also use the instance directly.
|
||||
base = API::moduleImport("snapdragon").getInstance() and
|
||||
methodName = ["parse", "compile"] and
|
||||
@@ -47,7 +47,7 @@ private module Snapdragon {
|
||||
or
|
||||
// for compiler handlers the input is the first parameter.
|
||||
methodName = "compile" and
|
||||
succ = set.getParameter(1).getParameter(0).getAnImmediateUse()
|
||||
succ = set.getParameter(1).getParameter(0).asSource()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ module SocketIO {
|
||||
class ServerObject extends SocketIOObject {
|
||||
API::Node node;
|
||||
|
||||
ServerObject() { node = newServer() and this = node.getAnImmediateUse() }
|
||||
ServerObject() { node = newServer() and this = node.asSource() }
|
||||
|
||||
/** Gets the Api node for this server. */
|
||||
API::Node asApiNode() { result = node }
|
||||
@@ -81,7 +81,7 @@ module SocketIO {
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::SourceNode ref() { result = this.server().getAUse() }
|
||||
override DataFlow::SourceNode ref() { result = this.server().getAValueReachableFromSource() }
|
||||
}
|
||||
|
||||
/** A data flow node that may produce (that is, create or return) a socket.io server. */
|
||||
@@ -119,7 +119,7 @@ module SocketIO {
|
||||
API::Node node;
|
||||
|
||||
NamespaceBase() {
|
||||
this = node.getAnImmediateUse() and
|
||||
this = node.asSource() and
|
||||
exists(ServerObject srv |
|
||||
// namespace lookup on `srv`
|
||||
node = srv.asApiNode().getMember("sockets") and
|
||||
@@ -158,7 +158,7 @@ module SocketIO {
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::SourceNode ref() { result = this.namespace().getAUse() }
|
||||
override DataFlow::SourceNode ref() { result = this.namespace().getAValueReachableFromSource() }
|
||||
}
|
||||
|
||||
/** A data flow node that may produce a namespace object. */
|
||||
|
||||
@@ -233,7 +233,7 @@ module Templating {
|
||||
/** Gets an API node that may flow to `succ` through a template instantiation. */
|
||||
private API::Node getTemplateInput(DataFlow::SourceNode succ) {
|
||||
exists(TemplateInstantiation inst, API::Node base, string name |
|
||||
base.getARhs() = inst.getTemplateParamsNode() and
|
||||
base.asSink() = inst.getTemplateParamsNode() and
|
||||
result = base.getMember(name) and
|
||||
succ =
|
||||
inst.getTemplateFile()
|
||||
@@ -244,7 +244,7 @@ module Templating {
|
||||
)
|
||||
or
|
||||
exists(TemplateInstantiation inst, string accessPath |
|
||||
result.getARhs() = inst.getTemplateParamForValue(accessPath) and
|
||||
result.asSink() = inst.getTemplateParamForValue(accessPath) and
|
||||
succ =
|
||||
inst.getTemplateFile()
|
||||
.getAnImportedFile*()
|
||||
@@ -261,7 +261,7 @@ module Templating {
|
||||
|
||||
private class TemplateInputStep extends DataFlow::SharedFlowStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
getTemplateInput(succ).getARhs() = pred
|
||||
getTemplateInput(succ).asSink() = pred
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,8 +321,8 @@ module Templating {
|
||||
result = this.getStringValue()
|
||||
or
|
||||
exists(API::Node node |
|
||||
this = node.getARhs() and
|
||||
result = node.getAValueReachingRhs().getStringValue()
|
||||
this = node.asSink() and
|
||||
result = node.getAValueReachingSink().getStringValue()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -657,11 +657,9 @@ module Templating {
|
||||
private class IncludeFunctionAsEntryPoint extends API::EntryPoint {
|
||||
IncludeFunctionAsEntryPoint() { this = "IncludeFunctionAsEntryPoint" }
|
||||
|
||||
override DataFlow::SourceNode getAUse() {
|
||||
override DataFlow::SourceNode getASource() {
|
||||
result = any(TemplatePlaceholderTag tag).getInnerTopLevel().getAVariableUse("include")
|
||||
}
|
||||
|
||||
override DataFlow::Node getARhs() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -718,7 +716,7 @@ module Templating {
|
||||
override TemplateSyntax getTemplateSyntax() { result.getAPackageName() = engine }
|
||||
|
||||
override DataFlow::SourceNode getOutput() {
|
||||
result = this.getParameter([1, 2]).getParameter(1).getAnImmediateUse()
|
||||
result = this.getParameter([1, 2]).getParameter(1).asSource()
|
||||
or
|
||||
not exists(this.getParameter([1, 2]).getParameter(1)) and
|
||||
result = this
|
||||
|
||||
@@ -21,7 +21,7 @@ module ParseTorrent {
|
||||
node = mod().getReturn() or
|
||||
node = mod().getMember("remote").getParameter(1).getParameter(1)
|
||||
) and
|
||||
this = node.getAnImmediateUse()
|
||||
this = node.asSource()
|
||||
}
|
||||
|
||||
/** Gets the API node for this torrent object. */
|
||||
@@ -29,7 +29,9 @@ module ParseTorrent {
|
||||
}
|
||||
|
||||
/** Gets a data flow node referring to a parsed torrent. */
|
||||
DataFlow::SourceNode parsedTorrentRef() { result = any(ParsedTorrent t).asApiNode().getAUse() }
|
||||
DataFlow::SourceNode parsedTorrentRef() {
|
||||
result = any(ParsedTorrent t).asApiNode().getAValueReachableFromSource()
|
||||
}
|
||||
|
||||
/**
|
||||
* An access to user-controlled torrent information.
|
||||
@@ -38,7 +40,7 @@ module ParseTorrent {
|
||||
UserControlledTorrentInfo() {
|
||||
exists(API::Node read |
|
||||
read = any(ParsedTorrent t).asApiNode().getAMember() and
|
||||
this = read.getAnImmediateUse()
|
||||
this = read.asSource()
|
||||
|
|
||||
exists(string prop |
|
||||
not (
|
||||
|
||||
@@ -14,9 +14,7 @@ module TrustedTypes {
|
||||
private class TrustedTypesEntry extends API::EntryPoint {
|
||||
TrustedTypesEntry() { this = "TrustedTypesEntry" }
|
||||
|
||||
override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("trustedTypes") }
|
||||
|
||||
override DataFlow::Node getARhs() { none() }
|
||||
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("trustedTypes") }
|
||||
}
|
||||
|
||||
private API::Node trustedTypesObj() { result = any(TrustedTypesEntry entry).getANode() }
|
||||
@@ -38,7 +36,7 @@ module TrustedTypes {
|
||||
private class PolicyInputStep extends DataFlow::SharedFlowStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(PolicyCreation policy, string method |
|
||||
pred = policy.getReturn().getMember(method).getParameter(0).getARhs() and
|
||||
pred = policy.getReturn().getMember(method).getParameter(0).asSink() and
|
||||
succ = policy.getPolicyCallback(method).getParameter(0)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ module Querystringify {
|
||||
* Gets a data flow source node for member `name` of the querystringify library.
|
||||
*/
|
||||
DataFlow::SourceNode querystringifyMember(string name) {
|
||||
result = querystringify().getMember(name).getAnImmediateUse()
|
||||
result = querystringify().getMember(name).asSource()
|
||||
}
|
||||
|
||||
/** Gets an API node referring to the `querystringify` module. */
|
||||
|
||||
@@ -9,9 +9,7 @@ module Vue {
|
||||
private class GlobalVueEntryPoint extends API::EntryPoint {
|
||||
GlobalVueEntryPoint() { this = "VueEntryPoint" }
|
||||
|
||||
override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("Vue") }
|
||||
|
||||
override DataFlow::Node getARhs() { none() }
|
||||
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("Vue") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -22,9 +20,7 @@ module Vue {
|
||||
private class VueExportEntryPoint extends API::EntryPoint {
|
||||
VueExportEntryPoint() { this = "VueExportEntryPoint" }
|
||||
|
||||
override DataFlow::SourceNode getAUse() { none() }
|
||||
|
||||
override DataFlow::Node getARhs() {
|
||||
override DataFlow::Node getASink() {
|
||||
result = any(SingleFileComponent c).getModule().getDefaultOrBulkExport()
|
||||
}
|
||||
}
|
||||
@@ -41,7 +37,7 @@ module Vue {
|
||||
/**
|
||||
* Gets a reference to the 'Vue' object.
|
||||
*/
|
||||
DataFlow::SourceNode vue() { result = vueLibrary().getAnImmediateUse() }
|
||||
DataFlow::SourceNode vue() { result = vueLibrary().asSource() }
|
||||
|
||||
/** Gets an API node referring to a component or `Vue`. */
|
||||
private API::Node component() {
|
||||
@@ -176,8 +172,8 @@ module Vue {
|
||||
|
||||
/** Gets a component which is extended by this one. */
|
||||
Component getABaseComponent() {
|
||||
result.getComponentRef().getAUse() =
|
||||
getOwnOptions().getMember(["extends", "mixins"]).getARhs()
|
||||
result.getComponentRef().getAValueReachableFromSource() =
|
||||
getOwnOptions().getMember(["extends", "mixins"]).asSink()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,12 +191,12 @@ module Vue {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Use `getOwnOptions().getARhs()`.
|
||||
* DEPRECATED. Use `getOwnOptions().getASink()`.
|
||||
*
|
||||
* Gets the options passed to the Vue object, such as the object literal `{...}` in `new Vue{{...})`
|
||||
* or the default export of a single-file component.
|
||||
*/
|
||||
deprecated DataFlow::Node getOwnOptionsObject() { result = getOwnOptions().getARhs() }
|
||||
deprecated DataFlow::Node getOwnOptionsObject() { result = getOwnOptions().asSink() }
|
||||
|
||||
/**
|
||||
* Gets the class implementing this Vue component, if any.
|
||||
@@ -208,19 +204,19 @@ module Vue {
|
||||
* Specifically, this is a class annotated with `@Component` which flows to the options
|
||||
* object of this Vue component.
|
||||
*/
|
||||
ClassComponent getAsClassComponent() { result = getOwnOptions().getAValueReachingRhs() }
|
||||
ClassComponent getAsClassComponent() { result = getOwnOptions().getAValueReachingSink() }
|
||||
|
||||
/**
|
||||
* Gets the node for option `name` for this component, not including
|
||||
* those from extended objects and mixins.
|
||||
*/
|
||||
DataFlow::Node getOwnOption(string name) { result = getOwnOptions().getMember(name).getARhs() }
|
||||
DataFlow::Node getOwnOption(string name) { result = getOwnOptions().getMember(name).asSink() }
|
||||
|
||||
/**
|
||||
* Gets the node for option `name` for this component, including those from
|
||||
* extended objects and mixins.
|
||||
*/
|
||||
DataFlow::Node getOption(string name) { result = getOptions().getMember(name).getARhs() }
|
||||
DataFlow::Node getOption(string name) { result = getOptions().getMember(name).asSink() }
|
||||
|
||||
/**
|
||||
* Gets a source node flowing into the option `name` of this component, including those from
|
||||
@@ -228,7 +224,7 @@ module Vue {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
DataFlow::SourceNode getOptionSource(string name) {
|
||||
result = getOptions().getMember(name).getAValueReachingRhs()
|
||||
result = getOptions().getMember(name).getAValueReachingSink()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -289,7 +285,7 @@ module Vue {
|
||||
DataFlow::FunctionNode getWatchHandler(string propName) {
|
||||
exists(API::Node propWatch |
|
||||
propWatch = getOptions().getMember("watch").getMember(propName) and
|
||||
result = [propWatch, propWatch.getMember("handler")].getAValueReachingRhs()
|
||||
result = [propWatch, propWatch.getMember("handler")].getAValueReachingSink()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -322,16 +318,16 @@ module Vue {
|
||||
* Gets a node for a function that will be invoked with `this` bound to this component.
|
||||
*/
|
||||
DataFlow::FunctionNode getABoundFunction() {
|
||||
result = getOptions().getAMember+().getAValueReachingRhs()
|
||||
result = getOptions().getAMember+().getAValueReachingSink()
|
||||
or
|
||||
result = getAsClassComponent().getAnInstanceMember()
|
||||
}
|
||||
|
||||
/** Gets an API node referring to an instance of this component. */
|
||||
API::Node getInstance() { result.getAnImmediateUse() = getABoundFunction().getReceiver() }
|
||||
API::Node getInstance() { result.asSource() = getABoundFunction().getReceiver() }
|
||||
|
||||
/** Gets a data flow node referring to an instance of this component. */
|
||||
DataFlow::SourceNode getAnInstanceRef() { result = getInstance().getAnImmediateUse() }
|
||||
DataFlow::SourceNode getAnInstanceRef() { result = getInstance().asSource() }
|
||||
|
||||
pragma[noinline]
|
||||
private DataFlow::PropWrite getAPropertyValueWrite(string name) {
|
||||
@@ -484,14 +480,12 @@ module Vue {
|
||||
private class VueFileImportEntryPoint extends API::EntryPoint {
|
||||
VueFileImportEntryPoint() { this = "VueFileImportEntryPoint" }
|
||||
|
||||
override DataFlow::SourceNode getAUse() {
|
||||
override DataFlow::SourceNode getASource() {
|
||||
exists(Import imprt |
|
||||
imprt.getImportedPath().resolve() instanceof VueFile and
|
||||
result = imprt.getImportedModuleNode()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getARhs() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -533,13 +527,13 @@ module Vue {
|
||||
// of the .vue file.
|
||||
exists(Import imprt |
|
||||
imprt.getImportedPath().resolve() = file and
|
||||
result.getAnImmediateUse() = imprt.getImportedModuleNode()
|
||||
result.asSource() = imprt.getImportedModuleNode()
|
||||
)
|
||||
}
|
||||
|
||||
override API::Node getOwnOptions() {
|
||||
// Use the entry point generated by `VueExportEntryPoint`
|
||||
result.getARhs() = getModule().getDefaultOrBulkExport()
|
||||
result.asSink() = getModule().getDefaultOrBulkExport()
|
||||
}
|
||||
|
||||
override string toString() { result = file.toString() }
|
||||
@@ -695,7 +689,7 @@ module Vue {
|
||||
t.start() and
|
||||
(
|
||||
exists(API::Node router | router = API::moduleImport("vue-router") |
|
||||
result = router.getInstance().getMember("currentRoute").getAnImmediateUse()
|
||||
result = router.getInstance().getMember("currentRoute").asSource()
|
||||
or
|
||||
result =
|
||||
router
|
||||
@@ -703,17 +697,12 @@ module Vue {
|
||||
.getMember(["beforeEach", "beforeResolve", "afterEach"])
|
||||
.getParameter(0)
|
||||
.getParameter([0, 1])
|
||||
.getAnImmediateUse()
|
||||
.asSource()
|
||||
or
|
||||
result =
|
||||
router
|
||||
.getParameter(0)
|
||||
.getMember("scrollBehavior")
|
||||
.getParameter([0, 1])
|
||||
.getAnImmediateUse()
|
||||
result = router.getParameter(0).getMember("scrollBehavior").getParameter([0, 1]).asSource()
|
||||
)
|
||||
or
|
||||
result = routeConfig().getMember("beforeEnter").getParameter([0, 1]).getAnImmediateUse()
|
||||
result = routeConfig().getMember("beforeEnter").getParameter([0, 1]).asSource()
|
||||
or
|
||||
exists(Component c |
|
||||
result = c.getABoundFunction().getAFunctionValue().getReceiver().getAPropertyRead("$route")
|
||||
|
||||
@@ -75,7 +75,7 @@ module Vuex {
|
||||
or
|
||||
exists(API::CallNode call |
|
||||
call = vuex().getMember("createNamespacedHelpers").getACall() and
|
||||
namespace = call.getParameter(0).getAValueReachingRhs().getStringValue() + "/" and
|
||||
namespace = call.getParameter(0).getAValueReachingSink().getStringValue() + "/" and
|
||||
this = call.getReturn().getMember(helperName).getACall()
|
||||
)
|
||||
)
|
||||
@@ -88,7 +88,8 @@ module Vuex {
|
||||
pragma[noinline]
|
||||
string getNamespace() {
|
||||
getNumArgument() = 2 and
|
||||
result = appendToNamespace(namespace, getParameter(0).getAValueReachingRhs().getStringValue())
|
||||
result =
|
||||
appendToNamespace(namespace, getParameter(0).getAValueReachingSink().getStringValue())
|
||||
or
|
||||
getNumArgument() = 1 and
|
||||
result = namespace
|
||||
@@ -99,28 +100,28 @@ module Vuex {
|
||||
*/
|
||||
predicate hasMapping(string localName, string storeName) {
|
||||
// mapGetters('foo')
|
||||
getLastParameter().getAValueReachingRhs().getStringValue() = localName and
|
||||
getLastParameter().getAValueReachingSink().getStringValue() = localName and
|
||||
storeName = getNamespace() + localName
|
||||
or
|
||||
// mapGetters(['foo', 'bar'])
|
||||
getLastParameter().getUnknownMember().getAValueReachingRhs().getStringValue() = localName and
|
||||
getLastParameter().getUnknownMember().getAValueReachingSink().getStringValue() = localName and
|
||||
storeName = getNamespace() + localName
|
||||
or
|
||||
// mapGetters({foo: 'bar'})
|
||||
storeName =
|
||||
getNamespace() +
|
||||
getLastParameter().getMember(localName).getAValueReachingRhs().getStringValue() and
|
||||
getLastParameter().getMember(localName).getAValueReachingSink().getStringValue() and
|
||||
localName != "*" // ignore special API graph member named "*"
|
||||
}
|
||||
|
||||
/** Gets the Vue component in which the generated functions are installed. */
|
||||
Vue::Component getVueComponent() {
|
||||
exists(DataFlow::ObjectLiteralNode obj |
|
||||
obj.getASpreadProperty() = getReturn().getAUse() and
|
||||
result.getOwnOptions().getAMember().getARhs() = obj
|
||||
obj.getASpreadProperty() = getReturn().getAValueReachableFromSource() and
|
||||
result.getOwnOptions().getAMember().asSink() = obj
|
||||
)
|
||||
or
|
||||
result.getOwnOptions().getAMember().getARhs() = this
|
||||
result.getOwnOptions().getAMember().asSink() = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +147,7 @@ module Vuex {
|
||||
/** Gets a value that is returned by a getter registered with the given name. */
|
||||
private DataFlow::Node getterPred(string name) {
|
||||
exists(string prefix, string prop |
|
||||
result = storeConfigObject(prefix).getMember("getters").getMember(prop).getReturn().getARhs() and
|
||||
result = storeConfigObject(prefix).getMember("getters").getMember(prop).getReturn().asSink() and
|
||||
name = prefix + prop
|
||||
)
|
||||
}
|
||||
@@ -154,12 +155,12 @@ module Vuex {
|
||||
/** Gets a property access that may receive the produced by a getter of the given name. */
|
||||
private DataFlow::Node getterSucc(string name) {
|
||||
exists(string prefix, string prop |
|
||||
result = storeRef(prefix).getMember("getters").getMember(prop).getAnImmediateUse() and
|
||||
result = storeRef(prefix).getMember("getters").getMember(prop).asSource() and
|
||||
prop != "*" and
|
||||
name = prefix + prop
|
||||
)
|
||||
or
|
||||
result = getAMappedAccess("mapGetters", name).getAnImmediateUse()
|
||||
result = getAMappedAccess("mapGetters", name).asSource()
|
||||
}
|
||||
|
||||
/** Holds if `pred -> succ` is a step from a getter function to a relevant property access. */
|
||||
@@ -212,19 +213,19 @@ module Vuex {
|
||||
commitCall = commitLikeFunctionRef(kind, prefix).getACall()
|
||||
|
|
||||
// commit('name', payload)
|
||||
name = prefix + commitCall.getParameter(0).getAValueReachingRhs().getStringValue() and
|
||||
name = prefix + commitCall.getParameter(0).getAValueReachingSink().getStringValue() and
|
||||
result = commitCall.getArgument(1)
|
||||
or
|
||||
// commit({type: 'name', ...<payload>...})
|
||||
name =
|
||||
prefix +
|
||||
commitCall.getParameter(0).getMember("type").getAValueReachingRhs().getStringValue() and
|
||||
commitCall.getParameter(0).getMember("type").getAValueReachingSink().getStringValue() and
|
||||
result = commitCall.getArgument(0)
|
||||
)
|
||||
or
|
||||
// this.name(payload)
|
||||
// methods: {...mapMutations(['name'])} }
|
||||
result = getAMappedAccess(getMapHelperForCommitKind(kind), name).getParameter(0).getARhs()
|
||||
result = getAMappedAccess(getMapHelperForCommitKind(kind), name).getParameter(0).asSink()
|
||||
}
|
||||
|
||||
/** Gets a node that refers the payload of a committed mutation with the given `name.` */
|
||||
@@ -238,7 +239,7 @@ module Vuex {
|
||||
.getMember(getStorePropForCommitKind(kind))
|
||||
.getMember(prop)
|
||||
.getParameter(1)
|
||||
.getAnImmediateUse() and
|
||||
.asSource() and
|
||||
prop != "*" and
|
||||
name = prefix + prop
|
||||
)
|
||||
@@ -293,19 +294,17 @@ module Vuex {
|
||||
|
||||
/** Gets a value that flows into the given access path of the state. */
|
||||
DataFlow::Node stateMutationPred(string path) {
|
||||
result = stateRefByAccessPath(path).getARhs()
|
||||
result = stateRefByAccessPath(path).asSink()
|
||||
or
|
||||
exists(ExtendCall call, string base, string prop |
|
||||
call.getDestinationOperand() = stateRefByAccessPath(base).getAUse() and
|
||||
call.getDestinationOperand() = stateRefByAccessPath(base).getAValueReachableFromSource() and
|
||||
result = call.getASourceOperand().getALocalSource().getAPropertyWrite(prop).getRhs() and
|
||||
path = appendToNamespace(base, prop)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a value that refers to the given access path of the state. */
|
||||
DataFlow::Node stateMutationSucc(string path) {
|
||||
result = stateRefByAccessPath(path).getAnImmediateUse()
|
||||
}
|
||||
DataFlow::Node stateMutationSucc(string path) { result = stateRefByAccessPath(path).asSource() }
|
||||
|
||||
/** Holds if `pred -> succ` is a step from state mutation to state access. */
|
||||
predicate stateMutationStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
@@ -325,7 +324,7 @@ module Vuex {
|
||||
exists(MapHelperCall call |
|
||||
call.getHelperName() = "mapState" and
|
||||
component = call.getVueComponent() and
|
||||
result = call.getLastParameter().getMember(name).getReturn().getARhs()
|
||||
result = call.getLastParameter().getMember(name).getReturn().asSink()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -336,7 +335,7 @@ module Vuex {
|
||||
predicate mapStateHelperStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(Vue::Component component, string name |
|
||||
pred = mapStateHelperPred(component, name) and
|
||||
succ = pragma[only_bind_out](component).getInstance().getMember(name).getAnImmediateUse()
|
||||
succ = pragma[only_bind_out](component).getInstance().getMember(name).asSource()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -378,7 +377,7 @@ module Vuex {
|
||||
|
||||
/** Gets a package that can be considered an entry point for a Vuex app. */
|
||||
private PackageJson entryPointPackage() {
|
||||
result = getPackageJson(storeRef().getAnImmediateUse().getFile())
|
||||
result = getPackageJson(storeRef().asSource().getFile())
|
||||
or
|
||||
// Any package that imports a store-creating package is considered a potential entry point.
|
||||
packageDependsOn(result, entryPointPackage())
|
||||
|
||||
@@ -100,7 +100,7 @@ module XML {
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResult() {
|
||||
result = [doc(), element(), attr()].getAnImmediateUse()
|
||||
result = [doc(), element(), attr()].asSource()
|
||||
or
|
||||
result = element().getMember(["name", "text"]).getACall()
|
||||
or
|
||||
@@ -282,11 +282,7 @@ module XML {
|
||||
|
||||
override DataFlow::Node getAResult() {
|
||||
result =
|
||||
parser
|
||||
.getReturn()
|
||||
.getMember(any(string s | s.matches("on%")))
|
||||
.getAParameter()
|
||||
.getAnImmediateUse()
|
||||
parser.getReturn().getMember(any(string s | s.matches("on%"))).getAParameter().asSource()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import Shared::ModelOutput as ModelOutput
|
||||
* A remote flow source originating from a CSV source row.
|
||||
*/
|
||||
private class RemoteFlowSourceFromCsv extends RemoteFlowSource {
|
||||
RemoteFlowSourceFromCsv() { this = ModelOutput::getASourceNode("remote").getAnImmediateUse() }
|
||||
RemoteFlowSourceFromCsv() { this = ModelOutput::getASourceNode("remote").asSource() }
|
||||
|
||||
override string getSourceType() { result = "Remote flow" }
|
||||
}
|
||||
@@ -37,8 +37,8 @@ private class RemoteFlowSourceFromCsv extends RemoteFlowSource {
|
||||
private predicate summaryStepNodes(DataFlow::Node pred, DataFlow::Node succ, string kind) {
|
||||
exists(API::Node predNode, API::Node succNode |
|
||||
Specific::summaryStep(predNode, succNode, kind) and
|
||||
pred = predNode.getARhs() and
|
||||
succ = succNode.getAnImmediateUse()
|
||||
pred = predNode.asSink() and
|
||||
succ = succNode.asSource()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -299,7 +299,7 @@ private class AccessPathRange extends AccessPath::Range {
|
||||
bindingset[token]
|
||||
API::Node getSuccessorFromNode(API::Node node, AccessPathToken token) {
|
||||
// API graphs use the same label for arguments and parameters. An edge originating from a
|
||||
// use-node represents be an argument, and an edge originating from a def-node represents a parameter.
|
||||
// use-node represents an argument, and an edge originating from a def-node represents a parameter.
|
||||
// We just map both to the same thing.
|
||||
token.getName() = ["Argument", "Parameter"] and
|
||||
result = node.getParameter(AccessPath::parseIntUnbounded(token.getAnArgument()))
|
||||
|
||||
@@ -61,9 +61,7 @@ private class GlobalApiEntryPoint extends API::EntryPoint {
|
||||
this = "GlobalApiEntryPoint:" + global
|
||||
}
|
||||
|
||||
override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef(global) }
|
||||
|
||||
override DataFlow::Node getARhs() { none() }
|
||||
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef(global) }
|
||||
|
||||
/** Gets the name of the global variable. */
|
||||
string getGlobal() { result = global }
|
||||
@@ -151,7 +149,7 @@ API::Node getExtraSuccessorFromInvoke(API::InvokeNode node, AccessPathToken toke
|
||||
or
|
||||
token.getName() = "Argument" and
|
||||
token.getAnArgument() = "this" and
|
||||
result.getARhs() = node.(DataFlow::CallNode).getReceiver()
|
||||
result.asSink() = node.(DataFlow::CallNode).getReceiver()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,7 +58,7 @@ class RemoteServerResponse extends HeuristicSource, RemoteFlowSource {
|
||||
*/
|
||||
private class RemoteFlowSourceFromDBAccess extends RemoteFlowSource, HeuristicSource {
|
||||
RemoteFlowSourceFromDBAccess() {
|
||||
this = ModelOutput::getASourceNode("database-access-result").getAUse() or
|
||||
this = ModelOutput::getASourceNode("database-access-result").getAValueReachableFromSource() or
|
||||
exists(DatabaseAccess dba | this = dba.getAResult())
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ module DomBasedXss {
|
||||
or
|
||||
// A construction of a JSDOM object (server side DOM), where scripts are allowed.
|
||||
exists(DataFlow::NewNode instance |
|
||||
instance = API::moduleImport("jsdom").getMember("JSDOM").getInstance().getAnImmediateUse() and
|
||||
instance = API::moduleImport("jsdom").getMember("JSDOM").getInstance().asSource() and
|
||||
this = instance.getArgument(0) and
|
||||
instance.getOptionArgument(1, "runScripts").mayHaveStringValue("dangerously")
|
||||
)
|
||||
|
||||
@@ -61,7 +61,7 @@ module ExceptionXss {
|
||||
*/
|
||||
private class JsonSchemaValidationError extends Source {
|
||||
JsonSchemaValidationError() {
|
||||
this = any(JsonSchema::Ajv::Instance i).getAValidationError().getAnImmediateUse()
|
||||
this = any(JsonSchema::Ajv::Instance i).getAValidationError().asSource()
|
||||
or
|
||||
this = any(JsonSchema::Joi::JoiValidationErrorRead r).getAValidationResultAccess(_)
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ module ExternalApiUsedWithUntrustedData {
|
||||
}
|
||||
|
||||
/** Holds if `node` corresponds to a deep object argument. */
|
||||
private predicate isDeepObjectSink(API::Node node) { node.getARhs() instanceof DeepObjectSink }
|
||||
private predicate isDeepObjectSink(API::Node node) { node.asSink() instanceof DeepObjectSink }
|
||||
|
||||
/**
|
||||
* A sanitizer for data flowing to an external API.
|
||||
@@ -165,9 +165,9 @@ module ExternalApiUsedWithUntrustedData {
|
||||
not param = base.getReceiver()
|
||||
|
|
||||
result = param and
|
||||
name = param.getAnImmediateUse().asExpr().(Parameter).getName()
|
||||
name = param.asSource().asExpr().(Parameter).getName()
|
||||
or
|
||||
param.getAnImmediateUse().asExpr() instanceof DestructuringPattern and
|
||||
param.asSource().asExpr() instanceof DestructuringPattern and
|
||||
result = param.getMember(name)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ module IndirectCommandInjection {
|
||||
].getMember("parse").getACall()
|
||||
or
|
||||
// `require('commander').myCmdArgumentName`
|
||||
this = commander().getAMember().getAnImmediateUse()
|
||||
this = commander().getAMember().asSource()
|
||||
or
|
||||
// `require('commander').opt()` => `{a: ..., b: ...}`
|
||||
this = commander().getMember("opts").getACall()
|
||||
|
||||
@@ -152,9 +152,7 @@ abstract class RateLimitingMiddleware extends DataFlow::SourceNode {
|
||||
* A rate limiter constructed using the `express-rate-limit` package.
|
||||
*/
|
||||
class ExpressRateLimit extends RateLimitingMiddleware {
|
||||
ExpressRateLimit() {
|
||||
this = API::moduleImport("express-rate-limit").getReturn().getAnImmediateUse()
|
||||
}
|
||||
ExpressRateLimit() { this = API::moduleImport("express-rate-limit").getReturn().asSource() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,7 +160,7 @@ class ExpressRateLimit extends RateLimitingMiddleware {
|
||||
*/
|
||||
class BruteForceRateLimit extends RateLimitingMiddleware {
|
||||
BruteForceRateLimit() {
|
||||
this = API::moduleImport("express-brute").getInstance().getMember("prevent").getAnImmediateUse()
|
||||
this = API::moduleImport("express-brute").getInstance().getMember("prevent").asSource()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +172,7 @@ class BruteForceRateLimit extends RateLimitingMiddleware {
|
||||
*/
|
||||
class RouteHandlerLimitedByExpressLimiter extends RateLimitingMiddleware {
|
||||
RouteHandlerLimitedByExpressLimiter() {
|
||||
this = API::moduleImport("express-limiter").getReturn().getReturn().getAnImmediateUse()
|
||||
this = API::moduleImport("express-limiter").getReturn().getReturn().asSource()
|
||||
}
|
||||
|
||||
override Routing::Node getRoutingNode() {
|
||||
@@ -211,7 +209,7 @@ class RateLimiterFlexibleRateLimiter extends DataFlow::FunctionNode {
|
||||
rateLimiterClass = API::moduleImport("rate-limiter-flexible").getMember(rateLimiterClassName) and
|
||||
rateLimiterConsume = rateLimiterClass.getInstance().getMember("consume") and
|
||||
request.getParameter() = getRouteHandlerParameter(this.getFunction(), "request") and
|
||||
request.getAPropertyRead().flowsTo(rateLimiterConsume.getAParameter().getARhs())
|
||||
request.getAPropertyRead().flowsTo(rateLimiterConsume.getAParameter().asSink())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,9 +164,7 @@ private class ExternalRemoteFlowSourceSpecEntryPoint extends API::EntryPoint {
|
||||
|
||||
string getName() { result = name }
|
||||
|
||||
override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef(name) }
|
||||
|
||||
override DataFlow::Node getARhs() { none() }
|
||||
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef(name) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,7 +173,7 @@ private class ExternalRemoteFlowSourceSpecEntryPoint extends API::EntryPoint {
|
||||
private class ExternalRemoteFlowSource extends RemoteFlowSource {
|
||||
RemoteFlowSourceAccessPath ap;
|
||||
|
||||
ExternalRemoteFlowSource() { Stages::Taint::ref() and this = ap.resolve().getAnImmediateUse() }
|
||||
ExternalRemoteFlowSource() { Stages::Taint::ref() and this = ap.resolve().asSource() }
|
||||
|
||||
override string getSourceType() { result = ap.getSourceType() }
|
||||
}
|
||||
|
||||
@@ -78,14 +78,8 @@ module ResourceExhaustion {
|
||||
exists(DataFlow::SourceNode clazz, DataFlow::InvokeNode invk, int index |
|
||||
clazz = DataFlow::globalVarRef("Buffer") and this = invk.getArgument(index)
|
||||
|
|
||||
exists(string name |
|
||||
invk = clazz.getAMemberCall(name) and
|
||||
(
|
||||
name = "from" and index = 2 // the length argument
|
||||
or
|
||||
name = ["alloc", "allocUnsafe", "allocUnsafeSlow"] and index = 0 // the buffer size
|
||||
)
|
||||
)
|
||||
invk = clazz.getAMemberCall(["alloc", "allocUnsafe", "allocUnsafeSlow"]) and
|
||||
index = 0 // the buffer size
|
||||
or
|
||||
invk = clazz.getAnInvocation() and
|
||||
(
|
||||
|
||||
@@ -51,7 +51,7 @@ module SqlInjection {
|
||||
this = any(LdapJS::ClientCall call).getArgument(0)
|
||||
or
|
||||
// A search options object, which contains a filter and a baseDN.
|
||||
this = any(LdapJS::SearchOptions opt).getARhs()
|
||||
this = any(LdapJS::SearchOptions opt).asSink()
|
||||
or
|
||||
// A call to "parseDN", which parses a DN from a string.
|
||||
this = LdapJS::ldapjs().getMember("parseDN").getACall().getArgument(0)
|
||||
|
||||
@@ -681,7 +681,7 @@ module TaintedPath {
|
||||
.getMember(["pdf", "screenshot"])
|
||||
.getParameter(0)
|
||||
.getMember("path")
|
||||
.getARhs()
|
||||
.asSink()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -702,7 +702,7 @@ module TaintedPath {
|
||||
.getACall()
|
||||
.getParameter(1)
|
||||
.getMember("config")
|
||||
.getARhs()
|
||||
.asSink()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,7 +716,7 @@ module TaintedPath {
|
||||
.getMember(["readPackageAsync", "readPackageSync"])
|
||||
.getParameter(0)
|
||||
.getMember("cwd")
|
||||
.getARhs()
|
||||
.asSink()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -726,8 +726,8 @@ module TaintedPath {
|
||||
private class ShellCwdSink extends TaintedPath::Sink {
|
||||
ShellCwdSink() {
|
||||
exists(SystemCommandExecution sys, API::Node opts |
|
||||
opts.getARhs() = sys.getOptionsArg() and // assuming that an API::Node exists here.
|
||||
this = opts.getMember("cwd").getARhs()
|
||||
opts.asSink() = sys.getOptionsArg() and // assuming that an API::Node exists here.
|
||||
this = opts.getMember("cwd").asSink()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,4 +27,30 @@ class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
override predicate isBarrier(DataFlow::Node node) { node instanceof Barrier }
|
||||
|
||||
override predicate isBarrierGuard(DataFlow::BarrierGuardNode guard) {
|
||||
guard instanceof TypeOfTestBarrier or
|
||||
guard instanceof IsArrayBarrier
|
||||
}
|
||||
}
|
||||
|
||||
private class TypeOfTestBarrier extends DataFlow::BarrierGuardNode, DataFlow::ValueNode {
|
||||
override EqualityTest astNode;
|
||||
|
||||
TypeOfTestBarrier() { TaintTracking::isTypeofGuard(astNode, _, _) }
|
||||
|
||||
override predicate blocks(boolean outcome, Expr e) {
|
||||
if TaintTracking::isTypeofGuard(astNode, e, ["string", "object"])
|
||||
then outcome = [true, false] // separation between string/array removes type confusion in both branches
|
||||
else outcome = astNode.getPolarity() // block flow to branch where value is neither string nor array
|
||||
}
|
||||
}
|
||||
|
||||
private class IsArrayBarrier extends DataFlow::BarrierGuardNode, DataFlow::CallNode {
|
||||
IsArrayBarrier() { this = DataFlow::globalVarRef("Array").getAMemberCall("isArray").getACall() }
|
||||
|
||||
override predicate blocks(boolean outcome, Expr e) {
|
||||
e = getArgument(0).asExpr() and
|
||||
outcome = [true, false] // separation between string/array removes type confusion in both branches
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,8 +208,7 @@ module XssThroughDom {
|
||||
exists(API::Node useForm |
|
||||
useForm = API::moduleImport("react-hook-form").getMember("useForm").getReturn()
|
||||
|
|
||||
this =
|
||||
useForm.getMember("handleSubmit").getParameter(0).getParameter(0).getAnImmediateUse()
|
||||
this = useForm.getMember("handleSubmit").getParameter(0).getParameter(0).asSource()
|
||||
or
|
||||
this = useForm.getMember("getValues").getACall()
|
||||
)
|
||||
|
||||
@@ -103,7 +103,7 @@ module ZipSlip {
|
||||
class JSZipFilesSource extends Source instanceof DynamicPropertyAccess::EnumeratedPropName {
|
||||
JSZipFilesSource() {
|
||||
super.getSourceObject() =
|
||||
API::moduleImport("jszip").getInstance().getMember("files").getAnImmediateUse()
|
||||
API::moduleImport("jszip").getInstance().getMember("files").asSource()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ module ZipSlip {
|
||||
.getMember(["forEach", "filter"])
|
||||
.getParameter(0)
|
||||
.getParameter(0)
|
||||
.getAnImmediateUse()
|
||||
.asSource()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ predicate hasUnknownPropertyRead(LocalObject obj) {
|
||||
or
|
||||
exists(obj.getAPropertyRead("hasOwnProperty"))
|
||||
or
|
||||
obj.flowsTo(DataFlow::globalVarRef("Object").getAMemberCall("hasOwn").getArgument(0))
|
||||
or
|
||||
exists(obj.getAPropertyRead("propertyIsEnumerable"))
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
</p>
|
||||
|
||||
<sample language="javascript">
|
||||
^0\.\d+E?\d+$ // BAD
|
||||
/^0\.\d+E?\d+$/.test(str) // BAD
|
||||
</sample>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-020
|
||||
* external/cwe/cwe-940
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
@@ -45,7 +45,7 @@ where
|
||||
or
|
||||
// the same thing, but with API-nodes if they happen to be available
|
||||
exists(API::Node tlsInvk | tlsInvk.getAnInvocation() = tlsInvocation() |
|
||||
disable.getRhs() = tlsInvk.getAParameter().getMember("rejectUnauthorized").getARhs()
|
||||
disable.getRhs() = tlsInvk.getAParameter().getMember("rejectUnauthorized").asSink()
|
||||
)
|
||||
) and
|
||||
disable.getRhs().(AnalyzedNode).getTheBooleanValue() = false
|
||||
|
||||
@@ -143,7 +143,7 @@ API::CallNode passportAuthenticateCall() {
|
||||
*/
|
||||
API::CallNode nonSessionBasedAuthMiddleware() {
|
||||
result = passportAuthenticateCall() and
|
||||
result.getParameter(1).getMember("session").getARhs().mayHaveBooleanValue(false)
|
||||
result.getParameter(1).getMember("session").asSink().mayHaveBooleanValue(false)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -339,19 +339,16 @@ class AllowListEqualityGuard extends DataFlow::LabeledBarrierGuardNode, ValueNod
|
||||
* but the destination object generally doesn't. It is therefore only a sanitizer when
|
||||
* used on the destination object.
|
||||
*/
|
||||
class HasOwnPropertyGuard extends DataFlow::BarrierGuardNode, CallNode {
|
||||
class HasOwnPropertyGuard extends DataFlow::BarrierGuardNode instanceof HasOwnPropertyCall {
|
||||
HasOwnPropertyGuard() {
|
||||
// Make sure we handle reflective calls since libraries love to do that.
|
||||
getCalleeNode().getALocalSource().(DataFlow::PropRead).getPropertyName() = "hasOwnProperty" and
|
||||
exists(getReceiver()) and
|
||||
// Try to avoid `src.hasOwnProperty` by requiring that the receiver
|
||||
// does not locally have its properties enumerated. Typically there is no
|
||||
// reason to enumerate the properties of the destination object.
|
||||
not arePropertiesEnumerated(getReceiver().getALocalSource())
|
||||
not arePropertiesEnumerated(super.getObject().getALocalSource())
|
||||
}
|
||||
|
||||
override predicate blocks(boolean outcome, Expr e) {
|
||||
e = getArgument(0).asExpr() and outcome = true
|
||||
e = super.getProperty().asExpr() and outcome = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `js/resource-exhaustion` query no longer treats the 3-argument version of `Buffer.from` as a sink,
|
||||
since it does not allocate a new buffer.
|
||||
@@ -12,4 +12,4 @@
|
||||
import javascript
|
||||
import meta.MetaMetrics
|
||||
|
||||
select projectRoot(), count(any(API::Node nd).getARhs())
|
||||
select projectRoot(), count(any(API::Node nd).asSink())
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
import javascript
|
||||
import meta.MetaMetrics
|
||||
|
||||
select projectRoot(), count(any(API::Node nd).getAUse())
|
||||
select projectRoot(), count(any(API::Node nd).getAValueReachableFromSource())
|
||||
|
||||
@@ -21,10 +21,10 @@ import javascript
|
||||
|
||||
private DataFlow::Node getNode(API::Node nd, string kind) {
|
||||
kind = "def" and
|
||||
result = nd.getARhs()
|
||||
result = nd.asSink()
|
||||
or
|
||||
kind = "use" and
|
||||
result = nd.getAUse()
|
||||
result = nd.getAValueReachableFromSource()
|
||||
}
|
||||
|
||||
private string getLoc(DataFlow::Node nd) {
|
||||
|
||||
@@ -3,9 +3,9 @@ import javascript
|
||||
class FooCall extends API::CallNode {
|
||||
FooCall() { this = API::moduleImport("mylibrary").getMember("foo").getACall() }
|
||||
|
||||
DataFlow::Node getFirst() { result = getParameter(0).getMember("value").getARhs() }
|
||||
DataFlow::Node getFirst() { result = getParameter(0).getMember("value").asSink() }
|
||||
|
||||
DataFlow::Node getSecond() { result = getParameter(1).getMember("value").getARhs() }
|
||||
DataFlow::Node getSecond() { result = getParameter(1).getMember("value").asSink() }
|
||||
}
|
||||
|
||||
query predicate values(FooCall call, int first, int second) {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
class CustomEntryPoint extends API::EntryPoint {
|
||||
CustomEntryPoint() { this = "CustomEntryPoint" }
|
||||
|
||||
override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("CustomEntryPoint") }
|
||||
|
||||
override DataFlow::Node getARhs() { none() }
|
||||
override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("CustomEntryPoint") }
|
||||
}
|
||||
|
||||
import ApiGraphs.VerifyAssertions
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from string mod, string tp
|
||||
select mod, tp, API::Node::ofType(mod, tp).getAnImmediateUse()
|
||||
select mod, tp, API::Node::ofType(mod, tp).asSource()
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:74:8:74:29 | arr.fin ... llback) |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:77:8:77:35 | arrayFi ... llback) |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:81:10:81:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:84:8:84:17 | arr.at(-1) |
|
||||
| arrays.js:18:22:18:29 | "source" | arrays.js:18:50:18:50 | e |
|
||||
| arrays.js:22:15:22:22 | "source" | arrays.js:23:8:23:17 | arr2.pop() |
|
||||
| arrays.js:25:15:25:22 | "source" | arrays.js:26:8:26:17 | arr3.pop() |
|
||||
|
||||
@@ -80,4 +80,6 @@
|
||||
for (const x of uniq(arr)) {
|
||||
sink(x); // NOT OK
|
||||
}
|
||||
|
||||
sink(arr.at(-1)); // NOT OK
|
||||
});
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
nodes
|
||||
| arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | semmle.label | [ParExpr] (functi ... } }) |
|
||||
| arrays.js:1:1:83:3 | [ExprStmt] (functi ... } }); | semmle.label | [ExprStmt] (functi ... } }); |
|
||||
| arrays.js:1:1:83:3 | [ExprStmt] (functi ... } }); | semmle.order | 1 |
|
||||
| arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | semmle.label | [FunctionExpr] functio ... K } } |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | semmle.label | [BlockStmt] { let ... K } } |
|
||||
| arrays.js:1:1:85:2 | [ParExpr] (functi ... T OK }) | semmle.label | [ParExpr] (functi ... T OK }) |
|
||||
| arrays.js:1:1:85:3 | [ExprStmt] (functi ... OK }); | semmle.label | [ExprStmt] (functi ... OK }); |
|
||||
| arrays.js:1:1:85:3 | [ExprStmt] (functi ... OK }); | semmle.order | 1 |
|
||||
| arrays.js:1:2:85:1 | [FunctionExpr] functio ... OT OK } | semmle.label | [FunctionExpr] functio ... OT OK } |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | semmle.label | [BlockStmt] { let ... OT OK } |
|
||||
| arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | [DeclStmt] let source = ... |
|
||||
| arrays.js:2:7:2:12 | [VarDecl] source | semmle.label | [VarDecl] source |
|
||||
| arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.label | [VariableDeclarator] source = "source" |
|
||||
@@ -339,6 +339,17 @@ nodes
|
||||
| arrays.js:81:5:81:11 | [CallExpr] sink(x) | semmle.label | [CallExpr] sink(x) |
|
||||
| arrays.js:81:5:81:12 | [ExprStmt] sink(x); | semmle.label | [ExprStmt] sink(x); |
|
||||
| arrays.js:81:10:81:10 | [VarRef] x | semmle.label | [VarRef] x |
|
||||
| arrays.js:84:3:84:6 | [VarRef] sink | semmle.label | [VarRef] sink |
|
||||
| arrays.js:84:3:84:18 | [CallExpr] sink(arr.at(-1)) | semmle.label | [CallExpr] sink(arr.at(-1)) |
|
||||
| arrays.js:84:3:84:19 | [ExprStmt] sink(arr.at(-1)); | semmle.label | [ExprStmt] sink(arr.at(-1)); |
|
||||
| arrays.js:84:8:84:10 | [VarRef] arr | semmle.label | [VarRef] arr |
|
||||
| arrays.js:84:8:84:13 | [DotExpr] arr.at | semmle.label | [DotExpr] arr.at |
|
||||
| arrays.js:84:8:84:17 | [MethodCallExpr] arr.at(-1) | semmle.label | [MethodCallExpr] arr.at(-1) |
|
||||
| arrays.js:84:12:84:13 | [Label] at | semmle.label | [Label] at |
|
||||
| arrays.js:84:15:84:16 | [UnaryExpr] -1 | semmle.label | [UnaryExpr] -1 |
|
||||
| arrays.js:84:16:84:16 | [Literal] 1 | semmle.label | [Literal] 1 |
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
|
||||
@@ -386,88 +397,90 @@ nodes
|
||||
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
|
||||
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
|
||||
edges
|
||||
| arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | semmle.label | 1 |
|
||||
| arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | semmle.order | 1 |
|
||||
| arrays.js:1:1:83:3 | [ExprStmt] (functi ... } }); | arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | semmle.label | 1 |
|
||||
| arrays.js:1:1:83:3 | [ExprStmt] (functi ... } }); | arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | semmle.order | 1 |
|
||||
| arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | semmle.label | 5 |
|
||||
| arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | semmle.order | 5 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | 1 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.order | 1 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.label | 2 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.order | 2 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.label | 3 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.order | 3 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.label | 4 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.order | 4 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.label | 5 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.order | 5 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.label | 6 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.order | 6 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.label | 7 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.order | 7 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.label | 8 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.order | 8 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.label | 9 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.order | 9 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.label | 10 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.order | 10 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.label | 11 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.order | 11 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.label | 12 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.order | 12 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.label | 13 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.order | 13 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.label | 14 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.order | 14 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.label | 15 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.order | 15 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.label | 16 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.order | 16 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.label | 17 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.order | 17 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:32:3:32:29 | [DeclStmt] var arr5 = ... | semmle.label | 18 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:32:3:32:29 | [DeclStmt] var arr5 = ... | semmle.order | 18 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:33:3:33:19 | [ExprStmt] sink(arr5.pop()); | semmle.label | 19 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:33:3:33:19 | [ExprStmt] sink(arr5.pop()); | semmle.order | 19 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:35:3:35:28 | [ExprStmt] sink(ar ... pop()); | semmle.label | 20 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:35:3:35:28 | [ExprStmt] sink(ar ... pop()); | semmle.order | 20 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:37:3:37:16 | [DeclStmt] var arr6 = ... | semmle.label | 21 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:37:3:37:16 | [DeclStmt] var arr6 = ... | semmle.order | 21 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:38:3:40:3 | [ForStmt] for (va ... i]; } | semmle.label | 22 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:38:3:40:3 | [ForStmt] for (va ... i]; } | semmle.order | 22 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:41:3:41:19 | [ExprStmt] sink(arr6.pop()); | semmle.label | 23 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:41:3:41:19 | [ExprStmt] sink(arr6.pop()); | semmle.order | 23 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:44:3:47:5 | [ExprStmt] ["sourc ... . }); | semmle.label | 24 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:44:3:47:5 | [ExprStmt] ["sourc ... . }); | semmle.order | 24 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:49:3:49:15 | [ExprStmt] sink(arr[0]); | semmle.label | 25 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:49:3:49:15 | [ExprStmt] sink(arr[0]); | semmle.order | 25 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:51:3:53:3 | [ForOfStmt] for (co ... OK } | semmle.label | 26 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:51:3:53:3 | [ForOfStmt] for (co ... OK } | semmle.order | 26 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:55:3:57:3 | [ForOfStmt] for (co ... OK } | semmle.label | 27 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:55:3:57:3 | [ForOfStmt] for (co ... OK } | semmle.order | 27 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:59:3:61:3 | [ForOfStmt] for (co ... OK } | semmle.label | 28 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:59:3:61:3 | [ForOfStmt] for (co ... OK } | semmle.order | 28 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:63:3:63:16 | [DeclStmt] var arr7 = ... | semmle.label | 29 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:63:3:63:16 | [DeclStmt] var arr7 = ... | semmle.order | 29 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:64:3:64:20 | [ExprStmt] arr7.push(...arr); | semmle.label | 30 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:64:3:64:20 | [ExprStmt] arr7.push(...arr); | semmle.order | 30 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:65:3:67:3 | [ForOfStmt] for (co ... OK } | semmle.label | 31 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:65:3:67:3 | [ForOfStmt] for (co ... OK } | semmle.order | 31 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:69:3:69:42 | [DeclStmt] const arrayFrom = ... | semmle.label | 32 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:69:3:69:42 | [DeclStmt] const arrayFrom = ... | semmle.order | 32 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:70:3:72:3 | [ForOfStmt] for (co ... OK } | semmle.label | 33 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:70:3:72:3 | [ForOfStmt] for (co ... OK } | semmle.order | 33 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:74:3:74:31 | [ExprStmt] sink(ar ... back)); | semmle.label | 34 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:74:3:74:31 | [ExprStmt] sink(ar ... back)); | semmle.order | 34 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:76:3:76:42 | [DeclStmt] const arrayFind = ... | semmle.label | 35 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:76:3:76:42 | [DeclStmt] const arrayFind = ... | semmle.order | 35 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:77:3:77:37 | [ExprStmt] sink(ar ... back)); | semmle.label | 36 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:77:3:77:37 | [ExprStmt] sink(ar ... back)); | semmle.order | 36 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:79:3:79:31 | [DeclStmt] const uniq = ... | semmle.label | 37 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:79:3:79:31 | [DeclStmt] const uniq = ... | semmle.order | 37 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:80:3:82:3 | [ForOfStmt] for (co ... OK } | semmle.label | 38 |
|
||||
| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:80:3:82:3 | [ForOfStmt] for (co ... OK } | semmle.order | 38 |
|
||||
| arrays.js:1:1:85:2 | [ParExpr] (functi ... T OK }) | arrays.js:1:2:85:1 | [FunctionExpr] functio ... OT OK } | semmle.label | 1 |
|
||||
| arrays.js:1:1:85:2 | [ParExpr] (functi ... T OK }) | arrays.js:1:2:85:1 | [FunctionExpr] functio ... OT OK } | semmle.order | 1 |
|
||||
| arrays.js:1:1:85:3 | [ExprStmt] (functi ... OK }); | arrays.js:1:1:85:2 | [ParExpr] (functi ... T OK }) | semmle.label | 1 |
|
||||
| arrays.js:1:1:85:3 | [ExprStmt] (functi ... OK }); | arrays.js:1:1:85:2 | [ParExpr] (functi ... T OK }) | semmle.order | 1 |
|
||||
| arrays.js:1:2:85:1 | [FunctionExpr] functio ... OT OK } | arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | semmle.label | 5 |
|
||||
| arrays.js:1:2:85:1 | [FunctionExpr] functio ... OT OK } | arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | semmle.order | 5 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | 1 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.order | 1 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.label | 2 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.order | 2 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.label | 3 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.order | 3 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.label | 4 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.order | 4 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.label | 5 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.order | 5 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.label | 6 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.order | 6 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.label | 7 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.order | 7 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.label | 8 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.order | 8 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.label | 9 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.order | 9 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.label | 10 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.order | 10 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.label | 11 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.order | 11 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.label | 12 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.order | 12 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.label | 13 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.order | 13 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.label | 14 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.order | 14 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.label | 15 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.order | 15 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.label | 16 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.order | 16 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.label | 17 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.order | 17 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:32:3:32:29 | [DeclStmt] var arr5 = ... | semmle.label | 18 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:32:3:32:29 | [DeclStmt] var arr5 = ... | semmle.order | 18 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:33:3:33:19 | [ExprStmt] sink(arr5.pop()); | semmle.label | 19 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:33:3:33:19 | [ExprStmt] sink(arr5.pop()); | semmle.order | 19 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:35:3:35:28 | [ExprStmt] sink(ar ... pop()); | semmle.label | 20 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:35:3:35:28 | [ExprStmt] sink(ar ... pop()); | semmle.order | 20 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:37:3:37:16 | [DeclStmt] var arr6 = ... | semmle.label | 21 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:37:3:37:16 | [DeclStmt] var arr6 = ... | semmle.order | 21 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:38:3:40:3 | [ForStmt] for (va ... i]; } | semmle.label | 22 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:38:3:40:3 | [ForStmt] for (va ... i]; } | semmle.order | 22 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:41:3:41:19 | [ExprStmt] sink(arr6.pop()); | semmle.label | 23 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:41:3:41:19 | [ExprStmt] sink(arr6.pop()); | semmle.order | 23 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:44:3:47:5 | [ExprStmt] ["sourc ... . }); | semmle.label | 24 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:44:3:47:5 | [ExprStmt] ["sourc ... . }); | semmle.order | 24 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:49:3:49:15 | [ExprStmt] sink(arr[0]); | semmle.label | 25 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:49:3:49:15 | [ExprStmt] sink(arr[0]); | semmle.order | 25 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:51:3:53:3 | [ForOfStmt] for (co ... OK } | semmle.label | 26 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:51:3:53:3 | [ForOfStmt] for (co ... OK } | semmle.order | 26 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:55:3:57:3 | [ForOfStmt] for (co ... OK } | semmle.label | 27 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:55:3:57:3 | [ForOfStmt] for (co ... OK } | semmle.order | 27 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:59:3:61:3 | [ForOfStmt] for (co ... OK } | semmle.label | 28 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:59:3:61:3 | [ForOfStmt] for (co ... OK } | semmle.order | 28 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:63:3:63:16 | [DeclStmt] var arr7 = ... | semmle.label | 29 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:63:3:63:16 | [DeclStmt] var arr7 = ... | semmle.order | 29 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:64:3:64:20 | [ExprStmt] arr7.push(...arr); | semmle.label | 30 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:64:3:64:20 | [ExprStmt] arr7.push(...arr); | semmle.order | 30 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:65:3:67:3 | [ForOfStmt] for (co ... OK } | semmle.label | 31 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:65:3:67:3 | [ForOfStmt] for (co ... OK } | semmle.order | 31 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:69:3:69:42 | [DeclStmt] const arrayFrom = ... | semmle.label | 32 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:69:3:69:42 | [DeclStmt] const arrayFrom = ... | semmle.order | 32 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:70:3:72:3 | [ForOfStmt] for (co ... OK } | semmle.label | 33 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:70:3:72:3 | [ForOfStmt] for (co ... OK } | semmle.order | 33 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:74:3:74:31 | [ExprStmt] sink(ar ... back)); | semmle.label | 34 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:74:3:74:31 | [ExprStmt] sink(ar ... back)); | semmle.order | 34 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:76:3:76:42 | [DeclStmt] const arrayFind = ... | semmle.label | 35 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:76:3:76:42 | [DeclStmt] const arrayFind = ... | semmle.order | 35 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:77:3:77:37 | [ExprStmt] sink(ar ... back)); | semmle.label | 36 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:77:3:77:37 | [ExprStmt] sink(ar ... back)); | semmle.order | 36 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:79:3:79:31 | [DeclStmt] const uniq = ... | semmle.label | 37 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:79:3:79:31 | [DeclStmt] const uniq = ... | semmle.order | 37 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:80:3:82:3 | [ForOfStmt] for (co ... OK } | semmle.label | 38 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:80:3:82:3 | [ForOfStmt] for (co ... OK } | semmle.order | 38 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:84:3:84:19 | [ExprStmt] sink(arr.at(-1)); | semmle.label | 39 |
|
||||
| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:84:3:84:19 | [ExprStmt] sink(arr.at(-1)); | semmle.order | 39 |
|
||||
| arrays.js:2:3:2:24 | [DeclStmt] let source = ... | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.label | 1 |
|
||||
| arrays.js:2:3:2:24 | [DeclStmt] let source = ... | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.order | 1 |
|
||||
| arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | arrays.js:2:7:2:12 | [VarDecl] source | semmle.label | 1 |
|
||||
@@ -1052,6 +1065,22 @@ edges
|
||||
| arrays.js:81:5:81:11 | [CallExpr] sink(x) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
|
||||
| arrays.js:81:5:81:12 | [ExprStmt] sink(x); | arrays.js:81:5:81:11 | [CallExpr] sink(x) | semmle.label | 1 |
|
||||
| arrays.js:81:5:81:12 | [ExprStmt] sink(x); | arrays.js:81:5:81:11 | [CallExpr] sink(x) | semmle.order | 1 |
|
||||
| arrays.js:84:3:84:18 | [CallExpr] sink(arr.at(-1)) | arrays.js:84:3:84:6 | [VarRef] sink | semmle.label | 0 |
|
||||
| arrays.js:84:3:84:18 | [CallExpr] sink(arr.at(-1)) | arrays.js:84:3:84:6 | [VarRef] sink | semmle.order | 0 |
|
||||
| arrays.js:84:3:84:18 | [CallExpr] sink(arr.at(-1)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
|
||||
| arrays.js:84:3:84:18 | [CallExpr] sink(arr.at(-1)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
|
||||
| arrays.js:84:3:84:19 | [ExprStmt] sink(arr.at(-1)); | arrays.js:84:3:84:18 | [CallExpr] sink(arr.at(-1)) | semmle.label | 1 |
|
||||
| arrays.js:84:3:84:19 | [ExprStmt] sink(arr.at(-1)); | arrays.js:84:3:84:18 | [CallExpr] sink(arr.at(-1)) | semmle.order | 1 |
|
||||
| arrays.js:84:8:84:13 | [DotExpr] arr.at | arrays.js:84:8:84:10 | [VarRef] arr | semmle.label | 1 |
|
||||
| arrays.js:84:8:84:13 | [DotExpr] arr.at | arrays.js:84:8:84:10 | [VarRef] arr | semmle.order | 1 |
|
||||
| arrays.js:84:8:84:13 | [DotExpr] arr.at | arrays.js:84:12:84:13 | [Label] at | semmle.label | 2 |
|
||||
| arrays.js:84:8:84:13 | [DotExpr] arr.at | arrays.js:84:12:84:13 | [Label] at | semmle.order | 2 |
|
||||
| arrays.js:84:8:84:17 | [MethodCallExpr] arr.at(-1) | arrays.js:84:8:84:13 | [DotExpr] arr.at | semmle.label | 0 |
|
||||
| arrays.js:84:8:84:17 | [MethodCallExpr] arr.at(-1) | arrays.js:84:8:84:13 | [DotExpr] arr.at | semmle.order | 0 |
|
||||
| arrays.js:84:8:84:17 | [MethodCallExpr] arr.at(-1) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
|
||||
| arrays.js:84:8:84:17 | [MethodCallExpr] arr.at(-1) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
|
||||
| arrays.js:84:15:84:16 | [UnaryExpr] -1 | arrays.js:84:16:84:16 | [Literal] 1 | semmle.label | 1 |
|
||||
| arrays.js:84:15:84:16 | [UnaryExpr] -1 | arrays.js:84:16:84:16 | [Literal] 1 | semmle.order | 1 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:5:8:5:14 | [DotExpr] obj.foo | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:5:8:5:14 | [DotExpr] obj.foo | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:8:12:8:17 | [VarRef] source | semmle.label | 0 |
|
||||
@@ -1140,6 +1169,10 @@ edges
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:80:24:80:26 | [VarRef] arr | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:81:10:81:10 | [VarRef] x | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:81:10:81:10 | [VarRef] x | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:84:8:84:17 | [MethodCallExpr] arr.at(-1) | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:84:8:84:17 | [MethodCallExpr] arr.at(-1) | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:84:15:84:16 | [UnaryExpr] -1 | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Arguments) | arrays.js:84:15:84:16 | [UnaryExpr] -1 | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Parameters) | arrays.js:15:16:15:16 | [SimpleParameter] e | semmle.label | 0 |
|
||||
| file://:0:0:0:0 | (Parameters) | arrays.js:15:16:15:16 | [SimpleParameter] e | semmle.order | 0 |
|
||||
| file://:0:0:0:0 | (Parameters) | arrays.js:16:12:16:12 | [SimpleParameter] e | semmle.label | 0 |
|
||||
|
||||
@@ -9,12 +9,12 @@ class Taint extends TaintTracking::Configuration {
|
||||
override predicate isSource(DataFlow::Node node) {
|
||||
node.(DataFlow::CallNode).getCalleeName() = "source"
|
||||
or
|
||||
node = testInstance().getMember("getSource").getReturn().getAnImmediateUse()
|
||||
node = testInstance().getMember("getSource").getReturn().asSource()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node node) {
|
||||
node = any(DataFlow::CallNode call | call.getCalleeName() = "sink").getAnArgument()
|
||||
or
|
||||
node = testInstance().getMember("getSink").getAParameter().getARhs()
|
||||
node = testInstance().getMember("getSink").getAParameter().asSink()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,10 @@ isLabeledBarrier
|
||||
| ExampleConfiguration | tst.js:361:14:361:14 | v | taint |
|
||||
| ExampleConfiguration | tst.js:371:14:371:16 | o.p | taint |
|
||||
| ExampleConfiguration | tst.js:378:14:378:17 | o[p] | taint |
|
||||
| ExampleConfiguration | tst.js:392:14:392:14 | v | taint |
|
||||
| ExampleConfiguration | tst.js:394:14:394:16 | v.p | taint |
|
||||
| ExampleConfiguration | tst.js:396:14:396:18 | v.p.q | taint |
|
||||
| ExampleConfiguration | tst.js:402:14:402:14 | v | taint |
|
||||
isSanitizer
|
||||
| ExampleConfiguration | tst.js:176:18:176:18 | v |
|
||||
sanitizingGuard
|
||||
@@ -122,6 +126,12 @@ sanitizingGuard
|
||||
| tst.js:370:9:370:29 | o.p == ... listed" | tst.js:370:16:370:29 | "white-listed" | true |
|
||||
| tst.js:377:11:377:32 | o[p] == ... listed" | tst.js:377:11:377:14 | o[p] | true |
|
||||
| tst.js:377:11:377:32 | o[p] == ... listed" | tst.js:377:19:377:32 | "white-listed" | true |
|
||||
| tst.js:391:9:391:27 | o.hasOwnProperty(v) | tst.js:391:26:391:26 | v | true |
|
||||
| tst.js:393:16:393:36 | o.hasOw ... ty(v.p) | tst.js:393:33:393:35 | v.p | true |
|
||||
| tst.js:395:16:395:38 | o.hasOw ... (v.p.q) | tst.js:395:33:395:37 | v.p.q | true |
|
||||
| tst.js:397:16:397:36 | o.hasOw ... ty(v.p) | tst.js:397:33:397:35 | v.p | true |
|
||||
| tst.js:399:16:399:41 | o.hasOw ... "p.q"]) | tst.js:399:33:399:40 | v["p.q"] | true |
|
||||
| tst.js:401:16:401:34 | Object.hasOwn(o, v) | tst.js:401:33:401:33 | v | true |
|
||||
taintedSink
|
||||
| tst.js:2:13:2:20 | SOURCE() | tst.js:3:10:3:10 | v |
|
||||
| tst.js:2:13:2:20 | SOURCE() | tst.js:8:14:8:14 | v |
|
||||
@@ -186,3 +196,6 @@ taintedSink
|
||||
| tst.js:367:13:367:20 | SOURCE() | tst.js:373:14:373:16 | o.p |
|
||||
| tst.js:367:13:367:20 | SOURCE() | tst.js:380:14:380:17 | o[p] |
|
||||
| tst.js:367:13:367:20 | SOURCE() | tst.js:382:14:382:17 | o[p] |
|
||||
| tst.js:388:13:388:20 | SOURCE() | tst.js:389:10:389:14 | v.p.q |
|
||||
| tst.js:388:13:388:20 | SOURCE() | tst.js:398:14:398:14 | v |
|
||||
| tst.js:388:13:388:20 | SOURCE() | tst.js:400:14:400:18 | v.p.q |
|
||||
|
||||
@@ -383,3 +383,22 @@ function constantComparisonSanitizer2() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function propertySanitization(o) {
|
||||
var v = SOURCE();
|
||||
SINK(v.p.q); // NOT OK
|
||||
|
||||
if (o.hasOwnProperty(v)) {
|
||||
SINK(v); // OK
|
||||
} else if (o.hasOwnProperty(v.p)) {
|
||||
SINK(v.p); // OK
|
||||
} else if (o.hasOwnProperty(v.p.q)) {
|
||||
SINK(v.p.q); // OK
|
||||
} else if (o.hasOwnProperty(v.p)) {
|
||||
SINK(v); // NOT OK
|
||||
} else if (o.hasOwnProperty(v["p.q"])) {
|
||||
SINK(v.p.q); // NOT OK
|
||||
} else if (Object.hasOwn(o, v)) {
|
||||
SINK(v); // OK
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ typeInferenceMismatch
|
||||
| arrays.js:2:15:2:22 | source() | arrays.js:11:10:11:28 | union(["bla"], foo) |
|
||||
| arrays.js:2:15:2:22 | source() | arrays.js:14:10:14:18 | flat(foo) |
|
||||
| arrays.js:2:15:2:22 | source() | arrays.js:19:10:19:12 | res |
|
||||
| arrays.js:2:15:2:22 | source() | arrays.js:21:10:21:19 | foo.at(-1) |
|
||||
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:4:8:4:8 | x |
|
||||
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:13:10:13:10 | x |
|
||||
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:19:10:19:10 | x |
|
||||
|
||||
@@ -17,4 +17,6 @@ function test() {
|
||||
return prev + '<b>' + current + '</b>';
|
||||
}, '');
|
||||
sink(res); // NOT OK
|
||||
|
||||
sink(foo.at(-1)); // NOT OK
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -386,6 +386,148 @@ getExprType
|
||||
| tst.ts:293:7:293:21 | payload.toFixed | (fractionDigits?: number) => string |
|
||||
| tst.ts:293:7:293:23 | payload.toFixed() | string |
|
||||
| tst.ts:293:15:293:21 | toFixed | (fractionDigits?: number) => string |
|
||||
| tst.ts:298:7:298:9 | key | typeof key |
|
||||
| tst.ts:298:13:298:18 | Symbol | SymbolConstructor |
|
||||
| tst.ts:298:13:298:20 | Symbol() | typeof key |
|
||||
| tst.ts:300:7:300:20 | numberOrString | "hello" \| 42 |
|
||||
| tst.ts:300:24:300:27 | Math | Math |
|
||||
| tst.ts:300:24:300:34 | Math.random | () => number |
|
||||
| tst.ts:300:24:300:36 | Math.random() | number |
|
||||
| tst.ts:300:24:300:42 | Math.random() < 0.5 | boolean |
|
||||
| tst.ts:300:24:300:57 | Math.ra ... "hello" | "hello" \| 42 |
|
||||
| tst.ts:300:29:300:34 | random | () => number |
|
||||
| tst.ts:300:40:300:42 | 0.5 | 0.5 |
|
||||
| tst.ts:300:46:300:47 | 42 | 42 |
|
||||
| tst.ts:300:51:300:57 | "hello" | "hello" |
|
||||
| tst.ts:302:5:302:7 | obj | { [key]: string \| number; } |
|
||||
| tst.ts:302:11:304:1 | {\\n [ke ... ring,\\n} | { [key]: string \| number; } |
|
||||
| tst.ts:303:4:303:6 | key | typeof key |
|
||||
| tst.ts:303:10:303:23 | numberOrString | "hello" \| 42 |
|
||||
| tst.ts:306:5:306:19 | typeof obj[key] | "string" \| "number" \| "bigint" \| "boolean" \| "s... |
|
||||
| tst.ts:306:5:306:32 | typeof ... string" | boolean |
|
||||
| tst.ts:306:12:306:14 | obj | { [key]: string \| number; } |
|
||||
| tst.ts:306:12:306:19 | obj[key] | string \| number |
|
||||
| tst.ts:306:16:306:18 | key | typeof key |
|
||||
| tst.ts:306:25:306:32 | "string" | "string" |
|
||||
| tst.ts:307:7:307:9 | str | string |
|
||||
| tst.ts:307:13:307:15 | obj | { [key]: string \| number; } |
|
||||
| tst.ts:307:13:307:20 | obj[key] | string |
|
||||
| tst.ts:307:17:307:19 | key | typeof key |
|
||||
| tst.ts:308:3:308:5 | str | string |
|
||||
| tst.ts:308:3:308:17 | str.toUpperCase | () => string |
|
||||
| tst.ts:308:3:308:19 | str.toUpperCase() | string |
|
||||
| tst.ts:308:7:308:17 | toUpperCase | () => string |
|
||||
| tst.ts:313:10:313:10 | f | <T>(arg: { produce: (n: string) => T; consume: ... |
|
||||
| tst.ts:313:15:313:17 | arg | { produce: (n: string) => T; consume: (x: T) =>... |
|
||||
| tst.ts:314:3:314:9 | produce | (n: string) => T |
|
||||
| tst.ts:314:12:314:27 | (n: string) => T | (n: string) => T |
|
||||
| tst.ts:314:13:314:13 | n | string |
|
||||
| tst.ts:315:3:315:9 | consume | (x: T) => void |
|
||||
| tst.ts:315:12:315:25 | (x: T) => void | (x: T) => void |
|
||||
| tst.ts:315:13:315:13 | x | T |
|
||||
| tst.ts:318:1:318:1 | f | <T>(arg: { produce: (n: string) => T; consume: ... |
|
||||
| tst.ts:318:1:321:2 | f({\\n p ... se()\\n}) | void |
|
||||
| tst.ts:318:3:321:1 | {\\n pro ... ase()\\n} | { produce: (n: string) => string; consume: (x: ... |
|
||||
| tst.ts:319:3:319:9 | produce | (n: string) => string |
|
||||
| tst.ts:319:12:319:12 | n | string |
|
||||
| tst.ts:319:12:319:17 | n => n | (n: string) => string |
|
||||
| tst.ts:319:17:319:17 | n | string |
|
||||
| tst.ts:320:3:320:9 | consume | (x: string) => string |
|
||||
| tst.ts:320:12:320:12 | x | string |
|
||||
| tst.ts:320:12:320:31 | x => x.toLowerCase() | (x: string) => string |
|
||||
| tst.ts:320:17:320:17 | x | string |
|
||||
| tst.ts:320:17:320:29 | x.toLowerCase | () => string |
|
||||
| tst.ts:320:17:320:31 | x.toLowerCase() | string |
|
||||
| tst.ts:320:19:320:29 | toLowerCase | () => string |
|
||||
| tst.ts:325:7:325:14 | ErrorMap | { new (entries?: readonly (readonly [string, Er... |
|
||||
| tst.ts:325:18:325:20 | Map | MapConstructor |
|
||||
| tst.ts:325:18:325:35 | Map<string, Error> | any |
|
||||
| tst.ts:327:7:327:14 | errorMap | Map<string, Error> |
|
||||
| tst.ts:327:18:327:31 | new ErrorMap() | Map<string, Error> |
|
||||
| tst.ts:327:22:327:29 | ErrorMap | { new (entries?: readonly (readonly [string, Er... |
|
||||
| tst.ts:338:7:338:7 | a | "a" \| "b" |
|
||||
| tst.ts:338:14:338:16 | 'a' | "a" |
|
||||
| tst.ts:343:3:343:5 | get | () => T |
|
||||
| tst.ts:343:8:343:14 | () => T | () => T |
|
||||
| tst.ts:344:3:344:5 | set | (value: T) => void |
|
||||
| tst.ts:344:8:344:25 | (value: T) => void | (value: T) => void |
|
||||
| tst.ts:344:9:344:13 | value | T |
|
||||
| tst.ts:347:7:347:11 | state | State<number> |
|
||||
| tst.ts:347:30:350:1 | {\\n get ... > { }\\n} | State<number> |
|
||||
| tst.ts:348:3:348:5 | get | () => number |
|
||||
| tst.ts:348:8:348:15 | () => 42 | () => number |
|
||||
| tst.ts:348:14:348:15 | 42 | 42 |
|
||||
| tst.ts:349:3:349:5 | set | (value: number) => void |
|
||||
| tst.ts:349:8:349:21 | (value) => { } | (value: number) => void |
|
||||
| tst.ts:349:9:349:13 | value | number |
|
||||
| tst.ts:352:7:352:14 | fortyTwo | number |
|
||||
| tst.ts:352:18:352:22 | state | State<number> |
|
||||
| tst.ts:352:18:352:26 | state.get | () => number |
|
||||
| tst.ts:352:18:352:28 | state.get() | number |
|
||||
| tst.ts:352:24:352:26 | get | () => number |
|
||||
| tst.ts:356:8:356:18 | tstModuleES | () => "a" \| "b" |
|
||||
| tst.ts:356:25:356:43 | './tstModuleES.mjs' | any |
|
||||
| tst.ts:358:1:358:7 | console | Console |
|
||||
| tst.ts:358:1:358:11 | console.log | (...data: any[]) => void |
|
||||
| tst.ts:358:1:358:26 | console ... leES()) | void |
|
||||
| tst.ts:358:9:358:11 | log | (...data: any[]) => void |
|
||||
| tst.ts:358:13:358:23 | tstModuleES | () => "a" \| "b" |
|
||||
| tst.ts:358:13:358:25 | tstModuleES() | "a" \| "b" |
|
||||
| tst.ts:360:10:360:21 | tstModuleCJS | () => "a" \| "b" |
|
||||
| tst.ts:360:10:360:21 | tstModuleCJS | () => "a" \| "b" |
|
||||
| tst.ts:360:30:360:49 | './tstModuleCJS.cjs' | any |
|
||||
| tst.ts:362:1:362:7 | console | Console |
|
||||
| tst.ts:362:1:362:11 | console.log | (...data: any[]) => void |
|
||||
| tst.ts:362:1:362:27 | console ... eCJS()) | void |
|
||||
| tst.ts:362:9:362:11 | log | (...data: any[]) => void |
|
||||
| tst.ts:362:13:362:24 | tstModuleCJS | () => "a" \| "b" |
|
||||
| tst.ts:362:13:362:26 | tstModuleCJS() | "a" \| "b" |
|
||||
| tst.ts:368:13:368:13 | A | typeof library-tests/TypeScript/Types/tstSuffixA.ts |
|
||||
| tst.ts:368:20:368:33 | './tstSuffixA' | any |
|
||||
| tst.ts:370:1:370:7 | console | Console |
|
||||
| tst.ts:370:1:370:11 | console.log | (...data: any[]) => void |
|
||||
| tst.ts:370:1:370:29 | console ... File()) | void |
|
||||
| tst.ts:370:9:370:11 | log | (...data: any[]) => void |
|
||||
| tst.ts:370:13:370:13 | A | typeof library-tests/TypeScript/Types/tstSuffixA.ts |
|
||||
| tst.ts:370:13:370:26 | A.resolvedFile | () => "tstSuffixA.ts" |
|
||||
| tst.ts:370:13:370:28 | A.resolvedFile() | "tstSuffixA.ts" |
|
||||
| tst.ts:370:15:370:26 | resolvedFile | () => "tstSuffixA.ts" |
|
||||
| tst.ts:372:13:372:13 | B | typeof library-tests/TypeScript/Types/tstSuffixB.ios.ts |
|
||||
| tst.ts:372:20:372:33 | './tstSuffixB' | any |
|
||||
| tst.ts:374:1:374:7 | console | Console |
|
||||
| tst.ts:374:1:374:11 | console.log | (...data: any[]) => void |
|
||||
| tst.ts:374:1:374:29 | console ... File()) | void |
|
||||
| tst.ts:374:9:374:11 | log | (...data: any[]) => void |
|
||||
| tst.ts:374:13:374:13 | B | typeof library-tests/TypeScript/Types/tstSuffixB.ios.ts |
|
||||
| tst.ts:374:13:374:26 | B.resolvedFile | () => "tstSuffixB.ios.ts" |
|
||||
| tst.ts:374:13:374:28 | B.resolvedFile() | "tstSuffixB.ios.ts" |
|
||||
| tst.ts:374:15:374:26 | resolvedFile | () => "tstSuffixB.ios.ts" |
|
||||
| tstModuleCJS.cts:1:17:1:28 | tstModuleCJS | () => "a" \| "b" |
|
||||
| tstModuleCJS.cts:2:12:2:15 | Math | Math |
|
||||
| tstModuleCJS.cts:2:12:2:22 | Math.random | () => number |
|
||||
| tstModuleCJS.cts:2:12:2:24 | Math.random() | number |
|
||||
| tstModuleCJS.cts:2:12:2:30 | Math.random() > 0.5 | boolean |
|
||||
| tstModuleCJS.cts:2:12:2:42 | Math.ra ... ' : 'b' | "a" \| "b" |
|
||||
| tstModuleCJS.cts:2:17:2:22 | random | () => number |
|
||||
| tstModuleCJS.cts:2:28:2:30 | 0.5 | 0.5 |
|
||||
| tstModuleCJS.cts:2:34:2:36 | 'a' | "a" |
|
||||
| tstModuleCJS.cts:2:40:2:42 | 'b' | "b" |
|
||||
| tstModuleES.mts:1:25:1:35 | tstModuleES | () => "a" \| "b" |
|
||||
| tstModuleES.mts:2:12:2:15 | Math | Math |
|
||||
| tstModuleES.mts:2:12:2:22 | Math.random | () => number |
|
||||
| tstModuleES.mts:2:12:2:24 | Math.random() | number |
|
||||
| tstModuleES.mts:2:12:2:30 | Math.random() > 0.5 | boolean |
|
||||
| tstModuleES.mts:2:12:2:42 | Math.ra ... ' : 'b' | "a" \| "b" |
|
||||
| tstModuleES.mts:2:17:2:22 | random | () => number |
|
||||
| tstModuleES.mts:2:28:2:30 | 0.5 | 0.5 |
|
||||
| tstModuleES.mts:2:34:2:36 | 'a' | "a" |
|
||||
| tstModuleES.mts:2:40:2:42 | 'b' | "b" |
|
||||
| tstSuffixA.ts:1:17:1:28 | resolvedFile | () => "tstSuffixA.ts" |
|
||||
| tstSuffixA.ts:2:12:2:26 | 'tstSuffixA.ts' | "tstSuffixA.ts" |
|
||||
| tstSuffixB.ios.ts:1:17:1:28 | resolvedFile | () => "tstSuffixB.ios.ts" |
|
||||
| tstSuffixB.ios.ts:2:12:2:30 | 'tstSuffixB.ios.ts' | "tstSuffixB.ios.ts" |
|
||||
| tstSuffixB.ts:1:17:1:28 | resolvedFile | () => "tstSuffixB.ts" |
|
||||
| tstSuffixB.ts:2:12:2:26 | 'tstSuffixB.ts' | "tstSuffixB.ts" |
|
||||
| type_alias.ts:3:5:3:5 | b | boolean |
|
||||
| type_alias.ts:7:5:7:5 | c | ValueOrArray<number> |
|
||||
| type_alias.ts:14:9:14:32 | [proper ... ]: Json | any |
|
||||
@@ -461,6 +603,9 @@ getTypeDefinitionType
|
||||
| tst.ts:265:3:269:3 | interfa ... an;\\n } | TypeMap |
|
||||
| tst.ts:271:3:276:7 | type Un ... }[P]; | UnionRecord<P> |
|
||||
| tst.ts:289:3:289:63 | type Fu ... > void; | Func |
|
||||
| tst.ts:331:1:334:14 | type Fi ... never; | FirstString<T> |
|
||||
| tst.ts:336:1:336:51 | type F ... lean]>; | "a" \| "b" |
|
||||
| tst.ts:342:1:345:1 | interfa ... void;\\n} | State<T> |
|
||||
| type_alias.ts:1:1:1:17 | type B = boolean; | boolean |
|
||||
| type_alias.ts:5:1:5:50 | type Va ... ay<T>>; | ValueOrArray<T> |
|
||||
| type_alias.ts:9:1:15:13 | type Js ... Json[]; | Json |
|
||||
@@ -703,6 +848,48 @@ getTypeExprType
|
||||
| tst.ts:289:47:289:52 | string | string |
|
||||
| tst.ts:289:59:289:62 | void | void |
|
||||
| tst.ts:291:13:291:16 | Func | Func |
|
||||
| tst.ts:313:12:313:12 | T | T |
|
||||
| tst.ts:313:20:315:27 | {\\n pro ... void } | { produce: (n: string) => T; consume: (x: T) =>... |
|
||||
| tst.ts:314:12:314:27 | (n: string) => T | (n: string) => T |
|
||||
| tst.ts:314:16:314:21 | string | string |
|
||||
| tst.ts:314:27:314:27 | T | T |
|
||||
| tst.ts:315:12:315:25 | (x: T) => void | (x: T) => void |
|
||||
| tst.ts:315:16:315:16 | T | T |
|
||||
| tst.ts:315:22:315:25 | void | void |
|
||||
| tst.ts:316:4:316:7 | void | void |
|
||||
| tst.ts:325:22:325:27 | string | string |
|
||||
| tst.ts:325:30:325:34 | Error | Error |
|
||||
| tst.ts:331:6:331:16 | FirstString | FirstString<T> |
|
||||
| tst.ts:331:18:331:18 | T | T |
|
||||
| tst.ts:336:6:336:6 | F | "a" \| "b" |
|
||||
| tst.ts:336:10:336:20 | FirstString | FirstString<T> |
|
||||
| tst.ts:336:10:336:50 | FirstSt ... olean]> | "a" \| "b" |
|
||||
| tst.ts:336:22:336:49 | ['a' \| ... oolean] | ["a" \| "b", number, boolean] |
|
||||
| tst.ts:336:23:336:25 | 'a' | "a" |
|
||||
| tst.ts:336:23:336:31 | 'a' \| 'b' | "a" \| "b" |
|
||||
| tst.ts:336:29:336:31 | 'b' | "b" |
|
||||
| tst.ts:336:34:336:39 | number | number |
|
||||
| tst.ts:336:42:336:48 | boolean | boolean |
|
||||
| tst.ts:338:10:338:10 | F | "a" \| "b" |
|
||||
| tst.ts:342:11:342:15 | State | State<T> |
|
||||
| tst.ts:342:24:342:24 | T | T |
|
||||
| tst.ts:343:8:343:14 | () => T | () => T |
|
||||
| tst.ts:343:14:343:14 | T | T |
|
||||
| tst.ts:344:8:344:25 | (value: T) => void | (value: T) => void |
|
||||
| tst.ts:344:16:344:16 | T | T |
|
||||
| tst.ts:344:22:344:25 | void | void |
|
||||
| tst.ts:347:14:347:18 | State | State<T> |
|
||||
| tst.ts:347:14:347:26 | State<number> | State<number> |
|
||||
| tst.ts:347:20:347:25 | number | number |
|
||||
| tstModuleCJS.cts:1:33:1:35 | 'a' | "a" |
|
||||
| tstModuleCJS.cts:1:33:1:41 | 'a' \| 'b' | "a" \| "b" |
|
||||
| tstModuleCJS.cts:1:39:1:41 | 'b' | "b" |
|
||||
| tstModuleES.mts:1:40:1:42 | 'a' | "a" |
|
||||
| tstModuleES.mts:1:40:1:48 | 'a' \| 'b' | "a" \| "b" |
|
||||
| tstModuleES.mts:1:46:1:48 | 'b' | "b" |
|
||||
| tstSuffixA.ts:1:33:1:47 | 'tstSuffixA.ts' | "tstSuffixA.ts" |
|
||||
| tstSuffixB.ios.ts:1:33:1:51 | 'tstSuffixB.ios.ts' | "tstSuffixB.ios.ts" |
|
||||
| tstSuffixB.ts:1:33:1:47 | 'tstSuffixB.ts' | "tstSuffixB.ts" |
|
||||
| type_alias.ts:1:6:1:6 | B | boolean |
|
||||
| type_alias.ts:1:10:1:16 | boolean | boolean |
|
||||
| type_alias.ts:3:8:3:8 | B | boolean |
|
||||
@@ -783,6 +970,7 @@ referenceDefinition
|
||||
| E | type_definition_objects.ts:6:8:6:16 | enum E {} |
|
||||
| EnumWithOneMember | type_definitions.ts:18:26:18:31 | member |
|
||||
| Error | tst.ts:210:10:213:3 | interfa ... ng;\\n } |
|
||||
| FirstString<T> | tst.ts:331:1:334:14 | type Fi ... never; |
|
||||
| Foo | tst.ts:116:3:129:3 | class F ... }\\n } |
|
||||
| Foo | tst.ts:165:5:167:5 | interfa ... ;\\n } |
|
||||
| Foo | tst.ts:179:3:192:3 | class F ... \\n } |
|
||||
@@ -796,6 +984,8 @@ referenceDefinition
|
||||
| NonAbstractDummy | tst.ts:54:1:56:1 | interfa ... mber;\\n} |
|
||||
| Person | tst.ts:222:3:234:3 | class P ... }\\n } |
|
||||
| Shape | tst.ts:140:3:142:47 | type Sh ... mber }; |
|
||||
| State<T> | tst.ts:342:1:345:1 | interfa ... void;\\n} |
|
||||
| State<number> | tst.ts:342:1:345:1 | interfa ... void;\\n} |
|
||||
| Sub | tst.ts:97:3:101:3 | class S ... }\\n } |
|
||||
| Success | tst.ts:205:10:208:3 | interfa ... ng;\\n } |
|
||||
| Super | tst.ts:91:3:95:3 | class S ... }\\n } |
|
||||
@@ -852,16 +1042,20 @@ abstractSignature
|
||||
unionIndex
|
||||
| 1 | 0 | 1 \| 2 |
|
||||
| 2 | 1 | 1 \| 2 |
|
||||
| 42 | 1 | "hello" \| 42 |
|
||||
| "NumberContents" | 0 | "NumberContents" \| "StringContents" |
|
||||
| "StringContents" | 1 | "NumberContents" \| "StringContents" |
|
||||
| "a" | 0 | "a" \| "b" |
|
||||
| "a" | 1 | number \| "a" |
|
||||
| "a" | 3 | number \| boolean \| "a" \| "b" |
|
||||
| "b" | 1 | "a" \| "b" |
|
||||
| "b" | 4 | number \| boolean \| "a" \| "b" |
|
||||
| "bigint" | 2 | "string" \| "number" \| "bigint" \| "boolean" \| "s... |
|
||||
| "boolean" | 2 | keyof TypeMap |
|
||||
| "boolean" | 3 | "string" \| "number" \| "bigint" \| "boolean" \| "s... |
|
||||
| "circle" | 0 | "circle" \| "square" |
|
||||
| "function" | 7 | "string" \| "number" \| "bigint" \| "boolean" \| "s... |
|
||||
| "hello" | 0 | "hello" \| 42 |
|
||||
| "number" | 1 | "string" \| "number" \| "bigint" \| "boolean" \| "s... |
|
||||
| "number" | 1 | keyof TypeMap |
|
||||
| "object" | 6 | "string" \| "number" \| "bigint" \| "boolean" \| "s... |
|
||||
@@ -871,6 +1065,7 @@ unionIndex
|
||||
| "symbol" | 4 | "string" \| "number" \| "bigint" \| "boolean" \| "s... |
|
||||
| "undefined" | 5 | "string" \| "number" \| "bigint" \| "boolean" \| "s... |
|
||||
| Error | 1 | Success \| Error |
|
||||
| Error | 1 | string \| Error |
|
||||
| Json[] | 5 | string \| number \| boolean \| { [property: string... |
|
||||
| Promise<number> | 2 | boolean \| Promise<number> |
|
||||
| PromiseLike<TResult1> | 1 | TResult1 \| PromiseLike<TResult1> |
|
||||
@@ -890,16 +1085,19 @@ unionIndex
|
||||
| false | 0 | boolean |
|
||||
| false | 0 | boolean \| Promise<number> |
|
||||
| false | 1 | number \| boolean |
|
||||
| false | 1 | number \| boolean \| "a" \| "b" |
|
||||
| false | 2 | string \| number \| boolean |
|
||||
| false | 2 | string \| number \| boolean \| { [property: string... |
|
||||
| number | 0 | number \| "a" |
|
||||
| number | 0 | number \| ValueOrArray<number>[] |
|
||||
| number | 0 | number \| boolean |
|
||||
| number | 0 | number \| boolean \| "a" \| "b" |
|
||||
| number | 1 | string \| number |
|
||||
| number | 1 | string \| number \| boolean |
|
||||
| number | 1 | string \| number \| boolean \| { [property: string... |
|
||||
| number | 1 | string \| number \| true |
|
||||
| string | 0 | VirtualNode \| { [key: string]: any; } |
|
||||
| string | 0 | string \| Error |
|
||||
| string | 0 | string \| [string, { [key: string]: any; }, ...V... |
|
||||
| string | 0 | string \| number |
|
||||
| string | 0 | string \| number \| boolean |
|
||||
@@ -911,6 +1109,7 @@ unionIndex
|
||||
| true | 1 | boolean |
|
||||
| true | 1 | boolean \| Promise<number> |
|
||||
| true | 2 | number \| boolean |
|
||||
| true | 2 | number \| boolean \| "a" \| "b" |
|
||||
| true | 2 | string \| number \| true |
|
||||
| true | 3 | string \| number \| boolean |
|
||||
| true | 3 | string \| number \| boolean \| { [property: string... |
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"lib": ["dom", "esnext"],
|
||||
"resolveJsonModule": true
|
||||
"resolveJsonModule": true,
|
||||
"moduleSuffixes": [".ios", ""]
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user