mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Merge pull request #3004 from esbena/js/additional-mongodb-and-mongoose-injection-sinks
JS: Mongoose and MongoDB improvements
This commit is contained in:
@@ -23,7 +23,15 @@ private module MongoDB {
|
||||
*/
|
||||
private DataFlow::SourceNode getAMongoClient(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result = mongodb().getAPropertyRead("MongoClient")
|
||||
(
|
||||
result = mongodb().getAPropertyRead("MongoClient")
|
||||
or
|
||||
exists(DataFlow::ParameterNode p |
|
||||
p = result and
|
||||
p = getAMongoDbCallback().getParameter(1) and
|
||||
not p.getName().toLowerCase() = "db" // mongodb v2 provides a `Db` here
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = getAMongoClient(t2).track(t2, t))
|
||||
}
|
||||
@@ -36,7 +44,7 @@ private module MongoDB {
|
||||
/** Gets a data flow node that leads to a `connect` callback. */
|
||||
private DataFlow::SourceNode getAMongoDbCallback(DataFlow::TypeBackTracker t) {
|
||||
t.start() and
|
||||
result = getAMongoClient().getAMemberCall("connect").getArgument(1).getALocalSource()
|
||||
result = getAMongoClient().getAMemberCall("connect").getLastArgument().getALocalSource()
|
||||
or
|
||||
exists(DataFlow::TypeBackTracker t2 | result = getAMongoDbCallback(t2).backtrack(t2, t))
|
||||
}
|
||||
@@ -51,7 +59,15 @@ private module MongoDB {
|
||||
*/
|
||||
private DataFlow::SourceNode getAMongoDb(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result = getAMongoDbCallback().getParameter(1)
|
||||
(
|
||||
exists(DataFlow::ParameterNode p |
|
||||
p = result and
|
||||
p = getAMongoDbCallback().getParameter(1) and
|
||||
not p.getName().toLowerCase() = "client" // mongodb v3 provides a `Mongoclient` here
|
||||
)
|
||||
or
|
||||
result = getAMongoClient().getAMethodCall("db")
|
||||
)
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = getAMongoDb(t2).track(t2, t))
|
||||
}
|
||||
@@ -104,43 +120,71 @@ private module MongoDB {
|
||||
|
||||
QueryCall() {
|
||||
exists(string m | this = getACollection().getAMethodCall(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
|
||||
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
|
||||
CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAQueryArgument() { result = getArgument(queryArgIdx) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides signatures for the Collection methods.
|
||||
*/
|
||||
module CollectionMethodSignatures {
|
||||
/**
|
||||
* Holds if Collection method `name` interprets parameter `n` as a query.
|
||||
*/
|
||||
predicate interpretsArgumentAsQuery(string name, int n) {
|
||||
// FilterQuery
|
||||
(
|
||||
name = "aggregate" and n = 0
|
||||
or
|
||||
name = "count" and n = 0
|
||||
or
|
||||
name = "countDocuments" and n = 0
|
||||
or
|
||||
name = "deleteMany" and n = 0
|
||||
or
|
||||
name = "deleteOne" and n = 0
|
||||
or
|
||||
name = "distinct" and n = 1
|
||||
or
|
||||
name = "find" and n = 0
|
||||
or
|
||||
name = "findOne" and n = 0
|
||||
or
|
||||
name = "findOneAndDelete" and n = 0
|
||||
or
|
||||
name = "findOneAndRemove" and n = 0
|
||||
or
|
||||
name = "findOneAndReplace" and n = 0
|
||||
or
|
||||
name = "findOneAndUpdate" and n = 0
|
||||
or
|
||||
name = "remove" and n = 0
|
||||
or
|
||||
name = "replaceOne" and n = 0
|
||||
or
|
||||
name = "update" and n = 0
|
||||
or
|
||||
name = "updateMany" and n = 0
|
||||
or
|
||||
name = "updateOne" and n = 0
|
||||
)
|
||||
or
|
||||
// UpdateQuery
|
||||
(
|
||||
name = "findOneAndUpdate" and n = 1
|
||||
or
|
||||
name = "update" and n = 1
|
||||
or
|
||||
name = "updateMany" and n = 1
|
||||
or
|
||||
name = "updateOne" and n = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that is interpreted as a MongoDB query.
|
||||
*/
|
||||
@@ -166,10 +210,241 @@ private module Mongoose {
|
||||
}
|
||||
|
||||
/**
|
||||
* A Mongoose collection object.
|
||||
* Provides classes modeling the Mongoose Model class
|
||||
*/
|
||||
class Model extends MongoDB::Collection {
|
||||
Model() { this = getAMongooseInstance().getAMemberCall("model") }
|
||||
module Model {
|
||||
/**
|
||||
* Gets a data flow node referring to a Mongoose Model object.
|
||||
*/
|
||||
private DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
|
||||
(
|
||||
result = getAMongooseInstance().getAMemberCall("model") or
|
||||
result.hasUnderlyingType("mongoose", "Model")
|
||||
) and
|
||||
t.start()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = ref(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data flow node referring to a Mongoose model object.
|
||||
*/
|
||||
DataFlow::SourceNode ref() { result = ref(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/**
|
||||
* Provides signatures for the Model methods.
|
||||
*/
|
||||
module MethodSignatures {
|
||||
/**
|
||||
* Holds if Model method `name` interprets parameter `n` as a query.
|
||||
*/
|
||||
predicate interpretsArgumentAsQuery(string name, int n) {
|
||||
// implement lots of the MongoDB collection interface
|
||||
MongoDB::CollectionMethodSignatures::interpretsArgumentAsQuery(name, n)
|
||||
or
|
||||
name = "findByIdAndUpdate" and n = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if Model method `name` returns a Query.
|
||||
*/
|
||||
predicate returnsQuery(string name) {
|
||||
name = "$where" or
|
||||
name = "count" or
|
||||
name = "countDocuments" or
|
||||
name = "deleteMany" or
|
||||
name = "deleteOne" or
|
||||
name = "find" or
|
||||
name = "findById" or
|
||||
name = "findByIdAndDelete" or
|
||||
name = "findByIdAndRemove" or
|
||||
name = "findByIdAndUpdate" or
|
||||
name = "findOne" or
|
||||
name = "findOneAndDelete" or
|
||||
name = "findOneAndRemove" or
|
||||
name = "findOneAndReplace" or
|
||||
name = "findOneAndUpdate" or
|
||||
name = "geosearch" or
|
||||
name = "replaceOne" or
|
||||
name = "update" or
|
||||
name = "updateMany" or
|
||||
name = "updateOne" or
|
||||
name = "where"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Mongoose query object as a result of a Query constructor invocation.
|
||||
*/
|
||||
class QueryFromConstructor extends DataFlow::NewNode {
|
||||
QueryFromConstructor() {
|
||||
this = getAMongooseInstance().getAPropertyRead("Query").getAnInstantiation()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data flow node referring to a Mongoose query object.
|
||||
*/
|
||||
private DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
|
||||
(
|
||||
result instanceof QueryFromConstructor or
|
||||
result instanceof QueryFromModel or
|
||||
result.hasUnderlyingType("mongoose", "Query")
|
||||
) 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::returnsQuery(name))) and
|
||||
t = t2.continue()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a data flow node referring to a Mongoose query object.
|
||||
*/
|
||||
DataFlow::SourceNode ref() { result = ref(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/**
|
||||
* Provides signatures for the Query methods.
|
||||
*/
|
||||
module MethodSignatures {
|
||||
/**
|
||||
* Holds if Query method `name` interprets parameter `n` as a query.
|
||||
*/
|
||||
predicate interpretsArgumentAsQuery(string name, int n) {
|
||||
n = 0 and
|
||||
(
|
||||
name = "and" or
|
||||
name = "count" or
|
||||
name = "countDocuments" or
|
||||
name = "deleteMany" or
|
||||
name = "deleteOne" or
|
||||
name = "elemMatch" or
|
||||
name = "find" or
|
||||
name = "findOne" or
|
||||
name = "findOneAndDelete" or
|
||||
name = "findOneAndRemove" or
|
||||
name = "findOneAndReplace" or
|
||||
name = "findOneAndUpdate" or
|
||||
name = "merge" or
|
||||
name = "nor" or
|
||||
name = "or" or
|
||||
name = "remove" or
|
||||
name = "replaceOne" or
|
||||
name = "setQuery" or
|
||||
name = "setUpdate" or
|
||||
name = "update" or
|
||||
name = "updateMany" or
|
||||
name = "updateOne" or
|
||||
name = "where"
|
||||
)
|
||||
or
|
||||
n = 1 and
|
||||
(
|
||||
name = "distinct" or
|
||||
name = "findOneAndUpdate" or
|
||||
name = "update" or
|
||||
name = "updateMany" or
|
||||
name = "updateOne"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if Query method `name` returns a Query.
|
||||
*/
|
||||
predicate returnsQuery(string name) {
|
||||
name = "$where" or
|
||||
name = "J" or
|
||||
name = "all" or
|
||||
name = "and" or
|
||||
name = "batchsize" or
|
||||
name = "box" or
|
||||
name = "center" or
|
||||
name = "centerSphere" or
|
||||
name = "circle" or
|
||||
name = "collation" or
|
||||
name = "comment" or
|
||||
name = "count" or
|
||||
name = "countDocuments" or
|
||||
name = "distinct" or
|
||||
name = "elemMatch" or
|
||||
name = "equals" or
|
||||
name = "error" or
|
||||
name = "estimatedDocumentCount" or
|
||||
name = "exists" or
|
||||
name = "explain" or
|
||||
name = "find" or
|
||||
name = "findById" or
|
||||
name = "findOne" or
|
||||
name = "findOneAndRemove" or
|
||||
name = "findOneAndUpdate" or
|
||||
name = "geometry" or
|
||||
name = "get" or
|
||||
name = "gt" or
|
||||
name = "gte" or
|
||||
name = "hint" or
|
||||
name = "in" or
|
||||
name = "intersects" or
|
||||
name = "lean" or
|
||||
name = "limit" or
|
||||
name = "lt" or
|
||||
name = "lte" or
|
||||
name = "map" or
|
||||
name = "map" or
|
||||
name = "maxDistance" or
|
||||
name = "maxTimeMS" or
|
||||
name = "maxscan" or
|
||||
name = "mod" or
|
||||
name = "ne" or
|
||||
name = "near" or
|
||||
name = "nearSphere" or
|
||||
name = "nin" or
|
||||
name = "or" or
|
||||
name = "orFail" or
|
||||
name = "polygon" or
|
||||
name = "populate" or
|
||||
name = "read" or
|
||||
name = "readConcern" or
|
||||
name = "regexp" or
|
||||
name = "remove" or
|
||||
name = "select" or
|
||||
name = "session" or
|
||||
name = "set" or
|
||||
name = "setOptions" or
|
||||
name = "setQuery" or
|
||||
name = "setUpdate" or
|
||||
name = "size" or
|
||||
name = "skip" or
|
||||
name = "slaveOk" or
|
||||
name = "slice" or
|
||||
name = "snapshot" or
|
||||
name = "sort" or
|
||||
name = "update" or
|
||||
name = "w" or
|
||||
name = "where" or
|
||||
name = "within" or
|
||||
name = "wtimeout"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,4 +463,58 @@ private module Mongoose {
|
||||
|
||||
override string getCredentialsKind() { result = kind }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An evaluation of a MongoDB query.
|
||||
*/
|
||||
class MongoDBQueryEvaluation extends DatabaseAccess {
|
||||
DataFlow::MethodCallNode mcn;
|
||||
|
||||
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))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,17 @@ nodes
|
||||
| typedClient.ts:14:24:14:32 | { id: v } |
|
||||
| typedClient.ts:14:24:14:32 | { id: v } |
|
||||
| typedClient.ts:14:30:14:30 | v |
|
||||
| typedClient.ts:21:7:21:32 | v |
|
||||
| typedClient.ts:21:11:21:32 | JSON.pa ... body.x) |
|
||||
| typedClient.ts:21:22:21:29 | req.body |
|
||||
| typedClient.ts:21:22:21:29 | req.body |
|
||||
| typedClient.ts:21:22:21:31 | req.body.x |
|
||||
| typedClient.ts:22:27:22:35 | { id: v } |
|
||||
| typedClient.ts:22:27:22:35 | { id: v } |
|
||||
| typedClient.ts:22:33:22:33 | v |
|
||||
| typedClient.ts:23:27:23:35 | { id: v } |
|
||||
| typedClient.ts:23:27:23:35 | { id: v } |
|
||||
| typedClient.ts:23:33:23:33 | v |
|
||||
edges
|
||||
| typedClient.ts:13:7:13:32 | v | typedClient.ts:14:30:14:30 | v |
|
||||
| typedClient.ts:13:11:13:32 | JSON.pa ... body.x) | typedClient.ts:13:7:13:32 | v |
|
||||
@@ -15,5 +26,17 @@ edges
|
||||
| typedClient.ts:13:22:13:31 | req.body.x | typedClient.ts:13:11:13:32 | JSON.pa ... body.x) |
|
||||
| typedClient.ts:14:30:14:30 | v | typedClient.ts:14:24:14:32 | { id: v } |
|
||||
| typedClient.ts:14:30:14:30 | v | typedClient.ts:14:24:14:32 | { id: v } |
|
||||
| typedClient.ts:21:7:21:32 | v | typedClient.ts:22:33:22:33 | v |
|
||||
| typedClient.ts:21:7:21:32 | v | typedClient.ts:23:33:23:33 | v |
|
||||
| typedClient.ts:21:11:21:32 | JSON.pa ... body.x) | typedClient.ts:21:7:21:32 | v |
|
||||
| typedClient.ts:21:22:21:29 | req.body | typedClient.ts:21:22:21:31 | req.body.x |
|
||||
| typedClient.ts:21:22:21:29 | req.body | typedClient.ts:21:22:21:31 | req.body.x |
|
||||
| typedClient.ts:21:22:21:31 | req.body.x | typedClient.ts:21:11:21:32 | JSON.pa ... body.x) |
|
||||
| typedClient.ts:22:33:22:33 | v | typedClient.ts:22:27:22:35 | { id: v } |
|
||||
| typedClient.ts:22:33:22:33 | v | typedClient.ts:22:27:22:35 | { id: v } |
|
||||
| typedClient.ts:23:33:23:33 | v | typedClient.ts:23:27:23:35 | { id: v } |
|
||||
| typedClient.ts:23:33:23:33 | v | typedClient.ts:23:27:23:35 | { id: v } |
|
||||
#select
|
||||
| typedClient.ts:14:24:14:32 | { id: v } | typedClient.ts:13:22:13:29 | req.body | typedClient.ts:14:24:14:32 | { id: v } | This query depends on $@. | typedClient.ts:13:22:13:29 | req.body | a user-provided value |
|
||||
| typedClient.ts:22:27:22:35 | { id: v } | typedClient.ts:21:22:21:29 | req.body | typedClient.ts:22:27:22:35 | { id: v } | This query depends on $@. | typedClient.ts:21:22:21:29 | req.body | a user-provided value |
|
||||
| typedClient.ts:23:27:23:35 | { id: v } | typedClient.ts:21:22:21:29 | req.body | typedClient.ts:23:27:23:35 | { id: v } | This query depends on $@. | typedClient.ts:21:22:21:29 | req.body | a user-provided value |
|
||||
|
||||
@@ -3,3 +3,11 @@ declare module "mongodb" {
|
||||
find(query: any): any;
|
||||
}
|
||||
}
|
||||
declare module "mongoose" {
|
||||
interface Model {
|
||||
find(query: any): any;
|
||||
}
|
||||
interface Query {
|
||||
find(query: any): any;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as mongodb from "mongodb";
|
||||
|
||||
const express = require('express') as any;
|
||||
const bodyParser = require('body-parser') as any;
|
||||
const express = require("express") as any;
|
||||
const bodyParser = require("body-parser") as any;
|
||||
|
||||
declare function getCollection(): mongodb.Collection;
|
||||
|
||||
@@ -9,7 +9,16 @@ let app = express();
|
||||
|
||||
app.use(bodyParser.json());
|
||||
|
||||
app.post('/find', (req, res) => {
|
||||
app.post("/find", (req, res) => {
|
||||
let v = JSON.parse(req.body.x);
|
||||
getCollection().find({ id: v }); // NOT OK
|
||||
});
|
||||
|
||||
import * as mongoose from "mongoose";
|
||||
declare function getMongooseModel(): mongoose.Model;
|
||||
declare function getMongooseQuery(): mongoose.Query;
|
||||
app.post("/find", (req, res) => {
|
||||
let v = JSON.parse(req.body.x);
|
||||
getMongooseModel().find({ id: v }); // NOT OK
|
||||
getMongooseQuery().find({ id: v }); // NOT OK
|
||||
});
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
| mongodb.js:18:7:18:21 | doc.find(query) |
|
||||
| mongodb.js:21:7:21:48 | doc.fin ... itle }) |
|
||||
| mongodb.js:24:7:24:53 | doc.fin ... r(1) }) |
|
||||
| mongodb.js:29:9:29:34 | doc.fin ... itle }) |
|
||||
| mongodb.js:32:9:32:46 | doc.fin ... tle) }) |
|
||||
| mongodb.js:43:7:43:21 | doc.find(query) |
|
||||
| mongodb.js:54:7:54:21 | doc.find(query) |
|
||||
| mongodb.js:65:3:65:17 | doc.find(query) |
|
||||
| mongodb.js:73:5:77:27 | client\\n ... tag }) |
|
||||
| mongodb.js:81:3:85:25 | importe ... tag }) |
|
||||
| mongodb_bodySafe.js:18:7:18:21 | doc.find(query) |
|
||||
| mongodb_bodySafe.js:29:7:29:21 | doc.find(query) |
|
||||
| mongoose.js:63:2:63:34 | Documen ... then(X) |
|
||||
| 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() |
|
||||
| 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 ... + "'") |
|
||||
| tst3.js:10:3:12:4 | pool.qu ... ts\\n }) |
|
||||
| tst3.js:17:3:19:4 | pool.qu ... ts\\n }) |
|
||||
| tst4.js:8:3:8:67 | db.get( ... + '"') |
|
||||
| tst.js:10:3:10:65 | db.get( ... + '"') |
|
||||
@@ -0,0 +1,3 @@
|
||||
import javascript
|
||||
|
||||
select any(DatabaseAccess a)
|
||||
@@ -20,6 +20,21 @@ nodes
|
||||
| mongodb.js:49:19:49:33 | req.query.title |
|
||||
| mongodb.js:54:16:54:20 | query |
|
||||
| mongodb.js:54:16:54:20 | query |
|
||||
| mongodb.js:59:8:59:17 | query |
|
||||
| mongodb.js:59:16:59:17 | {} |
|
||||
| mongodb.js:60:16:60:30 | req.query.title |
|
||||
| mongodb.js:60:16:60:30 | req.query.title |
|
||||
| mongodb.js:65:12:65:16 | query |
|
||||
| mongodb.js:65:12:65:16 | query |
|
||||
| mongodb.js:70:7:70:25 | tag |
|
||||
| mongodb.js:70:13:70:25 | req.query.tag |
|
||||
| mongodb.js:70:13:70:25 | req.query.tag |
|
||||
| mongodb.js:77:14:77:26 | { tags: tag } |
|
||||
| mongodb.js:77:14:77:26 | { tags: tag } |
|
||||
| mongodb.js:77:22:77:24 | tag |
|
||||
| mongodb.js:85:12:85:24 | { tags: tag } |
|
||||
| mongodb.js:85:12:85:24 | { tags: tag } |
|
||||
| mongodb.js:85:20:85:22 | tag |
|
||||
| mongodb_bodySafe.js:23:11:23:20 | query |
|
||||
| mongodb_bodySafe.js:23:19:23:20 | {} |
|
||||
| mongodb_bodySafe.js:24:19:24:33 | req.query.title |
|
||||
@@ -55,8 +70,22 @@ nodes
|
||||
| mongoose.js:57:21:57:25 | query |
|
||||
| mongoose.js:60:25:60:29 | query |
|
||||
| mongoose.js:60:25:60:29 | query |
|
||||
| mongoose.js:63:24:63:28 | query |
|
||||
| mongoose.js:63:24:63:28 | query |
|
||||
| mongoose.js:63:21:63:25 | query |
|
||||
| mongoose.js:63:21:63:25 | query |
|
||||
| mongoose.js:65:32:65:36 | query |
|
||||
| mongoose.js:65:32:65:36 | query |
|
||||
| mongoose.js:67:27:67:31 | query |
|
||||
| mongoose.js:67:27:67:31 | query |
|
||||
| mongoose.js:68:8:68:12 | query |
|
||||
| mongoose.js:68:8:68:12 | query |
|
||||
| mongoose.js:72:8:72:12 | query |
|
||||
| mongoose.js:72:8:72:12 | query |
|
||||
| mongoose.js:73:7:73:11 | query |
|
||||
| mongoose.js:73:7:73:11 | query |
|
||||
| mongoose.js:74:16:74:20 | query |
|
||||
| mongoose.js:74:16:74:20 | query |
|
||||
| mongoose.js:76:10:76:14 | query |
|
||||
| mongoose.js:76:10:76:14 | query |
|
||||
| mongooseJsonParse.js:19:11:19:20 | query |
|
||||
| mongooseJsonParse.js:19:19:19:20 | {} |
|
||||
| mongooseJsonParse.js:20:19:20:44 | JSON.pa ... y.data) |
|
||||
@@ -129,6 +158,25 @@ edges
|
||||
| mongodb.js:49:19:49:33 | req.query.title | mongodb.js:54:16:54:20 | query |
|
||||
| mongodb.js:49:19:49:33 | req.query.title | mongodb.js:54:16:54:20 | query |
|
||||
| mongodb.js:49:19:49:33 | req.query.title | mongodb.js:54:16:54:20 | query |
|
||||
| mongodb.js:59:8:59:17 | query | mongodb.js:65:12:65:16 | query |
|
||||
| mongodb.js:59:8:59:17 | query | mongodb.js:65:12:65:16 | query |
|
||||
| mongodb.js:59:16:59:17 | {} | mongodb.js:59:8:59:17 | query |
|
||||
| mongodb.js:60:16:60:30 | req.query.title | mongodb.js:59:8:59:17 | query |
|
||||
| mongodb.js:60:16:60:30 | req.query.title | mongodb.js:59:8:59:17 | query |
|
||||
| mongodb.js:60:16:60:30 | req.query.title | mongodb.js:59:16:59:17 | {} |
|
||||
| mongodb.js:60:16:60:30 | req.query.title | mongodb.js:59:16:59:17 | {} |
|
||||
| mongodb.js:60:16:60:30 | req.query.title | mongodb.js:65:12:65:16 | query |
|
||||
| mongodb.js:60:16:60:30 | req.query.title | mongodb.js:65:12:65:16 | query |
|
||||
| mongodb.js:60:16:60:30 | req.query.title | mongodb.js:65:12:65:16 | query |
|
||||
| mongodb.js:60:16:60:30 | req.query.title | mongodb.js:65:12:65:16 | query |
|
||||
| mongodb.js:70:7:70:25 | tag | mongodb.js:77:22:77:24 | tag |
|
||||
| mongodb.js:70:7:70:25 | tag | mongodb.js:85:20:85:22 | tag |
|
||||
| mongodb.js:70:13:70:25 | req.query.tag | mongodb.js:70:7:70:25 | tag |
|
||||
| mongodb.js:70:13:70:25 | req.query.tag | mongodb.js:70:7:70:25 | tag |
|
||||
| mongodb.js:77:22:77:24 | tag | mongodb.js:77:14:77:26 | { tags: tag } |
|
||||
| mongodb.js:77:22:77:24 | tag | mongodb.js:77:14:77:26 | { tags: tag } |
|
||||
| mongodb.js:85:20:85:22 | tag | mongodb.js:85:12:85:24 | { tags: tag } |
|
||||
| mongodb.js:85:20:85:22 | tag | mongodb.js:85:12:85:24 | { tags: tag } |
|
||||
| mongodb_bodySafe.js:23:11:23:20 | query | mongodb_bodySafe.js:29:16:29:20 | query |
|
||||
| mongodb_bodySafe.js:23:11:23:20 | query | mongodb_bodySafe.js:29:16:29:20 | query |
|
||||
| mongodb_bodySafe.js:23:19:23:20 | {} | mongodb_bodySafe.js:23:11:23:20 | query |
|
||||
@@ -164,8 +212,22 @@ edges
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:57:21:57:25 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:60:25:60:29 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:60:25:60:29 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:63:24:63:28 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:63:24:63:28 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:63:21:63:25 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:63:21:63:25 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:65:32:65:36 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:65:32:65:36 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:67:27:67:31 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:67:27:67:31 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:68:8:68:12 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:68:8:68:12 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:72:8:72:12 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:72:8:72:12 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:73:7:73:11 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:73:7:73:11 | query |
|
||||
| mongoose.js:20:11:20:20 | query | mongoose.js:74:16:74:20 | query |
|
||||
| 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: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 |
|
||||
@@ -195,8 +257,22 @@ edges
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:57:21:57:25 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:60:25:60:29 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:60:25:60:29 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:63:24:63:28 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:63:24:63:28 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:63:21:63:25 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:63:21:63:25 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:65:32:65:36 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:65:32:65:36 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:67:27:67:31 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:67:27:67:31 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:68:8:68:12 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:68:8:68:12 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:72:8:72:12 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:72:8:72:12 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:73:7:73:11 | query |
|
||||
| mongoose.js:21:19:21:32 | req.body.title | mongoose.js:73:7:73:11 | query |
|
||||
| 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: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 |
|
||||
| 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 |
|
||||
@@ -243,6 +319,9 @@ edges
|
||||
| mongodb.js:18:16:18:20 | query | mongodb.js:13:19:13:26 | req.body | 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:32:18:32:45 | { title ... itle) } | mongodb.js:26:19:26:26 | req.body | mongodb.js:32:18:32:45 | { title ... itle) } | This query depends on $@. | mongodb.js:26:19:26:26 | req.body | a user-provided value |
|
||||
| mongodb.js:54:16:54:20 | query | mongodb.js:49:19:49:33 | req.query.title | mongodb.js:54:16:54:20 | query | This query depends on $@. | mongodb.js:49:19:49:33 | req.query.title | a user-provided value |
|
||||
| mongodb.js:65:12:65:16 | query | mongodb.js:60:16:60:30 | req.query.title | mongodb.js:65:12:65:16 | query | This query depends on $@. | mongodb.js:60:16:60:30 | req.query.title | a user-provided value |
|
||||
| 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: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 |
|
||||
@@ -256,7 +335,14 @@ edges
|
||||
| mongoose.js:54:25:54:29 | query | mongoose.js:21:19:21:26 | req.body | 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 | mongoose.js:21:19:21:26 | req.body | 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 | mongoose.js:21:19:21:26 | req.body | 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 | mongoose.js:21:19:21:26 | req.body | mongoose.js:63:24:63:28 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:63:21:63:25 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:63:21:63:25 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:65:32:65:36 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:65:32:65:36 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:67:27:67:31 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:67:27:67:31 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:68:8:68:12 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:68:8:68:12 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| mongoose.js:72:8:72:12 | query | mongoose.js:21:19:21:26 | req.body | mongoose.js:72:8:72:12 | query | This query depends on $@. | mongoose.js:21:19:21:26 | req.body | a user-provided value |
|
||||
| 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 |
|
||||
| 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 |
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
let dbClient = require("mongodb").MongoClient,
|
||||
db = null;
|
||||
module.exports = {
|
||||
db: () => {
|
||||
return db;
|
||||
},
|
||||
connect: fn => {
|
||||
dbClient.connect(process.env.DB_URL, {}, (err, client) => {
|
||||
db = client.db(process.env.DB_NAME);
|
||||
return fn(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -54,3 +54,33 @@ app.post('/documents/find', (req, res) => {
|
||||
doc.find(query);
|
||||
});
|
||||
});
|
||||
|
||||
app.post('/documents/find', (req, res) => {
|
||||
const query = {};
|
||||
query.title = req.query.title;
|
||||
MongoClient.connect('mongodb://localhost:27017/test', (err, client) => {
|
||||
let doc = client.db("MASTER").collection('doc');
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
doc.find(query);
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/logs/count-by-tag", (req, res) => {
|
||||
let tag = req.query.tag;
|
||||
|
||||
MongoClient.connect(process.env.DB_URL, {}, (err, client) => {
|
||||
client
|
||||
.db(process.env.DB_NAME)
|
||||
.collection("logs")
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
.count({ tags: tag });
|
||||
});
|
||||
|
||||
let importedDbo = require("./dbo.js");
|
||||
importedDbo
|
||||
.db()
|
||||
.collection("logs")
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
.count({ tags: tag });
|
||||
});
|
||||
|
||||
@@ -60,6 +60,21 @@ app.post('/documents/find', (req, res) => {
|
||||
Document.updateMany(query);
|
||||
|
||||
// NOT OK: query is tainted by user-provided object value
|
||||
Document.updateOne(query);
|
||||
});
|
||||
Document.updateOne(query).then(X);
|
||||
|
||||
Document.findByIdAndUpdate(X, query, function(){}); // NOT OK
|
||||
|
||||
new Mongoose.Query(X, Y, query) // NOT OK
|
||||
.and(query, function(){}) // NOT OK
|
||||
;
|
||||
|
||||
Document.where(query) // NOT OK
|
||||
.and(query) // NOT OK
|
||||
.or(query) // NOT OK
|
||||
.distinct(X, query) // NOT OK
|
||||
.comment(query) // OK
|
||||
.count(query) // NOT OK
|
||||
.exec()
|
||||
;
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user