Merge remote-tracking branch 'upstream/master' into mergeback-2018-10-17

This commit is contained in:
Tom Hvitved
2018-10-17 13:24:37 +02:00
753 changed files with 30532 additions and 25013 deletions

View File

@@ -3,7 +3,7 @@
* @description Conditions that the user controls are not suited for making security-related decisions.
* @kind problem
* @problem.severity error
* @precision high
* @precision medium
* @id js/user-controlled-bypass
* @tags security
* external/cwe/cwe-807
@@ -83,8 +83,32 @@ predicate isTaintedGuardForSensitiveAction(Sink sink, DataFlow::Node source, Sen
)
}
/**
* Holds if `e` effectively guards access to `action` by returning or throwing early.
*
* Example: `if (e) return; action(x)`.
*/
predicate isEarlyAbortGuard(Sink e, SensitiveAction action) {
exists (IfStmt guard |
// `e` is in the condition of an if-statement ...
e.asExpr().getParentExpr*() = guard.getCondition() and
// ... where the then-branch always throws or returns
exists (Stmt abort |
abort instanceof ThrowStmt or
abort instanceof ReturnStmt |
abort.nestedIn(guard) and
abort.getBasicBlock().(ReachableBasicBlock).postDominates(guard.getThen().getBasicBlock() )
) and
// ... and the else-branch does not exist
not exists (guard.getElse()) |
// ... and `action` is outside the if-statement
not action.asExpr().getEnclosingStmt().nestedIn(guard)
)
}
from DataFlow::Node source, DataFlow::Node sink, SensitiveAction action
where isTaintedGuardForSensitiveAction(sink, source, action)
where isTaintedGuardForSensitiveAction(sink, source, action) and
not isEarlyAbortGuard(sink, action)
select sink, "This condition guards a sensitive $@, but $@ controls it.",
action, "action",
source, "a user-provided value"

View File

