@@ -429,6 +429,11 @@ private module Mongoose {
429429 )
430430 }
431431
432+ /**
433+ * Gets a data flow node referring to a Mongoose query object.
434+ */
435+ private DataFlow:: SourceNode getAQuery ( ) { result = getAQuery ( DataFlow:: TypeTracker:: end ( ) ) }
436+
432437 /**
433438 * An expression passed to `mongoose.createConnection` to supply credentials.
434439 */
@@ -460,9 +465,43 @@ private module Mongoose {
460465 this = any ( QueryFromConstructor c ) .getArgument ( 2 ) .asExpr ( )
461466 or
462467 exists ( string method , int n | QueryMethodSignatures:: interpretsArgumentAsQuery ( method , n ) |
463- this =
464- getAQuery ( DataFlow:: TypeTracker:: end ( ) ) .getAMethodCall ( method ) .getArgument ( n ) .asExpr ( )
468+ this = getAQuery ( ) .getAMethodCall ( method ) .getArgument ( n ) .asExpr ( )
465469 )
466470 }
467471 }
472+
473+ /**
474+ * An evaluation of a MongoDB query.
475+ */
476+ class MongoDBQueryEvaluation extends DatabaseAccess {
477+ DataFlow:: MethodCallNode mcn ;
478+
479+ MongoDBQueryEvaluation ( ) {
480+ this = mcn and
481+ (
482+ exists ( Model m , string method |
483+ ModelMethodSignatures:: returnsQuery ( method ) and
484+ mcn = m .ref ( ) .getAMethodCall ( method ) and
485+ // callback provided to a Model method call
486+ exists ( mcn .getCallback ( mcn .getNumArgument ( ) - 1 ) )
487+ )
488+ or
489+ getAQuery ( ) .getAMethodCall ( ) = mcn and
490+ (
491+ // explicit execution using a Query method call
492+ exists ( string executor | executor = "exec" or executor = "then" or executor = "catch" |
493+ mcn .getMethodName ( ) = executor
494+ )
495+ or
496+ // callback provided to a Query method call
497+ exists ( mcn .getCallback ( mcn .getNumArgument ( ) - 1 ) )
498+ )
499+ )
500+ }
501+
502+ override DataFlow:: Node getAQueryArgument ( ) {
503+ // NB: this does not account for all of the chained calls leading to this execution
504+ mcn .getAnArgument ( ) .asExpr ( ) .( MongoDBQueryPart ) .flow ( ) = result
505+ }
506+ }
468507}
0 commit comments