mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
Merge pull request #3076 from esbena/js/even-more-mongoose-improvements
Approved by erik-krogh
This commit is contained in:
@@ -209,16 +209,61 @@ private module Mongoose {
|
||||
result = getAMongooseInstance().getAMemberCall("createConnection")
|
||||
}
|
||||
|
||||
/**
|
||||
* A Mongoose function invocation.
|
||||
*/
|
||||
private class InvokeNode extends DataFlow::InvokeNode {
|
||||
/**
|
||||
* Holds if this invocation returns an object of type `Query`.
|
||||
*/
|
||||
abstract predicate returnsQuery();
|
||||
|
||||
/**
|
||||
* Holds if this invocation returns a `Query` that evaluates to one or
|
||||
* more Documents (`asArray` is false if it evaluates to a single
|
||||
* Document).
|
||||
*/
|
||||
abstract predicate returnsDocumentQuery(boolean asArray);
|
||||
|
||||
/**
|
||||
* Holds if this invocation interprets `arg` as a query.
|
||||
*/
|
||||
abstract predicate interpretsArgumentAsQuery(DataFlow::Node arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides classes modeling the Mongoose Model class
|
||||
*/
|
||||
module Model {
|
||||
private class ModelInvokeNode extends InvokeNode, DataFlow::MethodCallNode {
|
||||
ModelInvokeNode() { this = ref().getAMethodCall() }
|
||||
|
||||
override predicate returnsQuery() { MethodSignatures::returnsQuery(getMethodName()) }
|
||||
|
||||
override predicate returnsDocumentQuery(boolean asArray) {
|
||||
MethodSignatures::returnsDocumentQuery(getMethodName(), asArray)
|
||||
}
|
||||
|
||||
override predicate interpretsArgumentAsQuery(DataFlow::Node arg) {
|
||||
exists(int n |
|
||||
MethodSignatures::interpretsArgumentAsQuery(this.getMethodName(), n) and
|
||||
arg = this.getArgument(n)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data flow node referring to a Mongoose Model object.
|
||||
*/
|
||||
private DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
|
||||
(
|
||||
result = getAMongooseInstance().getAMemberCall("model") or
|
||||
result = getAMongooseInstance().getAMemberCall("model")
|
||||
or
|
||||
exists(DataFlow::SourceNode conn | conn = createConnection() |
|
||||
result = conn.getAMemberCall("model") or
|
||||
result = conn.getAPropertyRead("models").getAPropertyRead()
|
||||
)
|
||||
or
|
||||
result.hasUnderlyingType("mongoose", "Model")
|
||||
) and
|
||||
t.start()
|
||||
@@ -271,6 +316,17 @@ private module Mongoose {
|
||||
name = "updateOne" or
|
||||
name = "where"
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if Document method `name` returns a query that results in
|
||||
* one or more documents, the documents are wrapped in an array
|
||||
* if `asArray` is true.
|
||||
*/
|
||||
predicate returnsDocumentQuery(string name, boolean asArray) {
|
||||
asArray = false and name = "findOne"
|
||||
or
|
||||
asArray = true and name = "find"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,25 +334,33 @@ private module Mongoose {
|
||||
* Provides classes modeling the Mongoose Query class
|
||||
*/
|
||||
module Query {
|
||||
/**
|
||||
* A Mongoose query object as a result of a Model method call.
|
||||
*/
|
||||
private class QueryFromModel extends DataFlow::MethodCallNode {
|
||||
QueryFromModel() {
|
||||
exists(string name |
|
||||
Model::MethodSignatures::returnsQuery(name) and
|
||||
Model::ref().getAMethodCall(name) = this
|
||||
private class QueryInvokeNode extends InvokeNode, DataFlow::MethodCallNode {
|
||||
QueryInvokeNode() { this = ref().getAMethodCall() }
|
||||
|
||||
override predicate returnsQuery() { MethodSignatures::returnsQuery(getMethodName()) }
|
||||
|
||||
override predicate returnsDocumentQuery(boolean asArray) {
|
||||
MethodSignatures::returnsDocumentQuery(getMethodName(), asArray)
|
||||
}
|
||||
|
||||
override predicate interpretsArgumentAsQuery(DataFlow::Node arg) {
|
||||
exists(int n |
|
||||
MethodSignatures::interpretsArgumentAsQuery(this.getMethodName(), n) and
|
||||
arg = this.getArgument(n)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Mongoose query object as a result of a Query constructor invocation.
|
||||
*/
|
||||
class QueryFromConstructor extends DataFlow::NewNode {
|
||||
QueryFromConstructor() {
|
||||
private class NewQueryInvokeNode extends InvokeNode {
|
||||
NewQueryInvokeNode() {
|
||||
this = getAMongooseInstance().getAPropertyRead("Query").getAnInstantiation()
|
||||
}
|
||||
|
||||
override predicate returnsQuery() { any() }
|
||||
|
||||
override predicate returnsDocumentQuery(boolean asArray) { none() }
|
||||
|
||||
override predicate interpretsArgumentAsQuery(DataFlow::Node arg) { arg = this.getArgument(2) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,8 +368,7 @@ private module Mongoose {
|
||||
*/
|
||||
private DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
|
||||
(
|
||||
result instanceof QueryFromConstructor or
|
||||
result instanceof QueryFromModel or
|
||||
result.(InvokeNode).returnsQuery() or
|
||||
result.hasUnderlyingType("mongoose", "Query")
|
||||
) and
|
||||
t.start()
|
||||
@@ -444,6 +507,152 @@ private module Mongoose {
|
||||
name = "within" or
|
||||
name = "wtimeout"
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if Query method `name` returns a query that results in
|
||||
* one or more documents, the documents are wrapped in an array
|
||||
* if `asArray` is true.
|
||||
*/
|
||||
predicate returnsDocumentQuery(string name, boolean asArray) {
|
||||
asArray = false and name = "findOne"
|
||||
or
|
||||
asArray = true and name = "find"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides classes modeling the Mongoose Document class
|
||||
*/
|
||||
module Document {
|
||||
private class DocumentInvokeNode extends InvokeNode, DataFlow::MethodCallNode {
|
||||
DocumentInvokeNode() { this = ref().getAMethodCall() }
|
||||
|
||||
override predicate returnsQuery() { MethodSignatures::returnsQuery(getMethodName()) }
|
||||
|
||||
override predicate returnsDocumentQuery(boolean asArray) {
|
||||
MethodSignatures::returnsDocumentQuery(getMethodName(), asArray)
|
||||
}
|
||||
|
||||
override predicate interpretsArgumentAsQuery(DataFlow::Node arg) {
|
||||
exists(int n |
|
||||
MethodSignatures::interpretsArgumentAsQuery(this.getMethodName(), n) and
|
||||
arg = this.getArgument(n)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Mongoose Document that is retrieved from the backing database.
|
||||
*/
|
||||
class RetrievedDocument extends DataFlow::SourceNode {
|
||||
RetrievedDocument() {
|
||||
exists(boolean asArray, DataFlow::ParameterNode param |
|
||||
exists(InvokeNode call |
|
||||
call.returnsDocumentQuery(asArray) and
|
||||
param = call.getCallback(call.getNumArgument() - 1).getParameter(1)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
DataFlow::SourceNode base, DataFlow::MethodCallNode call, string executor,
|
||||
int paramIndex
|
||||
|
|
||||
executor = "then" and paramIndex = 0
|
||||
or
|
||||
executor = "exec" and paramIndex = 1
|
||||
|
|
||||
base = Query::ref() and
|
||||
call = base.getAMethodCall(executor) and
|
||||
param = call.getCallback(0).getParameter(paramIndex) and
|
||||
exists(DataFlow::MethodCallNode pred |
|
||||
// limitation: look at the previous method call
|
||||
Query::MethodSignatures::returnsDocumentQuery(pred.getMethodName(), asArray) and
|
||||
pred.getAMethodCall() = call
|
||||
)
|
||||
)
|
||||
|
|
||||
asArray = false and this = param
|
||||
or
|
||||
asArray = true and
|
||||
exists(DataFlow::PropRead access |
|
||||
// limitation: look for direct accesses
|
||||
access = param.getAPropertyRead() and
|
||||
not exists(access.getPropertyName()) and
|
||||
this = access
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data flow node referring to a Mongoose Document object.
|
||||
*/
|
||||
private DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
|
||||
(
|
||||
result instanceof RetrievedDocument or
|
||||
result.hasUnderlyingType("mongoose", "Document")
|
||||
) and
|
||||
t.start()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2, DataFlow::SourceNode succ | succ = ref(t2) |
|
||||
result = succ.track(t2, t)
|
||||
or
|
||||
result = succ.getAMethodCall(any(string name | MethodSignatures::returnsDocument(name))) and
|
||||
t = t2.continue()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data flow node referring to a Mongoose Document object.
|
||||
*/
|
||||
DataFlow::SourceNode ref() { result = ref(DataFlow::TypeTracker::end()) }
|
||||
|
||||
private module MethodSignatures {
|
||||
/**
|
||||
* Holds if Document method `name` returns a Query.
|
||||
*/
|
||||
predicate returnsQuery(string name) {
|
||||
// Documents are subtypes of Models
|
||||
Model::MethodSignatures::returnsQuery(name) or
|
||||
name = "replaceOne" or
|
||||
name = "update" or
|
||||
name = "updateOne"
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if Document method `name` interprets parameter `n` as a query.
|
||||
*/
|
||||
predicate interpretsArgumentAsQuery(string name, int n) {
|
||||
// Documents are subtypes of Models
|
||||
Model::MethodSignatures::interpretsArgumentAsQuery(name, n)
|
||||
or
|
||||
n = 0 and
|
||||
(
|
||||
name = "replaceOne" or
|
||||
name = "update" or
|
||||
name = "updateOne"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if Document method `name` returns a query that results in
|
||||
* one or more documents, the documents are wrapped in an array
|
||||
* if `asArray` is true.
|
||||
*/
|
||||
predicate returnsDocumentQuery(string name, boolean asArray) {
|
||||
// Documents are subtypes of Models
|
||||
Model::MethodSignatures::returnsDocumentQuery(name, asArray)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if Document method `name` returns a Document.
|
||||
*/
|
||||
predicate returnsDocument(string name) {
|
||||
name = "depopulate" or
|
||||
name = "init" or
|
||||
name = "populate" or
|
||||
name = "overwrite"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,53 +677,39 @@ private module Mongoose {
|
||||
* An expression that is interpreted as a (part of a) MongoDB query.
|
||||
*/
|
||||
class MongoDBQueryPart extends NoSQL::Query {
|
||||
MongoDBQueryPart() {
|
||||
exists(DataFlow::MethodCallNode mcn, string method, int n |
|
||||
Model::MethodSignatures::interpretsArgumentAsQuery(method, n) and
|
||||
mcn = Model::ref().getAMethodCall(method) and
|
||||
this = mcn.getArgument(n).asExpr()
|
||||
)
|
||||
or
|
||||
this = any(Query::QueryFromConstructor c).getArgument(2).asExpr()
|
||||
or
|
||||
exists(string method, int n | Query::MethodSignatures::interpretsArgumentAsQuery(method, n) |
|
||||
this = Query::ref().getAMethodCall(method).getArgument(n).asExpr()
|
||||
)
|
||||
}
|
||||
MongoDBQueryPart() { any(InvokeNode call).interpretsArgumentAsQuery(this.flow()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An evaluation of a MongoDB query.
|
||||
*/
|
||||
class MongoDBQueryEvaluation extends DatabaseAccess {
|
||||
DataFlow::MethodCallNode mcn;
|
||||
class ShorthandQueryEvaluation extends DatabaseAccess {
|
||||
InvokeNode invk;
|
||||
|
||||
MongoDBQueryEvaluation() {
|
||||
this = mcn and
|
||||
(
|
||||
exists(string method |
|
||||
Model::MethodSignatures::returnsQuery(method) and
|
||||
mcn = Model::ref().getAMethodCall(method) and
|
||||
// callback provided to a Model method call
|
||||
exists(mcn.getCallback(mcn.getNumArgument() - 1))
|
||||
)
|
||||
or
|
||||
Query::ref().getAMethodCall() = mcn and
|
||||
(
|
||||
// explicit execution using a Query method call
|
||||
exists(string executor | executor = "exec" or executor = "then" or executor = "catch" |
|
||||
mcn.getMethodName() = executor
|
||||
)
|
||||
or
|
||||
// callback provided to a Query method call
|
||||
exists(mcn.getCallback(mcn.getNumArgument() - 1))
|
||||
)
|
||||
ShorthandQueryEvaluation() {
|
||||
this = invk and
|
||||
// shorthand for execution: provide a callback
|
||||
invk.returnsQuery() and
|
||||
exists(invk.getCallback(invk.getNumArgument() - 1))
|
||||
}
|
||||
|
||||
override DataFlow::Node getAQueryArgument() {
|
||||
// NB: the complete information is not easily accessible for deeply chained calls
|
||||
invk.interpretsArgumentAsQuery(result)
|
||||
}
|
||||
}
|
||||
|
||||
class ExplicitQueryEvaluation extends DatabaseAccess {
|
||||
ExplicitQueryEvaluation() {
|
||||
// explicit execution using a Query method call
|
||||
exists(string executor | executor = "exec" or executor = "then" or executor = "catch" |
|
||||
Query::ref().getAMethodCall(executor) = this
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAQueryArgument() {
|
||||
// NB: this does not account for all of the chained calls leading to this execution
|
||||
mcn.getAnArgument().asExpr().(MongoDBQueryPart).flow() = result
|
||||
// NB: the complete information is not easily accessible for deeply chained calls
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,19 @@
|
||||
| mongoose.js:65:2:65:51 | Documen ... on(){}) |
|
||||
| mongoose.js:67:2:68:27 | new Mon ... on(){}) |
|
||||
| mongoose.js:71:2:77:9 | Documen ... .exec() |
|
||||
| mongoose.js:84:2:84:52 | Documen ... query)) |
|
||||
| mongoose.js:85:2:85:52 | Documen ... query)) |
|
||||
| mongoose.js:86:2:86:57 | Documen ... query)) |
|
||||
| mongoose.js:87:2:87:57 | Documen ... query)) |
|
||||
| mongoose.js:88:2:88:52 | Documen ... query)) |
|
||||
| mongoose.js:89:2:89:55 | Documen ... query)) |
|
||||
| mongoose.js:91:2:91:52 | Documen ... query)) |
|
||||
| mongoose.js:92:2:92:49 | Documen ... query)) |
|
||||
| mongoose.js:93:2:93:57 | Documen ... query)) |
|
||||
| mongoose.js:94:2:94:54 | Documen ... query)) |
|
||||
| mongoose.js:95:2:95:52 | Documen ... query)) |
|
||||
| mongoose.js:96:2:96:52 | Documen ... query)) |
|
||||
| mongoose.js:98:2:98:50 | Documen ... query)) |
|
||||
| socketio.js:11:5:11:54 | db.run( ... ndle}`) |
|
||||
| tst2.js:7:3:7:62 | sql.que ... ms.id}` |
|
||||
| tst2.js:9:3:9:85 | new sql ... + "'") |
|
||||
|
||||
@@ -46,6 +46,9 @@ nodes
|
||||
| mongoose.js:21:19:21:26 | req.body |
|
||||
| mongoose.js:21:19:21:26 | req.body |
|
||||
| mongoose.js:21:19:21:32 | req.body.title |
|
||||
| mongoose.js:24:24:24:30 | [query] |
|
||||
| mongoose.js:24:24:24:30 | [query] |
|
||||
| mongoose.js:24:25:24:29 | query |
|
||||
| mongoose.js:27:20:27:24 | query |
|
||||
| mongoose.js:27:20:27:24 | query |
|
||||
| mongoose.js:30:25:30:29 | query |
|
||||
@@ -86,6 +89,22 @@ nodes
|
||||
| mongoose.js:74:16:74:20 | query |
|
||||
| mongoose.js:76:10:76:14 | query |
|
||||
| mongoose.js:76:10:76:14 | query |
|
||||
| mongoose.js:81:46:81:50 | query |
|
||||
| mongoose.js:81:46:81:50 | query |
|
||||
| mongoose.js:82:47:82:51 | query |
|
||||
| mongoose.js:82:47:82:51 | query |
|
||||
| mongoose.js:84:46:84:50 | query |
|
||||
| mongoose.js:84:46:84:50 | query |
|
||||
| mongoose.js:86:51:86:55 | query |
|
||||
| mongoose.js:86:51:86:55 | query |
|
||||
| mongoose.js:88:46:88:50 | query |
|
||||
| mongoose.js:88:46:88:50 | query |
|
||||
| mongoose.js:91:46:91:50 | query |
|
||||
| mongoose.js:91:46:91:50 | query |
|
||||
| mongoose.js:93:51:93:55 | query |
|
||||
| mongoose.js:93:51:93:55 | query |
|
||||
| mongoose.js:95:46:95:50 | query |
|
||||
| mongoose.js:95:46:95:50 | query |
|
||||
| mongooseJsonParse.js:19:11:19:20 | query |
|
||||
| mongooseJsonParse.js:19:19:19:20 | {} |
|
||||
| mongooseJsonParse.js:20:19:20:44 | JSON.pa ... y.data) |
|
||||
@@ -188,6 +207,7 @@ edges
|
||||
| mongodb_bodySafe.js:24:19:24:33 | req.query.title | mongodb_bodySafe.js:29:16:29:20 | query |
|
||||
| mongodb_bodySafe.js:24:19:24:33 | req.query.title | mongodb_bodySafe.js:29:16:29:20 | query |
|
||||
| mongodb_bodySafe.js:24:19:24:33 | req.query.title | mongodb_bodySafe.js:29:16:29:20 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:24:25:24:29 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:27:20:27:24 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:27:20:27:24 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:30:25:30:29 | query |
|
||||
@@ -228,11 +248,28 @@ edges
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:74:16:74:20 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:76:10:76:14 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:76:10:76:14 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:81:46:81:50 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:81:46:81:50 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:82:47:82:51 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:82:47:82:51 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:84:46:84:50 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:84:46:84:50 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:86:51:86:55 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:86:51:86:55 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:88:46:88:50 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:88:46:88:50 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:91:46:91:50 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:91:46:91:50 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:93:51:93:55 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:93:51:93:55 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:95:46:95:50 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:95:46:95:50 | query |
|
||||
| mongoose.js:20:19:20:20 | {} | mongoose.js:20:11:20:20 | query |
|
||||
| mongoose.js:21:19:21:26 | req.body | mongoose.js:21:19:21:32 | req.body.title |
|
||||
| mongoose.js:21:19:21:26 | req.body | mongoose.js:21:19:21:32 | req.body.title |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:20:11:20:20 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:20:19:20:20 | {} |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:24:25:24:29 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:27:20:27:24 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:27:20:27:24 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:30:25:30:29 | query |
|
||||
@@ -273,6 +310,24 @@ edges
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:74:16:74:20 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:76:10:76:14 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:76:10:76:14 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:81:46:81:50 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:81:46:81:50 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:82:47:82:51 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:82:47:82:51 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:84:46:84:50 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:84:46:84:50 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:86:51:86:55 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:86:51:86:55 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:88:46:88:50 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:88:46:88:50 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:91:46:91:50 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:91:46:91:50 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:93:51:93:55 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:93:51:93:55 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:95:46:95:50 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:95:46:95:50 | query |
|
||||
| mongoose.js:24:25:24:29 | query | mongoose.js:24:24:24:30 | [query] |
|
||||
| mongoose.js:24:25:24:29 | query | mongoose.js:24:24:24:30 | [query] |
|
||||
| mongooseJsonParse.js:19:11:19:20 | query | mongooseJsonParse.js:23:19:23:23 | query |
|
||||
| mongooseJsonParse.js:19:11:19:20 | query | mongooseJsonParse.js:23:19:23:23 | query |
|
||||
| mongooseJsonParse.js:19:19:19:20 | {} | mongooseJsonParse.js:19:11:19:20 | query |
|
||||
@@ -323,6 +378,7 @@ edges
|
||||
| mongodb.js:77:14:77:26 | { tags: tag } | mongodb.js:70:13:70:25 | req.query.tag | mongodb.js:77:14:77:26 | { tags: tag } | This query depends on $@. | mongodb.js:70:13:70:25 | req.query.tag | a user-provided value |
|
||||
| mongodb.js:85:12:85:24 | { tags: tag } | mongodb.js:70:13:70:25 | req.query.tag | mongodb.js:85:12:85:24 | { tags: tag } | This query depends on $@. | mongodb.js:70:13:70:25 | req.query.tag | a user-provided value |
|
||||
| mongodb_bodySafe.js:29:16:29:20 | query | mongodb_bodySafe.js:24:19:24:33 | req.query.title | mongodb_bodySafe.js:29:16:29:20 | query | This query depends on $@. | mongodb_bodySafe.js:24:19:24:33 | req.query.title | a user-provided value |
|
||||
| mongoose.js:24:24:24:30 | [query] | mongoose.js:21:19:21:26 | req.body | mongoose.js:24:24:24:30 | [query] | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:27:20:27:24 | query | mongoose.js:21:19:21:26 | req.body | 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 | mongoose.js:21:19:21:26 | req.body | 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 | mongoose.js:21:19:21:26 | req.body | mongoose.js:33:24:33:28 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
@@ -343,6 +399,14 @@ edges
|
||||
| mongoose.js:73:7:73:11 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:73:7:73:11 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:74:16:74:20 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:74:16:74:20 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:76:10:76:14 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:76:10:76:14 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:81:46:81:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:81:46:81:50 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:82:47:82:51 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:82:47:82:51 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:84:46:84:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:84:46:84:50 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:86:51:86:55 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:86:51:86:55 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:88:46:88:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:88:46:88:50 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:91:46:91:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:91:46:91:50 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:93:51:93:55 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:93:51:93:55 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:95:46:95:50 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:95:46:95:50 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongooseJsonParse.js:23:19:23:23 | query | mongooseJsonParse.js:20:30:20:43 | req.query.data | mongooseJsonParse.js:23:19:23:23 | query | This query depends on $@. | mongooseJsonParse.js:20:30:20:43 | req.query.data | a user-provided value |
|
||||
| mongooseModelClient.js:11:16:11:24 | { id: v } | mongooseModelClient.js:10:22:10:29 | req.body | mongooseModelClient.js:11:16:11:24 | { id: v } | This query depends on $@. | mongooseModelClient.js:10:22:10:29 | req.body | a user-provided value |
|
||||
| mongooseModelClient.js:12:16:12:34 | { id: req.body.id } | mongooseModelClient.js:12:22:12:29 | req.body | mongooseModelClient.js:12:16:12:34 | { id: req.body.id } | This query depends on $@. | mongooseModelClient.js:12:22:12:29 | req.body | a user-provided value |
|
||||
|
||||
@@ -21,7 +21,7 @@ app.post('/documents/find', (req, res) => {
|
||||
query.title = req.body.title;
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.aggregate('type', query);
|
||||
Document.aggregate([query]);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.count(query);
|
||||
@@ -77,4 +77,23 @@ app.post('/documents/find', (req, res) => {
|
||||
.exec()
|
||||
;
|
||||
|
||||
Mongoose.createConnection(X).count(query); // OK (invalid program)
|
||||
Mongoose.createConnection(X).model(Y).count(query); // NOT OK
|
||||
Mongoose.createConnection(X).models[Y].count(query); // NOT OK
|
||||
|
||||
Document.findOne(X, (err, res) => res.count(query)); // NOT OK
|
||||
Document.findOne(X, (err, res) => err.count(query)); // OK
|
||||
Document.findOne(X).exec((err, res) => res.count(query)); // NOT OK
|
||||
Document.findOne(X).exec((err, res) => err.count(query)); // OK
|
||||
Document.findOne(X).then((res) => res.count(query)); // NOT OK
|
||||
Document.findOne(X).then(Y, (err) => err.count(query)); // OK
|
||||
|
||||
Document.find(X, (err, res) => res[i].count(query)); // NOT OK
|
||||
Document.find(X, (err, res) => err.count(query)); // OK
|
||||
Document.find(X).exec((err, res) => res[i].count(query)); // NOT OK
|
||||
Document.find(X).exec((err, res) => err.count(query)); // OK
|
||||
Document.find(X).then((res) => res[i].count(query)); // NOT OK
|
||||
Document.find(X).then(Y, (err) => err.count(query)); // OK
|
||||
|
||||
Document.count(X, (err, res) => res.count(query)); // OK (res is a number)
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user