@@ -96,8 +96,7 @@ class AbstractProtoProperty extends AbstractProperty {
* which in turn introduces a materialization.
*/
private AbstractValue getAnAssignedValue(AbstractValue b, string p) {
exists (AnalyzedPropertyWrite apw, DataFlow::AnalyzedNode afn |
apw.writes(b, p, afn) and
result = afn.getALocalValue()
exists (AnalyzedPropertyWrite apw |
apw.writesValue(b, p, result)
)
}

View File

@@ -359,11 +359,11 @@ abstract class AdditionalSink extends DataFlow::Node {
*
* This contributes additional argument-passing flow edges that should be added to all data flow configurations.
*/
cached abstract class AdditionalPartialInvokeNode extends DataFlow::InvokeNode {
abstract class AdditionalPartialInvokeNode extends DataFlow::InvokeNode {
/**
* Holds if `argument` is passed as argument `index` to the function in `callback`.
*/
cached abstract predicate isPartialArgument(DataFlow::Node callback, DataFlow::Node argument, int index);
abstract predicate isPartialArgument(DataFlow::Node callback, DataFlow::Node argument, int index);
}
/**

View File

@@ -131,6 +131,26 @@ abstract class SourceNode extends DataFlow::Node {
)
}
/**
* Gets a method call that invokes a method on this node.
*
* This includes only calls that have the syntactic shape of a method call,
* that is, `o.m(...)` or `o[p](...)`.
*/
DataFlow::CallNode getAMethodCall() {
result = getAMethodCall(_)
}
/**
* Gets a chained method call that invokes `methodName` last.
*
* The chain steps include only calls that have the syntactic shape of a method call,
* that is, `o.m(...)` or `o[p](...)`.
*/
DataFlow::CallNode getAChainedMethodCall(string methodName) {
result = getAMethodCall*().getAMethodCall(methodName)
}
/**
* Gets a `new` call that invokes constructor `constructorName` on this node.
*/

View File

@@ -268,6 +268,12 @@ private class AnalyzedVariableExport extends AnalyzedPropertyWrite, DataFlow::Va
propName = name and
source = varDef.getSource().analyze()
}
override predicate writesValue(AbstractValue baseVal, string propName, AbstractValue val) {
baseVal = TAbstractExportsObject(export.getEnclosingModule()) and
propName = name and
val = varDef.getAnAssignedValue()
}
}
/**

View File

@@ -160,18 +160,26 @@ private class IIFEWithAnalyzedReturnFlow extends CallWithAnalyzedReturnFlow {
}
/**
* Gets the only access to `v`, which is the variable declared by `fn`.
*
* This predicate is not defined for global functions `fn`, or for
* local variables `v` that do not have exactly one access.
*/
private VarAccess getOnlyAccess(FunctionDeclStmt fn, LocalVariable v) {
v = fn.getVariable() and
result = v.getAnAccess() and
strictcount(v.getAnAccess()) = 1
}
/** A function that only is used locally, making it amenable to type inference. */
class LocalFunction extends Function {
DataFlow::Impl::ExplicitInvokeNode invk;
LocalFunction() {
this instanceof FunctionDeclStmt and
exists (LocalVariable v, Expr callee |
callee = invk.getCalleeNode().asExpr() and
v = getVariable() and
v.getAnAccess() = callee and
forall(VarAccess o | o = v.getAnAccess() | o = callee) and
exists (LocalVariable v |
getOnlyAccess(this, v) = invk.getCalleeNode().asExpr() and
not exists(v.getAnAssignedExpr()) and
not exists(ExportDeclaration export | export.exportsAs(v, _))
) and

View File

@@ -96,8 +96,24 @@ abstract class AnalyzedPropertyWrite extends DataFlow::Node {
/**
* Holds if this property write assigns `source` to property `propName` of one of the
* concrete objects represented by `baseVal`.
*
* Note that not all property writes have an explicit `source` node; use predicate
* `writesValue` below to cover these cases.
*/
abstract predicate writes(AbstractValue baseVal, string propName, DataFlow::AnalyzedNode source);
predicate writes(AbstractValue baseVal, string propName, DataFlow::AnalyzedNode source) {
none()
}
/**
* Holds if this property write assigns `val` to property `propName` of one of the
* concrete objects represented by `baseVal`.
*/
predicate writesValue(AbstractValue baseVal, string propName, AbstractValue val) {
exists (AnalyzedNode source |
writes(baseVal, propName, source) and
val = source.getALocalValue()
)
}
/**
* Holds if the flow information for the base node of this property write is incomplete

View File

@@ -116,31 +116,36 @@ private class RequestUrlRequest extends CustomClientRequest {
*/
private class AxiosUrlRequest extends CustomClientRequest {
DataFlow::Node url;
string method;
AxiosUrlRequest() {
exists (string moduleName, DataFlow::SourceNode callee |
this = callee.getACall() |
moduleName = "axios" and
(
callee = DataFlow::moduleImport(moduleName) or
callee = DataFlow::moduleMember(moduleName, httpMethodName()) or
callee = DataFlow::moduleMember(moduleName, "request")
) and
(
url = getArgument(0) or
// depends on the method name and the call arity, over-approximating slightly in the name of simplicity
url = getOptionArgument([0..2], urlPropertyName())
callee = DataFlow::moduleImport(moduleName) and method = "request" or
callee = DataFlow::moduleMember(moduleName, method) and (method = httpMethodName() or method = "request")
)
)
}
override DataFlow::Node getUrl() {
result = url
result = getArgument(0) or
// depends on the method name and the call arity, over-approximating slightly in the name of simplicity
result = getOptionArgument([0..2], urlPropertyName())
}
override DataFlow::Node getADataNode() {
none()
method = "request" and
result = getOptionArgument(0, "data")
or
(method = "post" or method = "put" or method = "put") and
(result = getArgument(1) or result = getOptionArgument(2, "data"))
or
exists (string name |
name = "headers" or name = "params"|
result = getOptionArgument([0..2], name)
)
}
}
@@ -175,7 +180,10 @@ private class FetchUrlRequest extends CustomClientRequest {
}
override DataFlow::Node getADataNode() {
none()
exists (string name |
name = "headers" or name = "body" |
result = getOptionArgument(1, name)
)
}
}
@@ -185,8 +193,6 @@ private class FetchUrlRequest extends CustomClientRequest {
*/
private class GotUrlRequest extends CustomClientRequest {
DataFlow::Node url;
GotUrlRequest() {
exists (string moduleName, DataFlow::SourceNode callee |
this = callee.getACall() |
@@ -194,17 +200,20 @@ private class GotUrlRequest extends CustomClientRequest {
(
callee = DataFlow::moduleImport(moduleName) or
callee = DataFlow::moduleMember(moduleName, "stream")
) and
url = getArgument(0) and not exists (getOptionArgument(1, "baseUrl"))
)
)
}
override DataFlow::Node getUrl() {
result = url
result = getArgument(0) and
not exists (getOptionArgument(1, "baseUrl"))
}
override DataFlow::Node getADataNode() {
none()
exists (string name |
name = "headers" or name = "body" or name = "query" |
result = getOptionArgument(1, name)
)
}
}
@@ -230,7 +239,10 @@ private class SuperAgentUrlRequest extends CustomClientRequest {
}
override DataFlow::Node getADataNode() {
none()
exists (string name |
name = "set" or name = "send" or name = "query" |
result = this.getAChainedMethodCall(name).getAnArgument()
)
}
}

View File

@@ -49,32 +49,14 @@ module Electron {
}
}
/**
* A Node.js-style HTTP or HTTPS request made using `electron.net`, for example `net.request(url)`.
*/
private class NetRequest extends CustomElectronClientRequest {
NetRequest() {
this = DataFlow::moduleMember("electron", "net").getAMemberCall("request")
}
override DataFlow::Node getUrl() {
result = getArgument(0) or
result = getOptionArgument(0, "url")
}
override DataFlow::Node getADataNode() {
none()
}
}
/**
* A Node.js-style HTTP or HTTPS request made using `electron.client`, for example `new client(url)`.
* A Node.js-style HTTP or HTTPS request made using `electron.ClientRequest`.
*/
private class NewClientRequest extends CustomElectronClientRequest {
NewClientRequest() {
this = DataFlow::moduleMember("electron", "ClientRequest").getAnInstantiation()
this = DataFlow::moduleMember("electron", "ClientRequest").getAnInstantiation() or
this = DataFlow::moduleMember("electron", "net").getAMemberCall("request") // alias
}
override DataFlow::Node getUrl() {
@@ -83,7 +65,10 @@ module Electron {
}
override DataFlow::Node getADataNode() {
none()
exists (string name |
name = "write" or name = "end" |
result =this.(DataFlow::SourceNode).getAMethodCall(name).getArgument(0)
)
}
}

View File

@@ -62,9 +62,22 @@ private module MongoDB {
QueryCall() {
exists (string m | asExpr().(MethodCallExpr).calls(any(Collection c), m) |
m = "aggregate" and queryArgIdx = 0 or
m = "count" and queryArgIdx = 0 or
m = "deleteMany" and queryArgIdx = 0 or
m = "deleteOne" and queryArgIdx = 0 or
m = "distinct" and queryArgIdx = 1 or
m = "find" and queryArgIdx = 0
m = "find" and queryArgIdx = 0 or
m = "findOne" and queryArgIdx = 0 or
m = "findOneAndDelete" and queryArgIdx = 0 or
m = "findOneAndRemove" and queryArgIdx = 0 or
m = "findOneAndDelete" and queryArgIdx = 0 or
m = "findOneAndUpdate" and queryArgIdx = 0 or
m = "remove" and queryArgIdx = 0 or
m = "replaceOne" and queryArgIdx = 0 or
m = "update" and queryArgIdx = 0 or
m = "updateMany" and queryArgIdx = 0 or
m = "updateOne" and queryArgIdx = 0
)
}

View File

@@ -740,7 +740,10 @@ module NodeJSLib {
}
override DataFlow::Node getADataNode() {
result = getAMethodCall("write").getArgument(0)
exists (string name |
name = "write" or name = "end" |
result =this.(DataFlow::SourceNode).getAMethodCall(name).getArgument(0)
)
}
}

View File

@@ -387,3 +387,105 @@ private module Sequelize {
}
}
}
/**
* Provides classes modelling the Google Cloud Spanner library.
*/
private module Spanner {
/**
* Gets a node that refers to the `Spanner` class
*/
DataFlow::SourceNode spanner() {
// older versions
result = DataFlow::moduleImport("@google-cloud/spanner")
or
// newer versions
result = DataFlow::moduleMember("@google-cloud/spanner", "Spanner")
}
/**
* Gets a node that refers to an instance of the `Database` class.
*/
DataFlow::SourceNode database() {
result = spanner().getAnInvocation().getAMethodCall("instance").getAMethodCall("database")
}
/**
* Gets a node that refers to an instance of the `v1.SpannerClient` class.
*/
DataFlow::SourceNode v1SpannerClient() {
result = spanner().getAPropertyRead("v1").getAPropertyRead("SpannerClient").getAnInstantiation()
}
/**
* Gets a node that refers to a transaction object.
*/
DataFlow::SourceNode transaction() {
result = database().getAMethodCall("runTransaction").getCallback(0).getParameter(1)
}
/**
* A call to a Spanner method that executes a SQL query.
*/
abstract class SqlExecution extends DatabaseAccess, DataFlow::InvokeNode {
/**
* Gets the position of the query argument; default is zero, which can be overridden
* by subclasses.
*/
int getQueryArgumentPosition() {
result = 0
}
override DataFlow::Node getAQueryArgument() {
result = getArgument(getQueryArgumentPosition()) or
result = getOptionArgument(getQueryArgumentPosition(), "sql")
}
}
/**
* A call to `Database.run`, `Database.runPartitionedUpdate` or `Database.runStream`.
*/
class DatabaseRunCall extends SqlExecution {
DatabaseRunCall() {
exists (string run | run = "run" or run = "runPartitionedUpdate" or run = "runStream" |
this = database().getAMethodCall(run)
)
}
}
/**
* A call to `Transaction.run`, `Transaction.runStream` or `Transaction.runUpdate`.
*/
class TransactionRunCall extends SqlExecution {
TransactionRunCall() {
exists (string run | run = "run" or run = "runStream" or run = "runUpdate" |
this = transaction().getAMethodCall(run)
)
}
}
/**
* A call to `v1.SpannerClient.executeSql` or `v1.SpannerClient.executeStreamingSql`.
*/
class ExecuteSqlCall extends SqlExecution {
ExecuteSqlCall() {
exists (string exec | exec = "executeSql" or exec = "executeStreamingSql" |
this = v1SpannerClient().getAMethodCall(exec)
)
}
override DataFlow::Node getAQueryArgument() {
// `executeSql` and `executeStreamingSql` do not accept query strings directly
result = getOptionArgument(0, "sql")
}
}
/**
* An expression that is interpreted as a SQL string.
*/
class QueryString extends SQL::SqlString {
QueryString() {
this = any(SqlExecution se).getAQueryArgument().asExpr()
}
}
}

View File

@@ -4,10 +4,12 @@
| ChatListScreen.js:3:1:5:1 | instance of function foo |
| a2.js:1:1:2:0 | exports object of module a2 |
| a2.js:1:1:2:0 | module object of module a2 |
| a.js:1:1:13:0 | exports object of module a |
| a.js:1:1:13:0 | module object of module a |
| a.js:1:1:18:0 | exports object of module a |
| a.js:1:1:18:0 | module object of module a |
| a.js:3:8:5:1 | function setX |
| a.js:3:8:5:1 | instance of function setX |
| a.js:15:1:17:1 | function bump |
| a.js:15:1:17:1 | instance of function bump |
| amd2.js:1:1:4:0 | exports object of module amd2 |
| amd2.js:1:1:4:0 | module object of module amd2 |
| amd2.js:1:8:3:1 | anonymous function |
@@ -36,8 +38,8 @@
| arguments.js:30:2:33:1 | anonymous function |
| arguments.js:30:2:33:1 | arguments object of anonymous function |
| arguments.js:30:2:33:1 | instance of anonymous function |
| b.js:1:1:55:0 | exports object of module b |
| b.js:1:1:55:0 | module object of module b |
| b.js:1:1:58:0 | exports object of module b |
| b.js:1:1:58:0 | module object of module b |
| backend.js:1:1:3:0 | exports object of module backend |
| backend.js:1:1:3:0 | module object of module backend |
| backend.js:1:17:1:18 | object literal |

View File

@@ -10,3 +10,8 @@ let z = someGlobal;
export let w;
w = "w";
export let notAlwaysZero = 0;
function bump() {
++notAlwaysZero;
}

View File

@@ -6,6 +6,7 @@
| a.js:9:5:9:5 | z | a.js:9:9:9:18 | someGlobal | file://:0:0:0:0 | indefinite value (global) |
| a.js:9:5:9:5 | z | a.js:9:9:9:18 | someGlobal | file://:0:0:0:0 | non-zero value |
| a.js:9:5:9:5 | z | a.js:9:9:9:18 | someGlobal | file://:0:0:0:0 | true |
| a.js:14:12:14:24 | notAlwaysZero | a.js:14:28:14:28 | 0 | file://:0:0:0:0 | 0 |
| amd.js:2:7:2:7 | m | amd.js:2:11:2:13 | mod | amd.js:1:1:7:0 | module object of module amd |
| amd.js:2:7:2:7 | m | amd.js:2:11:2:13 | mod | file://:0:0:0:0 | indefinite value (call) |
| amd.js:3:7:3:7 | e | amd.js:3:11:3:13 | exp | amd.js:1:1:7:0 | exports object of module amd |
@@ -58,6 +59,8 @@
| b.js:48:5:48:7 | z13 | b.js:48:11:48:11 | w | file://:0:0:0:0 | non-empty, non-numeric string |
| b.js:51:5:51:7 | z14 | b.js:51:11:51:24 | foo_reexported | file://:0:0:0:0 | indefinite value (import) |
| b.js:54:5:54:7 | z15 | b.js:54:11:54:19 | something | file://:0:0:0:0 | indefinite value (import) |
| b.js:57:5:57:7 | z16 | b.js:57:11:57:23 | notAlwaysZero | file://:0:0:0:0 | 0 |
| b.js:57:5:57:7 | z16 | b.js:57:11:57:23 | notAlwaysZero | file://:0:0:0:0 | non-zero value |
| backend.js:1:7:1:13 | Backend | backend.js:1:17:1:18 | {} | backend.js:1:17:1:18 | object literal |
| classAccessors.js:10:9:10:11 | myX | classAccessors.js:10:15:10:20 | this.x | file://:0:0:0:0 | indefinite value (call) |
| classAccessors.js:10:9:10:11 | myX | classAccessors.js:10:15:10:20 | this.x | file://:0:0:0:0 | indefinite value (heap) |

View File

@@ -52,3 +52,6 @@ let z14 = foo_reexported;
import { something } from './reexport-unknown';
let z15 = something;
import { notAlwaysZero } from './a';
let z16 = notAlwaysZero;

View File

@@ -2,6 +2,7 @@
| a.js:1:12:1:12 | x | a.js:1:16:1:16 | 0 | number |
| a.js:1:19:1:19 | y | a.js:1:23:1:23 | 0 | number |
| a.js:9:5:9:5 | z | a.js:9:9:9:18 | someGlobal | boolean, class, date, function, null, number, object, regular expression,string or undefined |
| a.js:14:12:14:24 | notAlwaysZero | a.js:14:28:14:28 | 0 | number |
| amd.js:2:7:2:7 | m | amd.js:2:11:2:13 | mod | boolean, class, date, function, null, number, object, regular expression,string or undefined |
| amd.js:3:7:3:7 | e | amd.js:3:11:3:13 | exp | boolean, class, date, function, null, number, object, regular expression,string or undefined |
| arguments.js:2:7:2:7 | y | arguments.js:2:11:2:11 | x | number |
@@ -32,6 +33,7 @@
| b.js:48:5:48:7 | z13 | b.js:48:11:48:11 | w | string |
| b.js:51:5:51:7 | z14 | b.js:51:11:51:24 | foo_reexported | boolean, class, date, function, null, number, object, regular expression,string or undefined |
| b.js:54:5:54:7 | z15 | b.js:54:11:54:19 | something | boolean, class, date, function, null, number, object, regular expression,string or undefined |
| b.js:57:5:57:7 | z16 | b.js:57:11:57:23 | notAlwaysZero | number |
| backend.js:1:7:1:13 | Backend | backend.js:1:17:1:18 | {} | object |
| classAccessors.js:10:9:10:11 | myX | classAccessors.js:10:15:10:20 | this.x | boolean, class, date, function, null, number, object, regular expression,string or undefined |
| classAccessors.js:11:9:11:11 | myY | classAccessors.js:11:15:11:20 | this.y | boolean, class, date, function, null, number, object, regular expression,string or undefined |

View File

@@ -16,3 +16,14 @@
| tst.js:41:5:41:29 | net.req ... url }) |
| tst.js:43:5:43:26 | new Cli ... st(url) |
| tst.js:45:5:45:35 | new Cli ... url }) |
| tst.js:53:5:53:23 | axios({data: data}) |
| tst.js:55:5:55:34 | axios.g ... _data}) |
| tst.js:57:5:57:39 | axios.p ... data2}) |
| tst.js:59:5:59:52 | axios({ ... sData}) |
| tst.js:61:5:61:60 | window. ... yData}) |
| tst.js:63:5:63:68 | got(url ... yData}) |
| tst.js:65:5:65:23 | superagent.get(url) |
| tst.js:66:5:66:23 | superagent.get(url) |
| tst.js:67:5:67:24 | superagent.post(url) |
| tst.js:68:5:68:23 | superagent.get(url) |
| tst.js:69:5:69:23 | superagent.get(url) |

