mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge remote-tracking branch 'upstream/master' into mergeback-2018-10-17
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -10,3 +10,8 @@ let z = someGlobal;
|
||||
|
||||
export let w;
|
||||
w = "w";
|
||||
|
||||
export let notAlwaysZero = 0;
|
||||
function bump() {
|
||||
++notAlwaysZero;
|
||||
}
|
||||
|
||||
@@ -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) |
|
||||
|
||||
@@ -52,3 +52,6 @@ let z14 = foo_reexported;
|
||||
|
||||
import { something } from './reexport-unknown';
|
||||
let z15 = something;
|
||||
|
||||
import { notAlwaysZero } from './a';
|
||||
let z16 = notAlwaysZero;
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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) |
|
||||
|
||||
@@ -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 |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from ClientRequest r
|
||||
select r, r.getADataNode()
|
||||
@@ -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 |
|
||||
|
||||
@@ -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);
|
||||
|
||||
});
|
||||
|
||||
@@ -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' |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from Electron::ElectronClientRequest cr
|
||||
select cr, cr.getADataNode()
|
||||
@@ -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' |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from NodeJSLib::NodeJSClientRequest cr
|
||||
select cr, cr.getADataNode()
|
||||
@@ -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 = ?" |
|
||||
|
||||
20
javascript/ql/test/library-tests/frameworks/SQL/spanner.js
Normal file
20
javascript/ql/test/library-tests/frameworks/SQL/spanner.js
Normal 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" });
|
||||
});
|
||||
@@ -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) => {});
|
||||
@@ -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 |
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user