View File

@@ -0,0 +1,17 @@
| tst.js:53:5:53:23 | axios({data: data}) | tst.js:53:18:53:21 | data |
| tst.js:57:5:57:39 | axios.p ... data2}) | tst.js:57:19:57:23 | data1 |
| tst.js:57:5:57:39 | axios.p ... data2}) | tst.js:57:33:57:37 | data2 |
| tst.js:59:5:59:52 | axios({ ... sData}) | tst.js:59:21:59:30 | headerData |
| tst.js:59:5:59:52 | axios({ ... sData}) | tst.js:59:41:59:50 | paramsData |
| tst.js:61:5:61:60 | window. ... yData}) | tst.js:61:33:61:42 | headerData |
| tst.js:61:5:61:60 | window. ... yData}) | tst.js:61:51:61:58 | bodyData |
| tst.js:63:5:63:68 | got(url ... yData}) | tst.js:63:24:63:33 | headerData |
| tst.js:63:5:63:68 | got(url ... yData}) | tst.js:63:42:63:49 | bodyData |
| tst.js:65:5:65:23 | superagent.get(url) | tst.js:65:31:65:34 | data |
| tst.js:66:5:66:23 | superagent.get(url) | tst.js:66:29:66:31 | 'x' |
| tst.js:66:5:66:23 | superagent.get(url) | tst.js:66:34:66:43 | headerData |
| tst.js:67:5:67:24 | superagent.post(url) | tst.js:67:31:67:38 | bodyData |
| tst.js:68:5:68:23 | superagent.get(url) | tst.js:68:29:68:31 | 'x' |
| tst.js:68:5:68:23 | superagent.get(url) | tst.js:68:34:68:43 | headerData |
| tst.js:68:5:68:23 | superagent.get(url) | tst.js:68:52:68:60 | queryData |
| tst.js:69:5:69:23 | superagent.get(url) | tst.js:69:48:69:56 | queryData |

View File

@@ -0,0 +1,4 @@
import javascript
from ClientRequest r
select r, r.getADataNode()

View File

@@ -20,3 +20,14 @@
| tst.js:43:5:43:26 | new Cli ... st(url) | tst.js:43:23:43:25 | url |
| tst.js:45:5:45:35 | new Cli ... url }) | tst.js:45:23:45:34 | { url: url } |
| tst.js:45:5:45:35 | new Cli ... url }) | tst.js:45:30:45:32 | url |
| tst.js:53:5:53:23 | axios({data: data}) | tst.js:53:11:53:22 | {data: data} |
| tst.js:55:5:55:34 | axios.g ... _data}) | tst.js:55:15:55:15 | x |
| tst.js:57:5:57:39 | axios.p ... data2}) | tst.js:57:16:57:16 | x |
| tst.js:59:5:59:52 | axios({ ... sData}) | tst.js:59:11:59:51 | {header ... msData} |
| tst.js:61:5:61:60 | window. ... yData}) | tst.js:61:18:61:20 | url |
| tst.js:63:5:63:68 | got(url ... yData}) | tst.js:63:9:63:11 | url |
| tst.js:65:5:65:23 | superagent.get(url) | tst.js:65:20:65:22 | url |
| tst.js:66:5:66:23 | superagent.get(url) | tst.js:66:20:66:22 | url |
| tst.js:67:5:67:24 | superagent.post(url) | tst.js:67:21:67:23 | url |
| tst.js:68:5:68:23 | superagent.get(url) | tst.js:68:20:68:22 | url |
| tst.js:69:5:69:23 | superagent.get(url) | tst.js:69:20:69:22 | url |

View File

@@ -48,3 +48,24 @@ import {ClientRequest, net} from 'electron';
unknown({ url:url });
});
(function() {
axios({data: data});
axios.get(x, {data: not_data});
axios.post(x, data1, {data: data2});
axios({headers: headerData, params: paramsData});
window.fetch(url, {headers: headerData, body: bodyData});
got(url, {headers: headerData, body: bodyData, quer: queryData});
superagent.get(url).query(data);
superagent.get(url).set('x', headerData)
superagent.post(url).send(bodyData);
superagent.get(url).set('x', headerData).query(queryData);
superagent.get(url).unknown(nonData).query(queryData);
});

View File

@@ -0,0 +1,2 @@
| electron.js:8:16:8:78 | new Cli ... POST'}) | electron.js:31:16:31:22 | 'stuff' |
| electron.js:8:16:8:78 | new Cli ... POST'}) | electron.js:32:14:32:25 | 'more stuff' |

View File

@@ -0,0 +1,4 @@
import javascript
from Electron::ElectronClientRequest cr
select cr, cr.getADataNode()

View File

@@ -0,0 +1,2 @@
| src/http.js:27:16:27:73 | http.re ... POST'}) | src/http.js:50:16:50:22 | 'stuff' |
| src/http.js:27:16:27:73 | http.re ... POST'}) | src/http.js:51:14:51:25 | 'more stuff' |

View File

@@ -0,0 +1,4 @@
import javascript
from NodeJSLib::NodeJSClientRequest cr
select cr, cr.getADataNode()

View File

@@ -14,4 +14,24 @@
| postgres3.js:15:16:15:40 | 'SELECT ... s name' |
| sequelize2.js:10:17:10:118 | 'SELECT ... Y name' |
| sequelize.js:8:17:8:118 | 'SELECT ... Y name' |
| spanner2.js:5:26:5:35 | "SQL code" |
| spanner2.js:7:35:7:44 | "SQL code" |
| spanner.js:6:8:6:17 | "SQL code" |
| spanner.js:7:8:7:26 | { sql: "SQL code" } |
| spanner.js:7:15:7:24 | "SQL code" |
| spanner.js:8:25:8:34 | "SQL code" |
| spanner.js:9:25:9:43 | { sql: "SQL code" } |
| spanner.js:9:32:9:41 | "SQL code" |
| spanner.js:10:14:10:23 | "SQL code" |
| spanner.js:11:14:11:31 | { sql: "SQL code"} |
| spanner.js:11:21:11:30 | "SQL code" |
| spanner.js:14:10:14:19 | "SQL code" |
| spanner.js:15:10:15:28 | { sql: "SQL code" } |
| spanner.js:15:17:15:26 | "SQL code" |
| spanner.js:16:16:16:25 | "SQL code" |
| spanner.js:17:16:17:34 | { sql: "SQL code" } |
| spanner.js:17:23:17:32 | "SQL code" |
| spanner.js:18:16:18:25 | "SQL code" |
| spanner.js:19:16:19:34 | { sql: "SQL code" } |
| spanner.js:19:23:19:32 | "SQL code" |
| sqlite.js:7:8:7:45 | "UPDATE ... id = ?" |

View File

@@ -0,0 +1,20 @@
const { Spanner } = require("@google-cloud/spanner");
const spanner = new Spanner();
const instance = spanner.instance('inst');
const db = instance.database('db');
db.run("SQL code", (err, rows) => {});
db.run({ sql: "SQL code" }, (err, rows) => {});
db.runPartitionedUpdate("SQL code", (err, rows) => {});
db.runPartitionedUpdate({ sql: "SQL code" }, (err, rows) => {});
db.runStream("SQL code");
db.runStream({ sql: "SQL code"});
db.runTransaction((err, tx) => {
tx.run("SQL code");
tx.run({ sql: "SQL code" });
tx.runStream("SQL code");
tx.runStream({ sql: "SQL code" });
tx.runUpdate("SQL code");
tx.runUpdate({ sql: "SQL code" });
});

View File

@@ -0,0 +1,7 @@
const spanner = require("@google-cloud/spanner");
const client = new spanner.v1.SpannerClient({});
client.executeSql("not SQL code", (err, rows) => {});
client.executeSql({ sql: "SQL code" }, (err, rows) => {});
client.executeStreamingSql("not SQL code", (err, rows) => {});
client.executeStreamingSql({ sql: "SQL code" }, (err, rows) => {});

View File

@@ -1,6 +1,18 @@
| mongodb.js:18:16:18:20 | query | This query depends on $@. | mongodb.js:13:19:13:26 | req.body | a user-provided value |
| mongodb.js:39:16:39:20 | query | This query depends on $@. | mongodb.js:34:19:34:33 | req.query.title | a user-provided value |
| mongoose.js:24:19:24:23 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
| mongoose.js:27:20:27:24 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
| mongoose.js:30:25:30:29 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
| mongoose.js:33:24:33:28 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
| mongoose.js:36:31:36:35 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
| mongoose.js:39:19:39:23 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
| mongoose.js:42:22:42:26 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
| mongoose.js:45:31:45:35 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
| mongoose.js:48:31:48:35 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
| mongoose.js:51:31:51:35 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
| mongoose.js:54:25:54:29 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
| mongoose.js:57:21:57:25 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
| mongoose.js:60:25:60:29 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
| mongoose.js:63:24:63:28 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
| mongooseJsonParse.js:23:19:23:23 | query | This query depends on $@. | mongooseJsonParse.js:20:30:20:43 | req.query.data | a user-provided value |
| tst2.js:9:27:9:84 | "select ... d + "'" | This query depends on $@. | tst2.js:9:66:9:78 | req.params.id | a user-provided value |
| tst3.js:10:14:10:19 | query1 | This query depends on $@. | tst3.js:9:16:9:34 | req.params.category | a user-provided value |

View File

@@ -20,7 +20,46 @@ app.post('/documents/find', (req, res) => {
const query = {};
query.title = req.body.title;
// NOT OK: query is tainted by user-provided object value
Document.aggregate('type', query);
// NOT OK: query is tainted by user-provided object value
Document.count(query);
// NOT OK: query is tainted by user-provided object value
Document.deleteMany(query);
// NOT OK: query is tainted by user-provided object value
Document.deleteOne(query);
// NOT OK: query is tainted by user-provided object value
Document.distinct('type', query);
// NOT OK: query is tainted by user-provided object value
Document.find(query);
// NOT OK: query is tainted by user-provided object value
Document.findOne(query);
// NOT OK: query is tainted by user-provided object value
Document.findOneAndDelete(query);
// NOT OK: query is tainted by user-provided object value
Document.findOneAndRemove(query);
// NOT OK: query is tainted by user-provided object value
Document.findOneAndUpdate(query);
// NOT OK: query is tainted by user-provided object value
Document.replaceOne(query);
// NOT OK: query is tainted by user-provided object value
Document.update(query);
// NOT OK: query is tainted by user-provided object value
Document.updateMany(query);
// NOT OK: query is tainted by user-provided object value
Document.updateOne(query);
});

View File

@@ -10,3 +10,5 @@
| tst.js:76:9:76:10 | v1 | This condition guards a sensitive $@, but $@ controls it. | tst.js:78:9:78:22 | process.exit() | action | tst.js:75:14:75:24 | req.cookies | a user-provided value |
| tst.js:76:9:76:10 | v1 | This condition guards a sensitive $@, but $@ controls it. | tst.js:78:9:78:22 | process.exit() | action | tst.js:75:39:75:58 | req.params.requestId | a user-provided value |
| tst.js:90:9:90:41 | req.coo ... secret" | This condition guards a sensitive $@, but $@ controls it. | tst.js:92:9:92:22 | process.exit() | action | tst.js:90:9:90:19 | req.cookies | a user-provided value |
| tst.js:111:13:111:32 | req.query.vulnerable | This condition guards a sensitive $@, but $@ controls it. | tst.js:114:9:114:16 | verify() | action | tst.js:111:13:111:32 | req.query.vulnerable | a user-provided value |
| tst.js:118:13:118:32 | req.query.vulnerable | This condition guards a sensitive $@, but $@ controls it. | tst.js:121:13:121:20 | verify() | action | tst.js:118:13:118:32 | req.query.vulnerable | a user-provided value |

View File

@@ -99,3 +99,34 @@ app.get('/user/:id', function(req, res) {
console.log(commit.author().toString());
}
});
app.get('/user/:id', function(req, res) {
if (!req.body || !username || !password || riskAssessnment == null) { // OK: early return below
res.status(400).send({ error: '...', id: '...' });
return
}
customerLogin.customerLogin(username, password, riskAssessment, clientIpAddress);
while (!verified) {
if (req.query.vulnerable) { // NOT OK
break;
}
verify();
}
while (!verified) {
if (req.query.vulnerable) { // NOT OK
break;
} else {
verify();
}
}
while (!verified) {
if (req.query.vulnerable) { // OK: early return
return;
}
verify();
}
});