From a03e6a800dbc52342358f5da6dc5bf54a725ea41 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 14:31:00 +0200 Subject: [PATCH 01/39] deprecate the HTTP `flowsTo` predicates to avoid confusion with `SourceNode::flowsTo` --- .../ql/lib/semmle/javascript/frameworks/Connect.qll | 2 +- .../ql/lib/semmle/javascript/frameworks/Express.qll | 11 +++++++---- .../ql/lib/semmle/javascript/frameworks/HTTP.qll | 6 +++++- .../ql/lib/semmle/javascript/frameworks/Hapi.qll | 2 +- .../ql/lib/semmle/javascript/frameworks/Koa.qll | 6 ++---- .../ql/lib/semmle/javascript/frameworks/NodeJSLib.qll | 4 ++-- .../ql/lib/semmle/javascript/frameworks/Restify.qll | 2 +- .../TemplateObjectInjectionCustomizations.qll | 8 ++++---- 8 files changed, 23 insertions(+), 18 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll b/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll index 06138746fa61..5735ac5eb219 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll @@ -66,7 +66,7 @@ module Connect { getMethodName() = "use" and ( // app.use(fun) - server.flowsTo(getReceiver()) + server.ref().flowsToExpr(getReceiver()) or // app.use(...).use(fun) this.getReceiver().(RouteSetup).getServer() = server diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 196165307631..466448071bf1 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -43,7 +43,7 @@ module Express { /** * Holds if `e` may refer to the given `router` object. */ - private predicate isRouter(Expr e, RouterDefinition router) { router.flowsTo(e) } + private predicate isRouter(Expr e, RouterDefinition router) { router.ref().flowsToExpr(e) } // TODO: DataFlow::Node /** * Holds if `e` may refer to a router object. @@ -853,21 +853,24 @@ module Express { DataFlow::SourceNode ref() { result = this.ref(DataFlow::TypeTracker::end()) } /** + * DEPRECATED: Use `ref().flowsToExpr()` instead. * Holds if `sink` may refer to this router. */ - predicate flowsTo(Expr sink) { this.ref().flowsToExpr(sink) } + deprecated predicate flowsTo(Expr sink) { this.ref().flowsToExpr(sink) } /** * Gets a `RouteSetup` that was used for setting up a route on this router. */ - private RouteSetup getARouteSetup() { this.flowsTo(result.getReceiver()) } + private RouteSetup getARouteSetup() { this.ref().flowsToExpr(result.getReceiver()) } /** * Gets a sub-router registered on this router. * * Example: `router2` for `router1.use(router2)` or `router1.use("/route2", router2)` */ - RouterDefinition getASubRouter() { result.flowsTo(this.getARouteSetup().getAnArgument()) } + RouterDefinition getASubRouter() { + result.ref().flowsToExpr(this.getARouteSetup().getAnArgument()) + } /** * Gets a route handler registered on this router. diff --git a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll index f82b46506682..a489be4f3992 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll @@ -272,10 +272,14 @@ module HTTP { exists(DataFlow::TypeTracker t2 | result = this.ref(t2).track(t2, t)) } + /** Gets a data flow node referring to this server. */ + DataFlow::SourceNode ref() { result = this.ref(DataFlow::TypeTracker::end()) } + /** + * DEPRECATED: Use `ref().flowsToExpr()` instead. * Holds if `sink` may refer to this server definition. */ - predicate flowsTo(Expr sink) { this.ref(DataFlow::TypeTracker::end()).flowsToExpr(sink) } + deprecated predicate flowsTo(Expr sink) { this.ref().flowsToExpr(sink) } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll index b83b85831c7d..cddfc61d81b3 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll @@ -189,7 +189,7 @@ module Hapi { Expr handler; RouteSetup() { - server.flowsTo(getReceiver()) and + server.ref().flowsToExpr(getReceiver()) and ( // server.route({ handler: fun }) getMethodName() = "route" and diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll index f9519736b0e4..4fac49f81750 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll @@ -118,8 +118,6 @@ module Koa { */ RouteHandler getRouteHandler() { result = rh } - predicate flowsTo(DataFlow::Node nd) { this.ref().flowsTo(nd) } - private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { t.start() and result = this @@ -258,7 +256,7 @@ module Koa { class ContextExpr extends Expr { ContextSource src; - ContextExpr() { src.flowsTo(DataFlow::valueNode(this)) } + ContextExpr() { src.ref().flowsTo(DataFlow::valueNode(this)) } /** * Gets the route handler that provides this response. @@ -390,7 +388,7 @@ module Koa { RouteSetup() { // app.use(fun) - server.flowsTo(this.getReceiver()) and + server.ref().flowsToExpr(this.getReceiver()) and this.getMethodName() = "use" } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll index 5bd92e3ec5c6..0f18c18e13aa 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll @@ -221,10 +221,10 @@ module NodeJSLib { Expr handler; RouteSetup() { - server.flowsTo(this) and + server.ref().flowsToExpr(this) and handler = this.getLastArgument() or - server.flowsTo(this.getReceiver()) and + server.ref().flowsToExpr(this.getReceiver()) and this.(MethodCallExpr).getMethodName().regexpMatch("on(ce)?") and this.getArgument(0).getStringValue() = "request" and handler = this.getArgument(1) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll b/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll index f83f2930f51f..8d6e5acdd833 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll @@ -144,7 +144,7 @@ module Restify { RouteSetup() { // server.get('/', fun) // server.head('/', fun) - server.flowsTo(getReceiver()) and + server.ref().flowsToExpr(getReceiver()) and getMethodName() = any(HTTP::RequestMethodName m).toLowerCase() } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/TemplateObjectInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/TemplateObjectInjectionCustomizations.qll index 06008a0266de..6191c3898731 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/TemplateObjectInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/TemplateObjectInjectionCustomizations.qll @@ -76,8 +76,8 @@ module TemplateObjectInjection { predicate usesVulnerableTemplateEngine(Express::RouterDefinition router) { // option 1: `app.set("view engine", "theEngine")`. // Express will load the engine automatically. - exists(MethodCallExpr call | - router.flowsTo(call.getReceiver()) and + exists(DataFlow::MethodCallNode call | + router.ref().getAMethodCall() = call and call.getMethodName() = "set" and call.getArgument(0).getStringValue() = "view engine" and call.getArgument(1).getStringValue() = getAVulnerableTemplateEngine() @@ -91,11 +91,11 @@ module TemplateObjectInjection { DataFlow::MethodCallNode viewEngineCall | // `app.engine("name", engine) - router.flowsTo(registerCall.getReceiver().asExpr()) and + router.ref().getAMethodCall() = registerCall and registerCall.getMethodName() = ["engine", "register"] and engine = registerCall.getArgument(1).getALocalSource() and // app.set("view engine", "name") - router.flowsTo(viewEngineCall.getReceiver().asExpr()) and + router.ref().getAMethodCall() = viewEngineCall and viewEngineCall.getMethodName() = "set" and viewEngineCall.getArgument(0).getStringValue() = "view engine" and // The name set by the `app.engine("name")` call matches `app.set("view engine", "name")`. From d4ccc75ce16331f1213dc5587d1ea53970fb99ad Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 12:31:39 +0200 Subject: [PATCH 02/39] refactor RedirectInvocation to a DataFlow::Node --- .../ql/lib/semmle/javascript/frameworks/Express.qll | 6 +++--- .../ql/lib/semmle/javascript/frameworks/Fastify.qll | 8 +++----- javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll | 4 ++-- javascript/ql/lib/semmle/javascript/frameworks/Koa.qll | 8 +++++--- .../dataflow/ServerSideUrlRedirectCustomizations.qll | 4 ++-- .../library-tests/frameworks/koa/RedirectInvocation.qll | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 466448071bf1..d0e604cb96e7 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -697,12 +697,12 @@ module Express { /** * An invocation of the `redirect` method of an HTTP response object. */ - private class RedirectInvocation extends HTTP::RedirectInvocation, MethodCallExpr { + private class RedirectInvocation extends HTTP::RedirectInvocation, DataFlow::MethodCallNode { ResponseSource response; - RedirectInvocation() { this = response.ref().getAMethodCall("redirect").asExpr() } + RedirectInvocation() { this = response.ref().getAMethodCall("redirect") } - override Expr getUrlArgument() { result = this.getLastArgument() } + override DataFlow::Node getUrlArgument() { result = this.getLastArgument() } override RouteHandler getRouteHandler() { result = response.getRouteHandler() } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll index 000015191f8a..1fd97239d705 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll @@ -351,14 +351,12 @@ module Fastify { /** * An invocation of the `redirect` method of an HTTP response object. */ - private class RedirectInvocation extends HTTP::RedirectInvocation, MethodCallExpr { + private class RedirectInvocation extends HTTP::RedirectInvocation, DataFlow::MethodCallNode { RouteHandler rh; - RedirectInvocation() { - this = rh.getAResponseSource().ref().getAMethodCall("redirect").asExpr() - } + RedirectInvocation() { this = rh.getAResponseSource().ref().getAMethodCall("redirect") } - override Expr getUrlArgument() { result = this.getLastArgument() } + override DataFlow::Node getUrlArgument() { result = this.getLastArgument() } override RouteHandler getRouteHandler() { result = rh } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll index a489be4f3992..e2b114a87bae 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll @@ -12,9 +12,9 @@ module HTTP { /** * A function invocation that causes a redirect response to be sent. */ - abstract class RedirectInvocation extends InvokeExpr { + abstract class RedirectInvocation extends DataFlow::CallNode { /** Gets the argument specifying the URL to redirect to. */ - abstract Expr getUrlArgument(); + abstract DataFlow::Node getUrlArgument(); /** Gets the route handler this redirect occurs in. */ abstract RouteHandler getRouteHandler(); diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll index 4fac49f81750..3f746f2c18d6 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll @@ -422,12 +422,14 @@ module Koa { /** * An invocation of the `redirect` method of an HTTP response object. */ - private class RedirectInvocation extends HTTP::RedirectInvocation, MethodCallExpr { + private class RedirectInvocation extends HTTP::RedirectInvocation, DataFlow::MethodCallNode { RouteHandler rh; - RedirectInvocation() { this.(MethodCallExpr).calls(rh.getAResponseOrContextExpr(), "redirect") } + RedirectInvocation() { + this.asExpr().(MethodCallExpr).calls(rh.getAResponseOrContextExpr(), "redirect") + } // TODO: Improve this. - override Expr getUrlArgument() { result = this.getArgument(0) } + override DataFlow::Node getUrlArgument() { result = this.getArgument(0) } override RouteHandler getRouteHandler() { result = rh } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll index e8511ee1f5a2..643a509b2f8a 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll @@ -33,8 +33,8 @@ module ServerSideUrlRedirect { /** * An HTTP redirect, considered as a sink for `Configuration`. */ - class RedirectSink extends Sink, DataFlow::ValueNode { - RedirectSink() { astNode = any(HTTP::RedirectInvocation redir).getUrlArgument() } + class RedirectSink extends Sink { + RedirectSink() { this = any(HTTP::RedirectInvocation redir).getUrlArgument() } } /** diff --git a/javascript/ql/test/library-tests/frameworks/koa/RedirectInvocation.qll b/javascript/ql/test/library-tests/frameworks/koa/RedirectInvocation.qll index 8648d75eb636..c6d46ef8a022 100644 --- a/javascript/ql/test/library-tests/frameworks/koa/RedirectInvocation.qll +++ b/javascript/ql/test/library-tests/frameworks/koa/RedirectInvocation.qll @@ -1,7 +1,7 @@ import javascript query predicate test_RedirectInvocation( - HTTP::RedirectInvocation redirect, Expr url, HTTP::RouteHandler rh + HTTP::RedirectInvocation redirect, DataFlow::Node url, HTTP::RouteHandler rh ) { redirect.getUrlArgument() = url and redirect.getRouteHandler() = rh From ce0175a046662d46bf6e629f2340196e0b9ad0ef Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 12:45:44 +0200 Subject: [PATCH 03/39] don't use `astNode` in `StandardHeaderDefinition` --- .../semmle/javascript/frameworks/Express.qll | 20 ++++++++------- .../semmle/javascript/frameworks/Fastify.qll | 4 +-- .../lib/semmle/javascript/frameworks/HTTP.qll | 25 +++++++++++-------- .../lib/semmle/javascript/frameworks/Hapi.qll | 4 ++- .../lib/semmle/javascript/frameworks/Koa.qll | 5 ++-- .../javascript/frameworks/NodeJSLib.qll | 12 ++++----- .../semmle/javascript/frameworks/Restify.qll | 10 +++++--- .../RemotePropertyInjectionCustomizations.qll | 4 +-- 8 files changed, 49 insertions(+), 35 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index d0e604cb96e7..21b5f6f41178 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -674,12 +674,12 @@ module Express { /** * Holds if `e` is an HTTP request object. */ - predicate isRequest(Expr e) { any(RouteHandler rh).getARequestExpr() = e } + predicate isRequest(Expr e) { any(RouteHandler rh).getARequestExpr() = e } // TODO: DataFlow::Node /** * Holds if `e` is an HTTP response object. */ - predicate isResponse(Expr e) { any(RouteHandler rh).getAResponseExpr() = e } + predicate isResponse(Expr e) { any(RouteHandler rh).getAResponseExpr() = e } // TODO: DataFlow::Node /** * An access to the HTTP request body. @@ -689,9 +689,11 @@ module Express { } abstract private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { - HeaderDefinition() { isResponse(astNode.getReceiver()) } + HeaderDefinition() { isResponse(this.getReceiver().asExpr()) } - override RouteHandler getRouteHandler() { astNode.getReceiver() = result.getAResponseExpr() } + override RouteHandler getRouteHandler() { + this.getReceiver().asExpr() = result.getAResponseExpr() + } } /** @@ -713,8 +715,8 @@ module Express { */ private class SetOneHeader extends HeaderDefinition { SetOneHeader() { - astNode.getMethodName() = any(string n | n = "set" or n = "header") and - astNode.getNumArgument() = 2 + this.getMethodName() = any(string n | n = "set" or n = "header") and + this.getNumArgument() = 2 } } @@ -744,9 +746,9 @@ module Express { override RouteHandler getRouteHandler() { result = response.getRouteHandler() } - override Expr getNameExpr() { + override DataFlow::Node getNameNode() { exists(DataFlow::PropWrite write | this.getAHeaderSource().getAPropertyWrite() = write | - result = write.getPropertyNameExpr() + result = write.getPropertyNameExpr().flow() ) } } @@ -755,7 +757,7 @@ module Express { * An invocation of the `append` method on an HTTP response object. */ private class AppendHeader extends HeaderDefinition { - AppendHeader() { astNode.getMethodName() = "append" } + AppendHeader() { this.getMethodName() = "append" } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll index 1fd97239d705..9c8577d4e628 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll @@ -401,9 +401,9 @@ module Fastify { override RouteHandler getRouteHandler() { result = rh } - override Expr getNameExpr() { + override DataFlow::Node getNameNode() { exists(DataFlow::PropWrite write | this.getAHeaderSource().getAPropertyWrite() = write | - result = write.getPropertyNameExpr() + result = write.getPropertyNameExpr().flow() ) } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll index e2b114a87bae..2a898738be34 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll @@ -68,12 +68,16 @@ module HTTP { /** * Holds if the header with (lower-case) name `headerName` is set to the value of `headerValue`. */ - abstract predicate definesExplicitly(string headerName, Expr headerValue); + abstract predicate definesExplicitly(string headerName, Expr headerValue); // TODO: DataFlow::Node. /** + * DEPRECATED: Use `getNameNode()` instead. * Returns the expression used to compute the header name. */ - abstract Expr getNameExpr(); + deprecated Expr getNameExpr() { result = this.getNameNode().asExpr() } + + /** Returns the expression used to compute the header name. */ + abstract DataFlow::Node getNameNode(); } /** @@ -201,13 +205,13 @@ module HTTP { * Gets an expression that contains a request object handled * by this handler. */ - RequestExpr getARequestExpr() { result.getRouteHandler() = this } + RequestExpr getARequestExpr() { result.getRouteHandler() = this } // TODO: DataFlow::Node /** * Gets an expression that contains a response object provided * by this handler. */ - ResponseExpr getAResponseExpr() { result.getRouteHandler() = this } + ResponseExpr getAResponseExpr() { result.getRouteHandler() = this } // TODO: DataFlow::Node } /** @@ -238,6 +242,7 @@ module HTTP { * An expression that may contain a request object. */ abstract class RequestExpr extends Expr { + // TODO: DataFlow::Node /** * Gets the route handler that handles this request. */ @@ -248,6 +253,7 @@ module HTTP { * An expression that may contain a response object. */ abstract class ResponseExpr extends Expr { + // TODO: DataFlow::Node /** * Gets the route handler that handles this request. */ @@ -376,15 +382,14 @@ module HTTP { /** * A standard header definition. */ - abstract class StandardHeaderDefinition extends ExplicitHeaderDefinition, DataFlow::ValueNode { - override MethodCallExpr astNode; - + abstract class StandardHeaderDefinition extends ExplicitHeaderDefinition, + DataFlow::MethodCallNode { override predicate definesExplicitly(string headerName, Expr headerValue) { - headerName = this.getNameExpr().getStringValue().toLowerCase() and - headerValue = astNode.getArgument(1) + headerName = this.getNameNode().getStringValue().toLowerCase() and + headerValue = this.getArgument(1).asExpr() } - override Expr getNameExpr() { result = astNode.getArgument(0) } + override DataFlow::Node getNameNode() { result = this.getArgument(0) } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll index cddfc61d81b3..2b5e5bc6aefb 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll @@ -74,6 +74,7 @@ module Hapi { override RouteHandler getRouteHandler() { result = rh } } + // TODO: DataFlow::Node /** * A Hapi response expression. */ @@ -81,6 +82,7 @@ module Hapi { override ResponseSource src; } + // TODO: DataFlow::Node /** * An Hapi request expression. */ @@ -175,7 +177,7 @@ module Hapi { HeaderDefinition() { // request.response.header('Cache-Control', 'no-cache') - astNode.calls(res, "header") + this.calls(res.flow(), "header") } override RouteHandler getRouteHandler() { result = res.getRouteHandler() } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll index 3f746f2c18d6..b43dafa2c499 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll @@ -24,10 +24,10 @@ module Koa { HeaderDefinition() { // ctx.set('Cache-Control', 'no-cache'); - astNode.calls(rh.getAResponseOrContextExpr(), "set") + this.calls(rh.getAResponseOrContextExpr().flow(), "set") or // ctx.response.header('Cache-Control', 'no-cache') - astNode.calls(rh.getAResponseExpr(), "header") + this.calls(rh.getAResponseExpr().flow(), "header") } override RouteHandler getRouteHandler() { result = rh } @@ -59,6 +59,7 @@ module Koa { * object of a route handler invocation. */ Expr getAResponseOrContextExpr() { + // TODO: DataFlow::Node result = this.getAResponseExpr() or result = this.getAContextExpr() } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll index 0f18c18e13aa..5836ff829cb1 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll @@ -259,7 +259,7 @@ module NodeJSLib { abstract private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { ResponseExpr r; - HeaderDefinition() { astNode.getReceiver() = r } + HeaderDefinition() { this.getReceiver().asExpr() = r } override HTTP::RouteHandler getRouteHandler() { result = r.getRouteHandler() } } @@ -268,7 +268,7 @@ module NodeJSLib { * A call to the `setHeader` method of an HTTP response. */ private class SetHeader extends HeaderDefinition { - SetHeader() { astNode.getMethodName() = "setHeader" } + SetHeader() { this.getMethodName() = "setHeader" } } /** @@ -276,14 +276,14 @@ module NodeJSLib { */ private class WriteHead extends HeaderDefinition { WriteHead() { - astNode.getMethodName() = "writeHead" and - astNode.getNumArgument() >= 1 + this.getMethodName() = "writeHead" and + this.getNumArgument() >= 1 } override predicate definesExplicitly(string headerName, Expr headerValue) { - astNode.getNumArgument() > 1 and + this.getNumArgument() > 1 and exists(DataFlow::SourceNode headers, string header | - headers.flowsToExpr(astNode.getLastArgument()) and + headers.flowsTo(this.getLastArgument()) and headers.hasPropertyWrite(header, DataFlow::valueNode(headerValue)) and headerName = header.toLowerCase() ) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll b/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll index 8d6e5acdd833..4c319f17bfea 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll @@ -68,6 +68,7 @@ module Restify { override RouteHandler getRouteHandler() { result = rh } } + // TODO: DataFlow::Node /** * A Node.js HTTP response provided by Restify. */ @@ -75,6 +76,7 @@ module Restify { ResponseExpr() { src instanceof ResponseSource } } + // TODO: DataFlow::Node /** * A Node.js HTTP request provided by Restify. */ @@ -128,11 +130,13 @@ module Restify { private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { HeaderDefinition() { // response.header('Cache-Control', 'no-cache') - astNode.getReceiver() instanceof ResponseExpr and - astNode.getMethodName() = "header" + this.getReceiver().asExpr() instanceof ResponseExpr and + this.getMethodName() = "header" } - override RouteHandler getRouteHandler() { astNode.getReceiver() = result.getAResponseExpr() } + override RouteHandler getRouteHandler() { + this.getReceiver().asExpr() = result.getAResponseExpr() + } } /** diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/RemotePropertyInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/RemotePropertyInjectionCustomizations.qll index 8281a958142b..d060f91b371e 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/RemotePropertyInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/RemotePropertyInjectionCustomizations.qll @@ -57,11 +57,11 @@ module RemotePropertyInjection { * header names as properties. This case is already handled by * `PropertyWriteSink`. */ - class HeaderNameSink extends Sink, DataFlow::ValueNode { + class HeaderNameSink extends Sink { HeaderNameSink() { exists(HTTP::ExplicitHeaderDefinition hd | not hd instanceof Express::SetMultipleHeaders and - astNode = hd.getNameExpr() + this = hd.getNameNode() ) } From 19e808186dd522b43954379166f4d40df1ace9e9 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 12:56:22 +0200 Subject: [PATCH 04/39] refactor `definesExplicitly` to use DataFlow::Node --- .../semmle/javascript/frameworks/Express.qll | 4 +-- .../semmle/javascript/frameworks/Fastify.qll | 4 +-- .../lib/semmle/javascript/frameworks/HTTP.qll | 27 ++++++++++++------- .../javascript/frameworks/NodeJSLib.qll | 4 +-- ...figurationForCredentialsCustomizations.qll | 6 ++--- .../ServerSideUrlRedirectCustomizations.qll | 4 +-- .../Express/HeaderDefinition_getNameExpr.qll | 6 +++-- 7 files changed, 32 insertions(+), 23 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 21b5f6f41178..18fff6d622e8 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -737,9 +737,9 @@ module Express { */ private DataFlow::SourceNode getAHeaderSource() { result.flowsTo(this.getArgument(0)) } - override predicate definesExplicitly(string headerName, Expr headerValue) { + override predicate definesHeaderValue(string headerName, DataFlow::Node headerValue) { exists(string header | - this.getAHeaderSource().hasPropertyWrite(header, DataFlow::valueNode(headerValue)) and + this.getAHeaderSource().hasPropertyWrite(header, headerValue) and headerName = header.toLowerCase() ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll index 9c8577d4e628..00b2d280c52b 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll @@ -392,9 +392,9 @@ module Fastify { */ private DataFlow::SourceNode getAHeaderSource() { result.flowsTo(this.getArgument(0)) } - override predicate definesExplicitly(string headerName, Expr headerValue) { + override predicate definesHeaderValue(string headerName, DataFlow::Node headerValue) { exists(string header | - this.getAHeaderSource().hasPropertyWrite(header, headerValue.flow()) and + this.getAHeaderSource().hasPropertyWrite(header, headerValue) and headerName = header.toLowerCase() ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll index 2a898738be34..e096ac7a5b96 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll @@ -56,19 +56,25 @@ module HTTP { * An expression that sets HTTP response headers explicitly. */ abstract class ExplicitHeaderDefinition extends HeaderDefinition { - override string getAHeaderName() { this.definesExplicitly(result, _) } + override string getAHeaderName() { this.definesHeaderValue(result, _) } override predicate defines(string headerName, string headerValue) { - exists(Expr e | - this.definesExplicitly(headerName, e) and + exists(DataFlow::Node e | + this.definesHeaderValue(headerName, e) and headerValue = e.getStringValue() ) } /** + * DEPRECATED: use `definesHeaderValue` instead. * Holds if the header with (lower-case) name `headerName` is set to the value of `headerValue`. */ - abstract predicate definesExplicitly(string headerName, Expr headerValue); // TODO: DataFlow::Node. + deprecated predicate definesExplicitly(string headerName, Expr headerValue) { + this.definesHeaderValue(headerName, headerValue.flow()) + } + + /** Holds if the header with (lower-case) name `headerName` is set to the value of `headerValue`. */ + abstract predicate definesHeaderValue(string headerName, DataFlow::Node headerValue); /** * DEPRECATED: Use `getNameNode()` instead. @@ -128,20 +134,21 @@ module HTTP { * An expression that sets a cookie in an HTTP response. */ abstract class CookieDefinition extends Expr { + // TODO: DataFlow::Node /** * Gets the argument, if any, specifying the raw cookie header. */ - Expr getHeaderArgument() { none() } + Expr getHeaderArgument() { none() } // TODO: DataFlow::Node /** * Gets the argument, if any, specifying the cookie name. */ - Expr getNameArgument() { none() } + Expr getNameArgument() { none() } // TODO: DataFlow::Node /** * Gets the argument, if any, specifying the cookie value. */ - Expr getValueArgument() { none() } + Expr getValueArgument() { none() } // TODO: DataFlow::Node /** Gets the route handler that sets this cookie. */ abstract RouteHandler getRouteHandler(); @@ -159,7 +166,7 @@ module HTTP { } override Expr getHeaderArgument() { - header.(ExplicitHeaderDefinition).definesExplicitly("set-cookie", result) + header.(ExplicitHeaderDefinition).definesHeaderValue("set-cookie", result.flow()) } override RouteHandler getRouteHandler() { result = header.getRouteHandler() } @@ -384,9 +391,9 @@ module HTTP { */ abstract class StandardHeaderDefinition extends ExplicitHeaderDefinition, DataFlow::MethodCallNode { - override predicate definesExplicitly(string headerName, Expr headerValue) { + override predicate definesHeaderValue(string headerName, DataFlow::Node headerValue) { headerName = this.getNameNode().getStringValue().toLowerCase() and - headerValue = this.getArgument(1).asExpr() + headerValue = this.getArgument(1) } override DataFlow::Node getNameNode() { result = this.getArgument(0) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll index 5836ff829cb1..57c0b15029af 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll @@ -280,11 +280,11 @@ module NodeJSLib { this.getNumArgument() >= 1 } - override predicate definesExplicitly(string headerName, Expr headerValue) { + override predicate definesHeaderValue(string headerName, DataFlow::Node headerValue) { this.getNumArgument() > 1 and exists(DataFlow::SourceNode headers, string header | headers.flowsTo(this.getLastArgument()) and - headers.hasPropertyWrite(header, DataFlow::valueNode(headerValue)) and + headers.hasPropertyWrite(header, headerValue) and headerName = header.toLowerCase() ) } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsMisconfigurationForCredentialsCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsMisconfigurationForCredentialsCustomizations.qll index 867494fc0a36..24c9a707bd08 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CorsMisconfigurationForCredentialsCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CorsMisconfigurationForCredentialsCustomizations.qll @@ -46,12 +46,12 @@ module CorsMisconfigurationForCredentials { CorsOriginHeaderWithAssociatedCredentialHeader() { exists( HTTP::RouteHandler routeHandler, HTTP::ExplicitHeaderDefinition origin, - Expr credentialsValue + DataFlow::Node credentialsValue | routeHandler.getAResponseHeader(_) = origin and routeHandler.getAResponseHeader(_) = credentials and - origin.definesExplicitly("access-control-allow-origin", this.asExpr()) and - credentials.definesExplicitly("access-control-allow-credentials", credentialsValue) + origin.definesHeaderValue("access-control-allow-origin", this) and + credentials.definesHeaderValue("access-control-allow-credentials", credentialsValue) | credentialsValue.mayHaveBooleanValue(true) or credentialsValue.mayHaveStringValue("true") diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll index 643a509b2f8a..db62f29c8ddf 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll @@ -41,9 +41,9 @@ module ServerSideUrlRedirect { * A definition of the HTTP "Location" header, considered as a sink for * `Configuration`. */ - class LocationHeaderSink extends Sink, DataFlow::ValueNode { + class LocationHeaderSink extends Sink { LocationHeaderSink() { - any(HTTP::ExplicitHeaderDefinition def).definesExplicitly("location", astNode) + any(HTTP::ExplicitHeaderDefinition def).definesHeaderValue("location", this) } } diff --git a/javascript/ql/test/library-tests/frameworks/Express/HeaderDefinition_getNameExpr.qll b/javascript/ql/test/library-tests/frameworks/Express/HeaderDefinition_getNameExpr.qll index a1db639b0218..2a7da38aee24 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/HeaderDefinition_getNameExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/HeaderDefinition_getNameExpr.qll @@ -1,5 +1,7 @@ import javascript -query predicate test_HeaderDefinition_getNameExpr(HTTP::ExplicitHeaderDefinition hd, Expr res) { - hd.getRouteHandler() instanceof Express::RouteHandler and res = hd.getNameExpr() +query predicate test_HeaderDefinition_getNameExpr( + HTTP::ExplicitHeaderDefinition hd, DataFlow::Node res +) { + hd.getRouteHandler() instanceof Express::RouteHandler and res = hd.getNameNode() } From 24b845589d609dd00d34591b77a5d6e7e270c142 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 13:09:54 +0200 Subject: [PATCH 05/39] change `ResponseBody` to a `DataFlow::Node` --- javascript/ql/lib/semmle/javascript/frameworks/Express.qll | 4 ++-- javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll | 4 ++-- javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll | 2 +- javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll | 2 +- javascript/ql/lib/semmle/javascript/frameworks/Koa.qll | 3 +-- javascript/ql/lib/semmle/javascript/frameworks/Micro.qll | 2 +- javascript/ql/lib/semmle/javascript/frameworks/Nest.qll | 4 ++-- .../ql/lib/semmle/javascript/frameworks/NodeJSLib.qll | 6 +++--- .../security/dataflow/ReflectedXssCustomizations.qll | 6 ++---- .../security/dataflow/StackTraceExposureCustomizations.qll | 4 +--- 10 files changed, 16 insertions(+), 21 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 18fff6d622e8..857aa56b77de 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -766,7 +766,7 @@ module Express { private class ResponseSendArgument extends HTTP::ResponseSendArgument { ResponseSource response; - ResponseSendArgument() { this = response.ref().getAMethodCall("send").getArgument(0).asExpr() } + ResponseSendArgument() { this = response.ref().getAMethodCall("send").getArgument(0) } override RouteHandler getRouteHandler() { result = response.getRouteHandler() } } @@ -794,7 +794,7 @@ module Express { TemplateObjectInput obj; TemplateInput() { - obj.getALocalSource().(DataFlow::ObjectLiteralNode).hasPropertyWrite(_, this.flow()) + obj.getALocalSource().(DataFlow::ObjectLiteralNode).hasPropertyWrite(_, this) } override RouteHandler getRouteHandler() { result = obj.getRouteHandler() } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll index 00b2d280c52b..9abe15146af4 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll @@ -340,9 +340,9 @@ module Fastify { RouteHandler rh; ResponseSendArgument() { - this = rh.getAResponseSource().ref().getAMethodCall("send").getArgument(0).asExpr() + this = rh.getAResponseSource().ref().getAMethodCall("send").getArgument(0) or - this = rh.(DataFlow::FunctionNode).getAReturn().asExpr() + this = rh.(DataFlow::FunctionNode).getAReturn() } override RouteHandler getRouteHandler() { result = rh } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll index e096ac7a5b96..3161ec08e341 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll @@ -117,7 +117,7 @@ module HTTP { /** * An expression whose value is sent as (part of) the body of an HTTP response. */ - abstract class ResponseBody extends Expr { + abstract class ResponseBody extends DataFlow::Node { /** * Gets the route handler that sends this expression. */ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll index 2b5e5bc6aefb..9e6345d3fb98 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll @@ -270,7 +270,7 @@ module Hapi { private class HandlerReturn extends HTTP::ResponseSendArgument { RouteHandler handler; - HandlerReturn() { this = handler.(DataFlow::FunctionNode).getAReturn().asExpr() } + HandlerReturn() { this = handler.(DataFlow::FunctionNode).getAReturn() } override RouteHandler getRouteHandler() { result = handler } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll index b43dafa2c499..a7ba37b7f81c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll @@ -412,8 +412,7 @@ module Koa { ResponseSendArgument() { exists(DataFlow::PropWrite pwn | - pwn.writes(DataFlow::valueNode(rh.getAResponseOrContextExpr()), "body", - DataFlow::valueNode(this)) + pwn.writes(DataFlow::valueNode(rh.getAResponseOrContextExpr()), "body", this) ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Micro.qll b/javascript/ql/lib/semmle/javascript/frameworks/Micro.qll index bc0cd9a31bdf..349e44f2e6dc 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Micro.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Micro.qll @@ -104,7 +104,7 @@ private module Micro { MicroSendArgument() { send = moduleMember("micro", ["send", "sendError"]).getACall() and - this = send.getLastArgument().asExpr() + this = send.getLastArgument() } override HTTP::RouteHandler getRouteHandler() { diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll index 1799f35beb8a..bb3a91036ff2 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll @@ -349,10 +349,10 @@ module NestJS { ReturnValueAsResponseSend() { handler.isReturnValueReflected() and - this = handler.getAReturn().asExpr() and + this = handler.getAReturn() and // Only returned strings are sinks not exists(Type type | - type = getType() and + type = this.asExpr().getType() and not isStringType(type.unfold()) ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll index 57c0b15029af..ed5c0829b98a 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll @@ -363,9 +363,9 @@ module NodeJSLib { HTTP::RouteHandler rh; ResponseSendArgument() { - exists(MethodCallExpr mce, string m | m = "write" or m = "end" | - mce.calls(any(ResponseExpr e | e.getRouteHandler() = rh), m) and - this = mce.getArgument(0) and + exists(DataFlow::MethodCallNode mcn, string m | m = "write" or m = "end" | + mcn.calls(any(ResponseExpr e | e.getRouteHandler() = rh).flow(), m) and + this = mcn.getArgument(0) and // don't mistake callback functions as data not this.analyze().getAValue() instanceof AbstractFunction ) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ReflectedXssCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ReflectedXssCustomizations.qll index 73188869256d..2969d118c60f 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ReflectedXssCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ReflectedXssCustomizations.qll @@ -24,10 +24,8 @@ module ReflectedXss { * a content type that does not (case-insensitively) contain the string "html". This * is to prevent us from flagging plain-text or JSON responses as vulnerable. */ - class HttpResponseSink extends Sink, DataFlow::ValueNode { - override HTTP::ResponseSendArgument astNode; - - HttpResponseSink() { not exists(getANonHtmlHeaderDefinition(astNode)) } + class HttpResponseSink extends Sink instanceof HTTP::ResponseSendArgument { + HttpResponseSink() { not exists(getANonHtmlHeaderDefinition(this)) } } /** diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/StackTraceExposureCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/StackTraceExposureCustomizations.qll index 235926795ba4..1ee969205fdc 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/StackTraceExposureCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/StackTraceExposureCustomizations.qll @@ -32,7 +32,5 @@ module StackTraceExposure { * An expression that can become part of an HTTP response body, viewed * as a data flow sink for stack trace exposure vulnerabilities. */ - class DefaultSink extends Sink, DataFlow::ValueNode { - override HTTP::ResponseBody astNode; - } + class DefaultSink extends Sink instanceof HTTP::ResponseBody { } } From ced4843dd78a8a28e25d814b40fc0082f667b5ef Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 13:22:36 +0200 Subject: [PATCH 06/39] change `CookieDefinition` to a `DataFlow::Node` --- .../javascript/frameworks/CookieLibraries.qll | 17 +++++++---------- .../semmle/javascript/frameworks/Express.qll | 8 ++++---- .../lib/semmle/javascript/frameworks/HTTP.qll | 15 +++++++-------- .../dataflow/CleartextStorageCustomizations.qll | 4 ++-- .../semmle/javascript/security/dataflow/DOM.qll | 1 + 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/CookieLibraries.qll b/javascript/ql/lib/semmle/javascript/frameworks/CookieLibraries.qll index 77bfff9f3882..71b7254fbbcd 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/CookieLibraries.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/CookieLibraries.qll @@ -271,30 +271,27 @@ private module ExpressCookies { /** * A cookie set using `response.cookie` from `express` module (https://expressjs.com/en/api.html#res.cookie). */ - private class InsecureExpressCookieResponse extends CookieWrites::CookieWrite, - DataFlow::MethodCallNode { - InsecureExpressCookieResponse() { this.asExpr() instanceof Express::SetCookie } - + private class InsecureExpressCookieResponse extends CookieWrites::CookieWrite instanceof Express::SetCookie { override predicate isSecure() { // A cookie is secure if there are cookie options with the `secure` flag set to `true`. // The default is `false`. - exists(DataFlow::Node value | value = this.getOptionArgument(2, CookieWrites::secure()) | + exists(DataFlow::Node value | value = super.getOptionArgument(2, CookieWrites::secure()) | not value.mayHaveBooleanValue(false) // anything but `false` is accepted as being maybe true ) } - override predicate isSensitive() { canHaveSensitiveCookie(this.getArgument(0)) } + override predicate isSensitive() { canHaveSensitiveCookie(super.getArgument(0)) } override predicate isHttpOnly() { // A cookie is httpOnly if there are cookie options with the `httpOnly` flag set to `true`. // The default is `false`. - exists(DataFlow::Node value | value = this.getOptionArgument(2, CookieWrites::httpOnly()) | + exists(DataFlow::Node value | value = super.getOptionArgument(2, CookieWrites::httpOnly()) | not value.mayHaveBooleanValue(false) // anything but `false` is accepted as being maybe true ) } override string getSameSite() { - result = getSameSiteValue(this.getOptionArgument(2, "sameSite")) + result = getSameSiteValue(super.getOptionArgument(2, "sameSite")) } } @@ -372,10 +369,10 @@ private class HttpCookieWrite extends CookieWrites::CookieWrite { HttpCookieWrite() { exists(HTTP::CookieDefinition setCookie | - this.asExpr() = setCookie.getHeaderArgument() and + this = setCookie.getHeaderArgument() and not this instanceof DataFlow::ArrayCreationNode or - this = setCookie.getHeaderArgument().flow().(DataFlow::ArrayCreationNode).getAnElement() + this = setCookie.getHeaderArgument().(DataFlow::ArrayCreationNode).getAnElement() ) and header = [ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 857aa56b77de..7716b734298b 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -774,14 +774,14 @@ module Express { /** * An invocation of the `cookie` method on an HTTP response object. */ - class SetCookie extends HTTP::CookieDefinition, MethodCallExpr { + class SetCookie extends HTTP::CookieDefinition, DataFlow::MethodCallNode { ResponseSource response; - SetCookie() { this = response.ref().getAMethodCall("cookie").asExpr() } + SetCookie() { this = response.ref().getAMethodCall("cookie") } - override Expr getNameArgument() { result = this.getArgument(0) } + override DataFlow::Node getNameArgument() { result = this.getArgument(0) } - override Expr getValueArgument() { result = this.getArgument(1) } + override DataFlow::Node getValueArgument() { result = this.getArgument(1) } override RouteHandler getRouteHandler() { result = response.getRouteHandler() } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll index 3161ec08e341..85b44f4e1bda 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll @@ -133,22 +133,21 @@ module HTTP { /** * An expression that sets a cookie in an HTTP response. */ - abstract class CookieDefinition extends Expr { - // TODO: DataFlow::Node + abstract class CookieDefinition extends DataFlow::Node { /** * Gets the argument, if any, specifying the raw cookie header. */ - Expr getHeaderArgument() { none() } // TODO: DataFlow::Node + DataFlow::Node getHeaderArgument() { none() } /** * Gets the argument, if any, specifying the cookie name. */ - Expr getNameArgument() { none() } // TODO: DataFlow::Node + DataFlow::Node getNameArgument() { none() } /** * Gets the argument, if any, specifying the cookie value. */ - Expr getValueArgument() { none() } // TODO: DataFlow::Node + DataFlow::Node getValueArgument() { none() } /** Gets the route handler that sets this cookie. */ abstract RouteHandler getRouteHandler(); @@ -161,12 +160,12 @@ module HTTP { HeaderDefinition header; SetCookieHeader() { - this = header.asExpr() and + this = header and header.getAHeaderName() = "set-cookie" } - override Expr getHeaderArgument() { - header.(ExplicitHeaderDefinition).definesHeaderValue("set-cookie", result.flow()) + override DataFlow::Node getHeaderArgument() { + header.(ExplicitHeaderDefinition).definesHeaderValue("set-cookie", result) } override RouteHandler getRouteHandler() { result = header.getRouteHandler() } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll index e719d02d1009..95114e8c4b73 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll @@ -52,8 +52,8 @@ module CleartextStorage { class CookieStorageSink extends Sink { CookieStorageSink() { exists(HTTP::CookieDefinition cookieDef | - this.asExpr() = cookieDef.getValueArgument() or - this.asExpr() = cookieDef.getHeaderArgument() + this = cookieDef.getValueArgument() or + this = cookieDef.getHeaderArgument() ) } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll index 3b370bb6938a..58728d5f9e60 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll @@ -144,6 +144,7 @@ class DomPropWriteNode extends Assignment { * A value written to web storage, like `localStorage` or `sessionStorage`. */ class WebStorageWrite extends Expr { + // TODO: DataFlow::Node WebStorageWrite() { exists(DataFlow::SourceNode webStorage | webStorage = DataFlow::globalVarRef("localStorage") or From d98028be1a40877f88ef7e2f6134deee89a192b9 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 13:37:35 +0200 Subject: [PATCH 07/39] change `ServerDefinition` to a `DataFlow::Node` --- .../ql/lib/semmle/javascript/frameworks/Connect.qll | 8 ++++---- .../ql/lib/semmle/javascript/frameworks/Express.qll | 10 +++++++--- .../ql/lib/semmle/javascript/frameworks/Fastify.qll | 8 +++----- .../ql/lib/semmle/javascript/frameworks/HTTP.qll | 13 ++++++++----- .../ql/lib/semmle/javascript/frameworks/Hapi.qll | 6 +++--- .../ql/lib/semmle/javascript/frameworks/Koa.qll | 6 +++--- .../lib/semmle/javascript/frameworks/LiveServer.qll | 6 +++--- .../lib/semmle/javascript/frameworks/NodeJSLib.qll | 5 +++-- .../ql/lib/semmle/javascript/frameworks/Restify.qll | 6 +++--- 9 files changed, 37 insertions(+), 31 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll b/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll index 5735ac5eb219..1a7529c6dfbd 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll @@ -10,10 +10,10 @@ module Connect { /** * An expression that creates a new Connect server. */ - class ServerDefinition extends HTTP::Servers::StandardServerDefinition, CallExpr { + class ServerDefinition extends HTTP::Servers::StandardServerDefinition, DataFlow::CallNode { ServerDefinition() { // `app = connect()` - this = DataFlow::moduleImport("connect").getAnInvocation().asExpr() + this = DataFlow::moduleImport("connect").getAnInvocation() } } @@ -69,7 +69,7 @@ module Connect { server.ref().flowsToExpr(getReceiver()) or // app.use(...).use(fun) - this.getReceiver().(RouteSetup).getServer() = server + this.getReceiver().(RouteSetup).getServer() = server.asExpr() ) } @@ -84,7 +84,7 @@ module Connect { exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t)) } - override Expr getServer() { result = server } + override Expr getServer() { result = server.asExpr() } /** Gets an argument that represents a route handler being registered. */ Expr getARouteHandlerExpr() { result = getAnArgument() } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 7716b734298b..db6a471b909a 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -199,7 +199,10 @@ module Express { ) } - override Expr getServer() { result.(Application).getARouteHandler() = this.getARouteHandler() } + override Expr getServer() { + any(DataFlow::Node n | n.asExpr() = result).(Application).getARouteHandler() = + this.getARouteHandler() + } /** * Gets the HTTP request type this is registered for, if any. @@ -823,13 +826,13 @@ module Express { * An Express server application. */ private class Application extends HTTP::ServerDefinition { - Application() { this = appCreation().asExpr() } + Application() { this = appCreation() } /** * Gets a route handler of the application, regardless of nesting. */ override HTTP::RouteHandler getARouteHandler() { - result = this.(RouterDefinition).getASubRouter*().getARouteHandler() + result = this.asExpr().(RouterDefinition).getASubRouter*().getARouteHandler() } } @@ -837,6 +840,7 @@ module Express { * An Express router. */ class RouterDefinition extends InvokeExpr { + // TODO: DataFlow::Node RouterDefinition() { this = routerCreation().asExpr() } private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll index 9abe15146af4..a834d87039f8 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll @@ -18,9 +18,7 @@ module Fastify { * A standard way to create a Fastify server. */ class StandardServerDefinition extends ServerDefinition { - StandardServerDefinition() { - this = DataFlow::moduleImport("fastify").getAnInvocation().asExpr() - } + StandardServerDefinition() { this = DataFlow::moduleImport("fastify").getAnInvocation() } } /** Gets a data flow node referring to a fastify server. */ @@ -139,7 +137,7 @@ module Fastify { string methodName; RouteSetup() { - this = server(server.flow()).getAMethodCall(methodName).asExpr() and + this = server(server).getAMethodCall(methodName).asExpr() and methodName = ["route", "get", "head", "post", "put", "delete", "options", "patch"] } @@ -154,7 +152,7 @@ module Fastify { exists(DataFlow::TypeBackTracker t2 | result = this.getARouteHandler(t2).backtrack(t2, t)) } - override Expr getServer() { result = server } + override Expr getServer() { result = server.asExpr() } /** Gets an argument that represents a route handler being registered. */ DataFlow::Node getARouteHandlerExpr() { diff --git a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll index 85b44f4e1bda..c116be191c90 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll @@ -174,7 +174,7 @@ module HTTP { /** * An expression that creates a new server. */ - abstract class ServerDefinition extends Expr { + abstract class ServerDefinition extends DataFlow::Node { /** * Gets a route handler of the server. */ @@ -242,7 +242,7 @@ module HTTP { /** * An expression that sets up a route on a server. */ - abstract class RouteSetup extends Expr { } + abstract class RouteSetup extends Expr { } // TODO: DataFlow::Node /** * An expression that may contain a request object. @@ -275,11 +275,13 @@ module HTTP { * A standard server definition. */ abstract class StandardServerDefinition extends ServerDefinition { - override RouteHandler getARouteHandler() { result.(StandardRouteHandler).getServer() = this } + override RouteHandler getARouteHandler() { + result.(StandardRouteHandler).getServer() = this.asExpr() + } private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { t.start() and - result = DataFlow::exprNode(this) + result = this.getALocalSource() or exists(DataFlow::TypeTracker t2 | result = this.ref(t2).track(t2, t)) } @@ -307,6 +309,7 @@ module HTTP { * Gets the server this route handler is registered on. */ Expr getServer() { + // TODO: DataFlow::Node exists(StandardRouteSetup setup | setup.getARouteHandler() = this | result = setup.getServer() ) @@ -411,7 +414,7 @@ module HTTP { /** * Gets the server on which this route setup sets up routes. */ - abstract Expr getServer(); + abstract Expr getServer(); // TODO: DataFlow::Node } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll index 9e6345d3fb98..b8496a0d0920 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll @@ -9,10 +9,10 @@ module Hapi { /** * An expression that creates a new Hapi server. */ - class ServerDefinition extends HTTP::Servers::StandardServerDefinition, NewExpr { + class ServerDefinition extends HTTP::Servers::StandardServerDefinition, DataFlow::NewNode { ServerDefinition() { // `server = new Hapi.Server()` - this = DataFlow::moduleMember("hapi", "Server").getAnInstantiation().asExpr() + this = DataFlow::moduleMember("hapi", "Server").getAnInstantiation() } } @@ -219,7 +219,7 @@ module Hapi { Expr getRouteHandlerExpr() { result = handler } - override Expr getServer() { result = server } + override Expr getServer() { result = server.asExpr() } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll index a7ba37b7f81c..d2f2b139cab1 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll @@ -9,10 +9,10 @@ module Koa { /** * An expression that creates a new Koa application. */ - class AppDefinition extends HTTP::Servers::StandardServerDefinition, InvokeExpr { + class AppDefinition extends HTTP::Servers::StandardServerDefinition, DataFlow::InvokeNode { AppDefinition() { // `app = new Koa()` / `app = Koa()` - this = DataFlow::moduleImport("koa").getAnInvocation().asExpr() + this = DataFlow::moduleImport("koa").getAnInvocation() } } @@ -401,7 +401,7 @@ module Koa { result.(RouteHandler).getARouteHandlerRegistrationObject().flowsToExpr(this.getArgument(0)) } - override Expr getServer() { result = server } + override Expr getServer() { result = server.asExpr() } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll b/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll index 1d7604e0b0cb..858a5fb51b22 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll @@ -10,9 +10,9 @@ private module LiveServer { * An expression that imports the live-server package, seen as a server-definition. */ class ServerDefinition extends HTTP::Servers::StandardServerDefinition { - ServerDefinition() { this = DataFlow::moduleImport("live-server").asExpr() } + ServerDefinition() { this = DataFlow::moduleImport("live-server") } - API::Node getImportNode() { result.asSource().asExpr() = this } + API::Node getImportNode() { result.asSource() = this } } /** @@ -49,6 +49,6 @@ private module LiveServer { ) } - override Expr getServer() { result = server } + override Expr getServer() { result = server.asExpr() } } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll index ed5c0829b98a..a71ff7117dcf 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll @@ -50,6 +50,7 @@ module NodeJSLib { * Holds if `call` is an invocation of `http.createServer` or `https.createServer`. */ predicate isCreateServer(CallExpr call) { + // TODO: DataFlow::Node exists(string pkg, string fn | pkg = "http" and fn = "createServer" or @@ -248,7 +249,7 @@ module NodeJSLib { ) } - override Expr getServer() { result = server } + override Expr getServer() { result = server.asExpr() } /** * Gets the expression for the handler registered by this setup. @@ -378,7 +379,7 @@ module NodeJSLib { * An expression that creates a new Node.js server. */ class ServerDefinition extends HTTP::Servers::StandardServerDefinition { - ServerDefinition() { isCreateServer(this) } + ServerDefinition() { isCreateServer(this.asExpr()) } } /** An expression that is passed as `http.request({ auth: }, ...)`. */ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll b/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll index 4c319f17bfea..ed6ca6adac0b 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll @@ -9,10 +9,10 @@ module Restify { /** * An expression that creates a new Restify server. */ - class ServerDefinition extends HTTP::Servers::StandardServerDefinition, CallExpr { + class ServerDefinition extends HTTP::Servers::StandardServerDefinition, DataFlow::CallNode { ServerDefinition() { // `server = restify.createServer()` - this = DataFlow::moduleMember("restify", "createServer").getACall().asExpr() + this = DataFlow::moduleMember("restify", "createServer").getACall() } } @@ -154,6 +154,6 @@ module Restify { override DataFlow::SourceNode getARouteHandler() { result.flowsToExpr(getArgument(1)) } - override Expr getServer() { result = server } + override Expr getServer() { result = server.asExpr() } } } From 9cb7522bc197e94edf5972dadd8e6f702f6a8dfb Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 14:17:01 +0200 Subject: [PATCH 08/39] change `RouteSetup` to a `DataFlow::Node` --- .../semmle/javascript/frameworks/Connect.qll | 10 ++--- .../semmle/javascript/frameworks/Express.qll | 40 ++++++++++--------- .../semmle/javascript/frameworks/Fastify.qll | 31 +++++--------- .../semmle/javascript/frameworks/Firebase.qll | 10 ++--- .../lib/semmle/javascript/frameworks/HTTP.qll | 11 ++--- .../lib/semmle/javascript/frameworks/Hapi.qll | 14 +++---- .../lib/semmle/javascript/frameworks/Koa.qll | 11 +++-- .../javascript/frameworks/LiveServer.qll | 12 ++---- .../javascript/frameworks/NodeJSLib.qll | 16 ++++---- .../semmle/javascript/frameworks/Restify.qll | 9 ++--- .../Security/CWE-200/PrivateFileExposure.ql | 4 +- javascript/ql/src/experimental/poi/PoI.qll | 2 +- .../UnpromotedRouteSetupCandidate.ql | 2 +- .../test/experimental/PoI/TestCustomPoIs.ql | 6 +-- .../frameworks/Express/RouteSetup.qll | 2 +- .../Express/RouteSetup_getServer.qll | 4 +- .../RouteSetup_handlesSameRequestMethodAs.qll | 6 +-- .../Express/StandardRouteHandler.qll | 2 +- .../HeaderDefinition_getNameExpr.qll | 6 ++- .../frameworks/NodeJSLib/RouteHandler.qll | 4 +- .../NodeJSLib/RouteSetup_getServer.qll | 4 +- .../library-tests/frameworks/connect/tests.ql | 8 +++- .../frameworks/fastify/RouteHandler.qll | 4 +- .../fastify/RouteSetup_getServer.qll | 4 +- .../frameworks/hapi/RouteHandler.qll | 4 +- .../frameworks/hapi/RouteSetup_getServer.qll | 4 +- .../frameworks/koa/RouteHandler.qll | 2 +- .../frameworks/koa/RouteSetup_getServer.qll | 4 +- .../frameworks/restify/RouteHandler.qll | 4 +- .../restify/RouteSetup_getServer.qll | 4 +- 30 files changed, 124 insertions(+), 120 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll b/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll index 1a7529c6dfbd..8cf6b7ccebab 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll @@ -59,17 +59,17 @@ module Connect { /** * A call to a Connect method that sets up a route. */ - class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup { + class RouteSetup extends DataFlow::MethodCallNode, HTTP::Servers::StandardRouteSetup { ServerDefinition server; RouteSetup() { getMethodName() = "use" and ( // app.use(fun) - server.ref().flowsToExpr(getReceiver()) + server.ref().getAMethodCall() = this or // app.use(...).use(fun) - this.getReceiver().(RouteSetup).getServer() = server.asExpr() + this.getReceiver().(RouteSetup).getServer() = server ) } @@ -84,10 +84,10 @@ module Connect { exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t)) } - override Expr getServer() { result = server.asExpr() } + override DataFlow::Node getServer() { result = server } /** Gets an argument that represents a route handler being registered. */ - Expr getARouteHandlerExpr() { result = getAnArgument() } + Expr getARouteHandlerExpr() { result = getAnArgument().asExpr() } // TODO: DataFlow::Node } /** An expression that is passed as `basicAuthConnect(, )`. */ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index db6a471b909a..d0d494285248 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -49,6 +49,7 @@ module Express { * Holds if `e` may refer to a router object. */ private predicate isRouter(Expr e) { + // TODO: DataFlow::Node isRouter(e, _) or e.getType().hasUnderlyingType("express", "Router") @@ -89,7 +90,7 @@ module Express { } private class RoutingTreeSetup extends Routing::RouteSetup::MethodCall { - RoutingTreeSetup() { this.asExpr() instanceof RouteSetup } + RoutingTreeSetup() { this instanceof RouteSetup } override string getRelativePath() { not this.getMethodName() = "param" and // do not treat parameter name as a path @@ -140,9 +141,9 @@ module Express { /** * A call to an Express router method that sets up a route. */ - class RouteSetup extends HTTP::Servers::StandardRouteSetup, MethodCallExpr { + class RouteSetup extends HTTP::Servers::StandardRouteSetup, DataFlow::MethodCallNode { RouteSetup() { - isRouter(this.getReceiver()) and + isRouter(this.getReceiver().asExpr()) and this.getMethodName() = routeSetupMethodName() } @@ -150,7 +151,7 @@ module Express { string getPath() { this.getArgument(0).mayHaveStringValue(result) } /** Gets the router on which handlers are being registered. */ - RouterDefinition getRouter() { isRouter(this.getReceiver(), result) } + RouterDefinition getRouter() { isRouter(this.getReceiver().asExpr(), result) } /** Holds if this is a call `use`, such as `app.use(handler)`. */ predicate isUseCall() { this.getMethodName() = "use" } @@ -162,13 +163,14 @@ module Express { * returned, not its dataflow source. */ Expr getRouteHandlerExpr(int index) { + // TODO: DataFlow::Node // The first argument is a URI pattern if it is a string. If it could possibly be // a function, we consider it to be a route handler, otherwise a URI pattern. exists(AnalyzedNode firstArg | firstArg = this.getArgument(0).analyze() | if firstArg.getAType() = TTFunction() - then result = this.getArgument(index) + then result = this.getArgument(index).asExpr() else ( - index >= 0 and result = this.getArgument(index + 1) + index >= 0 and result = this.getArgument(index + 1).asExpr() ) ) } @@ -199,9 +201,8 @@ module Express { ) } - override Expr getServer() { - any(DataFlow::Node n | n.asExpr() = result).(Application).getARouteHandler() = - this.getARouteHandler() + override DataFlow::Node getServer() { + result.(Application).getARouteHandler() = this.getARouteHandler() } /** @@ -236,16 +237,16 @@ module Express { /** * A call that sets up a Passport router that includes the request object. */ - private class PassportRouteSetup extends HTTP::Servers::StandardRouteSetup, CallExpr { + private class PassportRouteSetup extends HTTP::Servers::StandardRouteSetup, DataFlow::CallNode { DataFlow::ModuleImportNode importNode; DataFlow::FunctionNode callback; // looks for this pattern: passport.use(new Strategy({passReqToCallback: true}, callback)) PassportRouteSetup() { importNode = DataFlow::moduleImport("passport") and - this = importNode.getAMemberCall("use").asExpr() and + this = importNode.getAMemberCall("use") and exists(DataFlow::NewNode strategy | - strategy.flowsToExpr(this.getArgument(0)) and + strategy.flowsTo(this.getArgument(0)) and strategy.getNumArgument() = 2 and // new Strategy({passReqToCallback: true}, ...) strategy.getOptionArgument(0, "passReqToCallback").mayHaveBooleanValue(true) and @@ -253,7 +254,7 @@ module Express { ) } - override Expr getServer() { result = importNode.asExpr() } + override DataFlow::Node getServer() { result = importNode } override DataFlow::SourceNode getARouteHandler() { result = callback } } @@ -335,7 +336,8 @@ module Express { * same requests. */ Express::RouteHandlerExpr getPreviousMiddleware() { - index = 0 and result = setup.getRouter().getMiddlewareStackAt(setup.getAPredecessor()) + index = 0 and + result = setup.getRouter().getMiddlewareStackAt(setup.asExpr().getAPredecessor()) or index > 0 and result = setup.getRouteHandlerExpr(index - 1) or @@ -867,7 +869,7 @@ module Express { /** * Gets a `RouteSetup` that was used for setting up a route on this router. */ - private RouteSetup getARouteSetup() { this.ref().flowsToExpr(result.getReceiver()) } + private RouteSetup getARouteSetup() { this.ref().flowsTo(result.getReceiver()) } /** * Gets a sub-router registered on this router. @@ -875,7 +877,7 @@ module Express { * Example: `router2` for `router1.use(router2)` or `router1.use("/route2", router2)` */ RouterDefinition getASubRouter() { - result.ref().flowsToExpr(this.getARouteSetup().getAnArgument()) + result.ref().flowsTo(this.getARouteSetup().getAnArgument()) } /** @@ -884,7 +886,7 @@ module Express { * Example: `fun` for `router1.use(fun)` or `router.use("/route", fun)` */ HTTP::RouteHandler getARouteHandler() { - result.(DataFlow::SourceNode).flowsToExpr(this.getARouteSetup().getAnArgument()) + result.(DataFlow::SourceNode).flowsToExpr(this.getARouteSetup().getAnArgument().asExpr()) } /** @@ -904,10 +906,10 @@ module Express { */ Express::RouteHandlerExpr getMiddlewareStackAt(ControlFlowNode node) { if - exists(Express::RouteSetup setup | node = setup and setup.getRouter() = this | + exists(Express::RouteSetup setup | node = setup.asExpr() and setup.getRouter() = this | setup.isUseCall() ) - then result = node.(Express::RouteSetup).getLastRouteHandlerExpr() + then result = node.(AST::ValueNode).flow().(Express::RouteSetup).getLastRouteHandlerExpr() else result = this.getMiddlewareStackAt(node.getAPredecessor()) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll index a834d87039f8..b80baeb7a90c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll @@ -132,12 +132,12 @@ module Fastify { /** * A call to a Fastify method that sets up a route. */ - class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup { + class RouteSetup extends DataFlow::MethodCallNode, HTTP::Servers::StandardRouteSetup { ServerDefinition server; string methodName; RouteSetup() { - this = server(server).getAMethodCall(methodName).asExpr() and + this = server(server).getAMethodCall(methodName) and methodName = ["route", "get", "head", "post", "put", "delete", "options", "patch"] } @@ -152,20 +152,19 @@ module Fastify { exists(DataFlow::TypeBackTracker t2 | result = this.getARouteHandler(t2).backtrack(t2, t)) } - override Expr getServer() { result = server.asExpr() } + override DataFlow::SourceNode getServer() { result = server } /** Gets an argument that represents a route handler being registered. */ DataFlow::Node getARouteHandlerExpr() { if methodName = "route" - then - result = this.flow().(DataFlow::MethodCallNode).getOptionArgument(0, getNthHandlerName(_)) - else result = this.getLastArgument().flow() + then result = this.getOptionArgument(0, getNthHandlerName(_)) + else result = this.getLastArgument() } } private class ShorthandRoutingTreeSetup extends Routing::RouteSetup::MethodCall { ShorthandRoutingTreeSetup() { - this.asExpr() instanceof RouteSetup and + this instanceof RouteSetup and not this.getMethodName() = "route" } @@ -183,7 +182,7 @@ module Fastify { private class FullRoutingTreeSetup extends Routing::RouteSetup::MethodCall { FullRoutingTreeSetup() { - this.asExpr() instanceof RouteSetup and + this instanceof RouteSetup and this.getMethodName() = "route" } @@ -285,13 +284,7 @@ module Fastify { */ private predicate usesFastifyPlugin(RouteHandler rh, DataFlow::SourceNode plugin) { exists(RouteSetup setup | - plugin - .flowsTo(setup - .getServer() - .flow() - .(DataFlow::SourceNode) - .getAMethodCall("register") - .getArgument(0)) and // only matches the plugins that apply to all routes + plugin.flowsTo(setup.getServer().getAMethodCall("register").getArgument(0)) and // only matches the plugins that apply to all routes rh = setup.getARouteHandler() ) } @@ -301,13 +294,7 @@ module Fastify { */ private predicate usesMiddleware(RouteHandler rh, DataFlow::SourceNode middleware) { exists(RouteSetup setup | - middleware - .flowsTo(setup - .getServer() - .flow() - .(DataFlow::SourceNode) - .getAMethodCall("use") - .getArgument(0)) and // only matches the middlewares that apply to all routes + middleware.flowsTo(setup.getServer().getAMethodCall("use").getArgument(0)) and // only matches the middlewares that apply to all routes rh = setup.getARouteHandler() ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/lib/semmle/javascript/frameworks/Firebase.qll index 3678d5fde578..626943688154 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Firebase.qll @@ -195,10 +195,8 @@ module Firebase { /** * A call to a Firebase method that sets up a route. */ - private class RouteSetup extends HTTP::Servers::StandardRouteSetup, CallExpr { - RouteSetup() { - this = namespace().getAPropertyRead("https").getAMemberCall("onRequest").asExpr() - } + private class RouteSetup extends HTTP::Servers::StandardRouteSetup, DataFlow::CallNode { + RouteSetup() { this = namespace().getAPropertyRead("https").getAMemberCall("onRequest") } override DataFlow::SourceNode getARouteHandler() { result = getARouteHandler(DataFlow::TypeBackTracker::end()) @@ -206,12 +204,12 @@ module Firebase { private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { t.start() and - result = getArgument(0).flow().getALocalSource() + result = getArgument(0).getALocalSource() or exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t)) } - override Expr getServer() { none() } + override DataFlow::Node getServer() { none() } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll index c116be191c90..8ff456c36a14 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll @@ -242,7 +242,7 @@ module HTTP { /** * An expression that sets up a route on a server. */ - abstract class RouteSetup extends Expr { } // TODO: DataFlow::Node + abstract class RouteSetup extends DataFlow::Node { } /** * An expression that may contain a request object. @@ -275,9 +275,7 @@ module HTTP { * A standard server definition. */ abstract class StandardServerDefinition extends ServerDefinition { - override RouteHandler getARouteHandler() { - result.(StandardRouteHandler).getServer() = this.asExpr() - } + override RouteHandler getARouteHandler() { result.(StandardRouteHandler).getServer() = this } private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { t.start() and @@ -308,8 +306,7 @@ module HTTP { /** * Gets the server this route handler is registered on. */ - Expr getServer() { - // TODO: DataFlow::Node + DataFlow::Node getServer() { exists(StandardRouteSetup setup | setup.getARouteHandler() = this | result = setup.getServer() ) @@ -414,7 +411,7 @@ module HTTP { /** * Gets the server on which this route setup sets up routes. */ - abstract Expr getServer(); // TODO: DataFlow::Node + abstract DataFlow::Node getServer(); } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll index b8496a0d0920..0b1923a24af7 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll @@ -186,16 +186,16 @@ module Hapi { /** * A call to a Hapi method that sets up a route. */ - class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup { + class RouteSetup extends DataFlow::MethodCallNode, HTTP::Servers::StandardRouteSetup { ServerDefinition server; - Expr handler; + DataFlow::Node handler; RouteSetup() { - server.ref().flowsToExpr(getReceiver()) and + server.ref().getAMethodCall() = this and ( // server.route({ handler: fun }) getMethodName() = "route" and - hasOptionArgument(0, "handler", handler) + getOptionArgument(0, "handler") = handler or // server.ext('/', fun) getMethodName() = "ext" and @@ -215,11 +215,11 @@ module Hapi { } pragma[noinline] - private DataFlow::Node getRouteHandler() { result = handler.flow() } + private DataFlow::Node getRouteHandler() { result = handler } - Expr getRouteHandlerExpr() { result = handler } + Expr getRouteHandlerExpr() { result = handler.asExpr() } // TODO: DataFlow::Node - override Expr getServer() { result = server.asExpr() } + override DataFlow::Node getServer() { result = server } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll index d2f2b139cab1..7c5d2fe6655f 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll @@ -384,24 +384,23 @@ module Koa { /** * A call to a Koa method that sets up a route. */ - class RouteSetup extends HTTP::Servers::StandardRouteSetup, MethodCallExpr { + class RouteSetup extends HTTP::Servers::StandardRouteSetup, DataFlow::MethodCallNode { AppDefinition server; RouteSetup() { // app.use(fun) - server.ref().flowsToExpr(this.getReceiver()) and - this.getMethodName() = "use" + server.ref().getAMethodCall("use") = this } override DataFlow::SourceNode getARouteHandler() { // `StandardRouteHandler` uses this predicate in it's charpred, so making this predicate return a `RouteHandler` would give an empty recursion. - result.flowsToExpr(this.getArgument(0)) + result.flowsToExpr(this.getArgument(0).asExpr()) or // For the route-handlers that does not depend on this predicate in their charpred. - result.(RouteHandler).getARouteHandlerRegistrationObject().flowsToExpr(this.getArgument(0)) + result.(RouteHandler).getARouteHandlerRegistrationObject().flowsTo(this.getArgument(0)) } - override Expr getServer() { result = server.asExpr() } + override DataFlow::Node getServer() { result = server } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll b/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll index 858a5fb51b22..da23907ee8f5 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll @@ -30,18 +30,14 @@ private module LiveServer { /** * The call to `require("live-server").start()`, seen as a route setup. */ - class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup { + class RouteSetup extends HTTP::Servers::StandardRouteSetup instanceof API::CallNode { ServerDefinition server; - API::CallNode call; - RouteSetup() { - call = server.getImportNode().getMember("start").getACall() and - this = call.asExpr() - } + RouteSetup() { this = server.getImportNode().getMember("start").getACall() } override DataFlow::SourceNode getARouteHandler() { exists(DataFlow::SourceNode middleware | - middleware = call.getParameter(0).getMember("middleware").getAValueReachingSink() + middleware = super.getParameter(0).getMember("middleware").getAValueReachingSink() | result = middleware.getAMemberCall(["push", "unshift"]).getArgument(0).getAFunctionValue() or @@ -49,6 +45,6 @@ private module LiveServer { ) } - override Expr getServer() { result = server.asExpr() } + override DataFlow::Node getServer() { result = server } } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll index a71ff7117dcf..bd34abb12655 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll @@ -217,16 +217,16 @@ module NodeJSLib { RequestExpr getRequest() { result = request } } - class RouteSetup extends CallExpr, HTTP::Servers::StandardRouteSetup { + class RouteSetup extends DataFlow::CallNode, HTTP::Servers::StandardRouteSetup { ServerDefinition server; - Expr handler; + DataFlow::Node handler; RouteSetup() { - server.ref().flowsToExpr(this) and + server.ref() = this and handler = this.getLastArgument() or - server.ref().flowsToExpr(this.getReceiver()) and - this.(MethodCallExpr).getMethodName().regexpMatch("on(ce)?") and + server.ref().getAMethodCall() = this and + this.getCalleeName().regexpMatch("on(ce)?") and this.getArgument(0).getStringValue() = "request" and handler = this.getArgument(1) } @@ -237,7 +237,7 @@ module NodeJSLib { private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { t.start() and - result = handler.flow().getALocalSource() + result = handler.getALocalSource() or exists(DataFlow::TypeBackTracker t2, DataFlow::SourceNode succ | succ = this.getARouteHandler(t2) @@ -249,12 +249,12 @@ module NodeJSLib { ) } - override Expr getServer() { result = server.asExpr() } + override DataFlow::Node getServer() { result = server } /** * Gets the expression for the handler registered by this setup. */ - Expr getRouteHandlerExpr() { result = handler } + Expr getRouteHandlerExpr() { result = handler.asExpr() } // TODO: DataFlow::Node } abstract private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll b/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll index ed6ca6adac0b..7f14e9040e7a 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll @@ -142,18 +142,17 @@ module Restify { /** * A call to a Restify method that sets up a route. */ - class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup { + class RouteSetup extends DataFlow::MethodCallNode, HTTP::Servers::StandardRouteSetup { ServerDefinition server; RouteSetup() { // server.get('/', fun) // server.head('/', fun) - server.ref().flowsToExpr(getReceiver()) and - getMethodName() = any(HTTP::RequestMethodName m).toLowerCase() + server.ref().getAMethodCall(any(HTTP::RequestMethodName m).toLowerCase()) = this } - override DataFlow::SourceNode getARouteHandler() { result.flowsToExpr(getArgument(1)) } + override DataFlow::SourceNode getARouteHandler() { result.flowsTo(getArgument(1)) } - override Expr getServer() { result = server.asExpr() } + override DataFlow::Node getServer() { result = server } } } diff --git a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql index 73a20ce22494..fc402857e651 100644 --- a/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql +++ b/javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql @@ -135,7 +135,7 @@ DataFlow::CallNode servesAPrivateFolder(string description) { */ Express::RouteSetup getAnExposingExpressSetup(string path) { result.isUseCall() and - result.getArgument([0 .. 1]) = servesAPrivateFolder(path).getEnclosingExpr() + result.getArgument([0 .. 1]) = servesAPrivateFolder(path) } /** @@ -149,7 +149,7 @@ DataFlow::CallNode getAnExposingServeSetup(string path) { from DataFlow::Node node, string path where - node = getAnExposingExpressSetup(path).flow() + node = getAnExposingExpressSetup(path) or node = getAnExposingServeSetup(path) select node, "Serves " + path + ", which can contain private information." diff --git a/javascript/ql/src/experimental/poi/PoI.qll b/javascript/ql/src/experimental/poi/PoI.qll index c51909c5c9ec..68143be6bdd5 100644 --- a/javascript/ql/src/experimental/poi/PoI.qll +++ b/javascript/ql/src/experimental/poi/PoI.qll @@ -77,7 +77,7 @@ private module StandardPoIs { UnpromotedRouteSetupPoI() { this = "UnpromotedRouteSetupPoI" } override predicate is(Node l0) { - l0 instanceof HTTP::RouteSetupCandidate and not l0.asExpr() instanceof HTTP::RouteSetup + l0 instanceof HTTP::RouteSetupCandidate and not l0 instanceof HTTP::RouteSetup } } diff --git a/javascript/ql/src/meta/analysis-quality/UnpromotedRouteSetupCandidate.ql b/javascript/ql/src/meta/analysis-quality/UnpromotedRouteSetupCandidate.ql index 361e2d8a6194..428f6b4e4b07 100644 --- a/javascript/ql/src/meta/analysis-quality/UnpromotedRouteSetupCandidate.ql +++ b/javascript/ql/src/meta/analysis-quality/UnpromotedRouteSetupCandidate.ql @@ -13,7 +13,7 @@ import CandidateTracking from HTTP::RouteSetupCandidate setup where - not setup.asExpr() instanceof HTTP::RouteSetup and + not setup instanceof HTTP::RouteSetup and exists(HTTP::RouteHandlerCandidate rh | track(rh, DataFlow::TypeTracker::end()).flowsTo(setup.getARouteHandlerArg()) ) diff --git a/javascript/ql/test/experimental/PoI/TestCustomPoIs.ql b/javascript/ql/test/experimental/PoI/TestCustomPoIs.ql index 5e73f8a4f874..dd526143a65e 100644 --- a/javascript/ql/test/experimental/PoI/TestCustomPoIs.ql +++ b/javascript/ql/test/experimental/PoI/TestCustomPoIs.ql @@ -16,7 +16,7 @@ class RouteHandlerAndSetupPoI extends ActivePoI { RouteHandlerAndSetupPoI() { this = "RouteHandlerAndSetupPoI" } override predicate is(Node l0, Node l1, string t1) { - l1.asExpr().(Express::RouteSetup).getARouteHandler() = l0 and t1 = "setup" + l1.(Express::RouteSetup).getARouteHandler() = l0 and t1 = "setup" } } @@ -24,9 +24,9 @@ class RouteSetupAndRouterAndRouteHandlerPoI extends ActivePoI { RouteSetupAndRouterAndRouteHandlerPoI() { this = "RouteSetupAndRouterAndRouteHandlerPoI" } override predicate is(Node l0, Node l1, string t1, Node l2, string t2) { - l0.asExpr().(Express::RouteSetup).getRouter().flow() = l1 and + l0.(Express::RouteSetup).getRouter().flow() = l1 and t1 = "router" and - l0.asExpr().(Express::RouteSetup).getARouteHandler() = l2 and + l0.(Express::RouteSetup).getARouteHandler() = l2 and t2 = "routehandler" } } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup.qll index d291a319a79f..26aff886cfa5 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup.qll @@ -1,6 +1,6 @@ import javascript -query predicate test_RouteSetup(Express::RouteSetup rs, Expr res0, boolean isUseCall) { +query predicate test_RouteSetup(Express::RouteSetup rs, DataFlow::Node res0, boolean isUseCall) { (if rs.isUseCall() then isUseCall = true else isUseCall = false) and res0 = rs.getServer() } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getServer.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getServer.qll index fdb650230003..1b6e30803ac4 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getServer.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getServer.qll @@ -1,3 +1,5 @@ import javascript -query predicate test_RouteSetup_getServer(Express::RouteSetup rs, Expr res) { res = rs.getServer() } +query predicate test_RouteSetup_getServer(Express::RouteSetup rs, DataFlow::Node res) { + res = rs.getServer() +} diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_handlesSameRequestMethodAs.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_handlesSameRequestMethodAs.qll index a39f945f3cab..13f37d703841 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_handlesSameRequestMethodAs.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_handlesSameRequestMethodAs.qll @@ -4,7 +4,7 @@ query predicate test_RouteSetup_handlesSameRequestMethodAs( Express::RouteSetup rs, Express::RouteSetup rs2 ) { rs.handlesSameRequestMethodAs(rs2) and - rs.getLocation().getStartLine() < rs2.getLocation().getStartLine() and - rs.getLocation().getFile().getBaseName() = "csurf-example.js" and - rs2.getLocation().getFile().getBaseName() = "csurf-example.js" + rs.asExpr().getLocation().getStartLine() < rs2.asExpr().getLocation().getStartLine() and + rs.asExpr().getLocation().getFile().getBaseName() = "csurf-example.js" and + rs2.asExpr().getLocation().getFile().getBaseName() = "csurf-example.js" } diff --git a/javascript/ql/test/library-tests/frameworks/Express/StandardRouteHandler.qll b/javascript/ql/test/library-tests/frameworks/Express/StandardRouteHandler.qll index 7d5a60cfab29..26f06678dc8e 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/StandardRouteHandler.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/StandardRouteHandler.qll @@ -1,7 +1,7 @@ import javascript query predicate test_StandardRouteHandler( - Express::StandardRouteHandler rh, Expr res0, SimpleParameter res1, SimpleParameter res2 + Express::StandardRouteHandler rh, DataFlow::Node res0, SimpleParameter res1, SimpleParameter res2 ) { res0 = rh.getServer() and res1 = rh.getRequestParameter() and res2 = rh.getResponseParameter() } diff --git a/javascript/ql/test/library-tests/frameworks/NodeJSLib/HeaderDefinition_getNameExpr.qll b/javascript/ql/test/library-tests/frameworks/NodeJSLib/HeaderDefinition_getNameExpr.qll index 87f73f43770a..b62e44bf9471 100644 --- a/javascript/ql/test/library-tests/frameworks/NodeJSLib/HeaderDefinition_getNameExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/NodeJSLib/HeaderDefinition_getNameExpr.qll @@ -1,5 +1,7 @@ import javascript -query predicate test_HeaderDefinition_getNameExpr(HTTP::ExplicitHeaderDefinition hd, Expr res) { - hd.getRouteHandler() instanceof NodeJSLib::RouteHandler and res = hd.getNameExpr() +query predicate test_HeaderDefinition_getNameExpr( + HTTP::ExplicitHeaderDefinition hd, DataFlow::Node res +) { + hd.getRouteHandler() instanceof NodeJSLib::RouteHandler and res = hd.getNameNode() } diff --git a/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteHandler.qll b/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteHandler.qll index 61f7f8dea0e0..9114d2d48f19 100644 --- a/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteHandler.qll +++ b/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteHandler.qll @@ -1,3 +1,5 @@ import javascript -query predicate test_RouteHandler(NodeJSLib::RouteHandler rh, Expr res) { res = rh.getServer() } +query predicate test_RouteHandler(NodeJSLib::RouteHandler rh, DataFlow::Node res) { + res = rh.getServer() +} diff --git a/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteSetup_getServer.qll b/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteSetup_getServer.qll index a10c7e0da8e7..24dfd61fb666 100644 --- a/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteSetup_getServer.qll +++ b/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteSetup_getServer.qll @@ -1,3 +1,5 @@ import javascript -query predicate test_RouteSetup_getServer(NodeJSLib::RouteSetup r, Expr res) { res = r.getServer() } +query predicate test_RouteSetup_getServer(NodeJSLib::RouteSetup r, DataFlow::Node res) { + res = r.getServer() +} diff --git a/javascript/ql/test/library-tests/frameworks/connect/tests.ql b/javascript/ql/test/library-tests/frameworks/connect/tests.ql index 24ddefeaf5d0..3a521d7f7e7d 100644 --- a/javascript/ql/test/library-tests/frameworks/connect/tests.ql +++ b/javascript/ql/test/library-tests/frameworks/connect/tests.ql @@ -26,7 +26,9 @@ query predicate test_HeaderDefinition(HTTP::HeaderDefinition hd, Connect::RouteH rh = hd.getRouteHandler() } -query predicate test_RouteSetup_getServer(Connect::RouteSetup rs, Expr res) { res = rs.getServer() } +query predicate test_RouteSetup_getServer(Connect::RouteSetup rs, DataFlow::Node res) { + res = rs.getServer() +} query predicate test_HeaderDefinition_getAHeaderName(HTTP::HeaderDefinition hd, string res) { hd.getRouteHandler() instanceof Connect::RouteHandler and res = hd.getAHeaderName() @@ -42,7 +44,9 @@ query predicate test_RouteSetup_getARouteHandler(Connect::RouteSetup r, DataFlow res = r.getARouteHandler() } -query predicate test_RouteHandler(Connect::RouteHandler rh, Expr res) { res = rh.getServer() } +query predicate test_RouteHandler(Connect::RouteHandler rh, DataFlow::Node res) { + res = rh.getServer() +} query predicate test_RequestExpr(HTTP::RequestExpr e, HTTP::RouteHandler res) { res = e.getRouteHandler() diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler.qll index 89598e2169ed..68ec89563ea6 100644 --- a/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler.qll +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler.qll @@ -1,3 +1,5 @@ import javascript -query predicate test_RouteHandler(Fastify::RouteHandler rh, Expr res) { res = rh.getServer() } +query predicate test_RouteHandler(Fastify::RouteHandler rh, DataFlow::Node res) { + res = rh.getServer() +} diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getServer.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getServer.qll index 8339498d0949..5a19750fd507 100644 --- a/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getServer.qll +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteSetup_getServer.qll @@ -1,3 +1,5 @@ import javascript -query predicate test_RouteSetup_getServer(Fastify::RouteSetup rs, Expr res) { res = rs.getServer() } +query predicate test_RouteSetup_getServer(Fastify::RouteSetup rs, DataFlow::Node res) { + res = rs.getServer() +} diff --git a/javascript/ql/test/library-tests/frameworks/hapi/RouteHandler.qll b/javascript/ql/test/library-tests/frameworks/hapi/RouteHandler.qll index 45e51d1b9995..58bcd7ab42bb 100644 --- a/javascript/ql/test/library-tests/frameworks/hapi/RouteHandler.qll +++ b/javascript/ql/test/library-tests/frameworks/hapi/RouteHandler.qll @@ -1,3 +1,5 @@ import javascript -query predicate test_RouteHandler(Hapi::RouteHandler rh, Expr res) { res = rh.getServer() } +query predicate test_RouteHandler(Hapi::RouteHandler rh, DataFlow::Node res) { + res = rh.getServer() +} diff --git a/javascript/ql/test/library-tests/frameworks/hapi/RouteSetup_getServer.qll b/javascript/ql/test/library-tests/frameworks/hapi/RouteSetup_getServer.qll index ffdbe44e168e..11c510a91d67 100644 --- a/javascript/ql/test/library-tests/frameworks/hapi/RouteSetup_getServer.qll +++ b/javascript/ql/test/library-tests/frameworks/hapi/RouteSetup_getServer.qll @@ -1,3 +1,5 @@ import javascript -query predicate test_RouteSetup_getServer(Hapi::RouteSetup rs, Expr res) { res = rs.getServer() } +query predicate test_RouteSetup_getServer(Hapi::RouteSetup rs, DataFlow::Node res) { + res = rs.getServer() +} diff --git a/javascript/ql/test/library-tests/frameworks/koa/RouteHandler.qll b/javascript/ql/test/library-tests/frameworks/koa/RouteHandler.qll index 032d5a293660..1c7fafa4d406 100644 --- a/javascript/ql/test/library-tests/frameworks/koa/RouteHandler.qll +++ b/javascript/ql/test/library-tests/frameworks/koa/RouteHandler.qll @@ -1,3 +1,3 @@ import javascript -query predicate test_RouteHandler(Koa::RouteHandler rh, Expr res) { res = rh.getServer() } +query predicate test_RouteHandler(Koa::RouteHandler rh, DataFlow::Node res) { res = rh.getServer() } diff --git a/javascript/ql/test/library-tests/frameworks/koa/RouteSetup_getServer.qll b/javascript/ql/test/library-tests/frameworks/koa/RouteSetup_getServer.qll index bb674e0d1927..b54b22498175 100644 --- a/javascript/ql/test/library-tests/frameworks/koa/RouteSetup_getServer.qll +++ b/javascript/ql/test/library-tests/frameworks/koa/RouteSetup_getServer.qll @@ -1,3 +1,5 @@ import javascript -query predicate test_RouteSetup_getServer(Koa::RouteSetup rs, Expr res) { res = rs.getServer() } +query predicate test_RouteSetup_getServer(Koa::RouteSetup rs, DataFlow::Node res) { + res = rs.getServer() +} diff --git a/javascript/ql/test/library-tests/frameworks/restify/RouteHandler.qll b/javascript/ql/test/library-tests/frameworks/restify/RouteHandler.qll index c15bb690a72c..dc7315cc4922 100644 --- a/javascript/ql/test/library-tests/frameworks/restify/RouteHandler.qll +++ b/javascript/ql/test/library-tests/frameworks/restify/RouteHandler.qll @@ -1,3 +1,5 @@ import javascript -query predicate test_RouteHandler(Restify::RouteHandler rh, Expr res) { res = rh.getServer() } +query predicate test_RouteHandler(Restify::RouteHandler rh, DataFlow::Node res) { + res = rh.getServer() +} diff --git a/javascript/ql/test/library-tests/frameworks/restify/RouteSetup_getServer.qll b/javascript/ql/test/library-tests/frameworks/restify/RouteSetup_getServer.qll index fb6d67c3e54c..e84c65c3fc20 100644 --- a/javascript/ql/test/library-tests/frameworks/restify/RouteSetup_getServer.qll +++ b/javascript/ql/test/library-tests/frameworks/restify/RouteSetup_getServer.qll @@ -1,3 +1,5 @@ import javascript -query predicate test_RouteSetup_getServer(Restify::RouteSetup rs, Expr res) { res = rs.getServer() } +query predicate test_RouteSetup_getServer(Restify::RouteSetup rs, DataFlow::Node res) { + res = rs.getServer() +} From 30d929909cef9622edefa4d0d786fc1c3cf02142 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 16:18:07 +0200 Subject: [PATCH 09/39] deprecate `RequestExpr` and `ResponseExpr` and use `ResponseNode` and `RequestNode` instead --- .../NosqlInjectionATM.qll | 4 +- .../semmle/javascript/frameworks/Connect.qll | 12 +-- .../semmle/javascript/frameworks/Express.qll | 47 ++++++++---- .../lib/semmle/javascript/frameworks/HTTP.qll | 76 ++++++++++++++++--- .../lib/semmle/javascript/frameworks/Hapi.qll | 56 +++++++++----- .../lib/semmle/javascript/frameworks/Koa.qll | 29 +++++-- .../semmle/javascript/frameworks/Logging.qll | 4 +- .../semmle/javascript/frameworks/Micro.qll | 12 ++- .../javascript/frameworks/NodeJSLib.qll | 68 +++++++++++++---- .../semmle/javascript/frameworks/Restify.qll | 41 ++++++---- .../frameworks/Express/RequestExpr.qll | 4 +- .../frameworks/Express/ResponseExpr.qll | 2 +- .../Express/RouteHandler_getARequestExpr.qll | 4 +- .../Express/RouteHandler_getAResponseExpr.qll | 4 +- .../frameworks/NodeJSLib/RequestExpr.qll | 2 +- .../frameworks/NodeJSLib/ResponseExpr.qll | 2 +- .../RouteHandler_getARequestExpr.qll | 4 +- .../RouteHandler_getAResponseExpr.qll | 4 +- .../library-tests/frameworks/connect/tests.ql | 12 +-- .../fastify/RouteHandler_getARequestExpr.qll | 4 +- .../frameworks/hapi/RequestExpr.qll | 2 +- .../frameworks/hapi/ResponseExpr.qll | 2 +- .../hapi/RouteHandler_getARequestExpr.qll | 4 +- .../frameworks/koa/RequestExpr.qll | 2 +- .../frameworks/koa/ResponseExpr.qll | 2 +- .../koa/RouteHandler_getARequestExpr.qll | 4 +- .../koa/RouteHandler_getAResponseExpr.qll | 4 +- .../frameworks/restify/RequestExpr.qll | 2 +- .../frameworks/restify/ResponseExpr.qll | 2 +- .../restify/RouteHandler_getARequestExpr.qll | 4 +- .../restify/RouteHandler_getAResponseExpr.qll | 4 +- 31 files changed, 290 insertions(+), 133 deletions(-) diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/NosqlInjectionATM.qll b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/NosqlInjectionATM.qll index 2f84c558f3a7..7debdba1f02a 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/NosqlInjectionATM.qll +++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/NosqlInjectionATM.qll @@ -42,10 +42,10 @@ module SinkEndpointFilter { result = "modeled database access" or // Remove calls to APIs that aren't relevant to NoSQL injection - call.getReceiver().asExpr() instanceof HTTP::RequestExpr and + call.getReceiver() instanceof HTTP::RequestNode and result = "receiver is a HTTP request expression" or - call.getReceiver().asExpr() instanceof HTTP::ResponseExpr and + call.getReceiver() instanceof HTTP::ResponseNode and result = "receiver is a HTTP response expression" ) or diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll b/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll index 8cf6b7ccebab..20efe1b97688 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll @@ -108,22 +108,24 @@ module Connect { override string getCredentialsKind() { result = kind } } - class RequestExpr = NodeJSLib::RequestExpr; + deprecated class RequestExpr = NodeJSLib::RequestExpr; + + class RequestNode = NodeJSLib::RequestNode; /** * An access to a user-controlled Connect request input. */ - private class RequestInputAccess extends HTTP::RequestInputAccess { - RequestExpr request; + private class RequestInputAccess extends HTTP::RequestInputAccess instanceof DataFlow::MethodCallNode { + RequestNode request; string kind; RequestInputAccess() { request.getRouteHandler() instanceof StandardRouteHandler and - exists(PropAccess cookies | + exists(DataFlow::PropRead cookies | // `req.cookies.get()` kind = "cookie" and cookies.accesses(request, "cookies") and - this.asExpr().(MethodCallExpr).calls(cookies, "get") + super.calls(cookies, "get") ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index d0d494285248..6041cab9f759 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -409,22 +409,24 @@ module Express { * * `kind` is one of: "error", "request", "response", "next", or "parameter". */ - abstract Parameter getRouteHandlerParameter(string kind); + abstract Parameter getRouteHandlerParameter(string kind); // TODO: DataFlow::ParameterNode /** * Gets the parameter of the route handler that contains the request object. */ - Parameter getRequestParameter() { result = this.getRouteHandlerParameter("request") } + Parameter getRequestParameter() { result = this.getRouteHandlerParameter("request") } // TODO: DataFlow::ParameterNode /** * Gets the parameter of the route handler that contains the response object. */ - Parameter getResponseParameter() { result = this.getRouteHandlerParameter("response") } + Parameter getResponseParameter() { result = this.getRouteHandlerParameter("response") } // TODO: DataFlow::ParameterNode /** * Gets a request body access of this handler. */ - Expr getARequestBodyAccess() { result.(PropAccess).accesses(this.getARequestExpr(), "body") } + Expr getARequestBodyAccess() { + result.(PropAccess).accesses(this.getARequestNode().asExpr(), "body") + } // TODO: DataFlow::Node } /** @@ -448,7 +450,8 @@ module Express { * Holds if `call` is a chainable method call on the response object of `handler`. */ private predicate isChainableResponseMethodCall(RouteHandler handler, MethodCallExpr call) { - exists(string name | call.calls(handler.getAResponseExpr(), name) | + // TODO: DataFlow::MethodCallNode + exists(string name | call.calls(handler.getAResponseNode().asExpr(), name) | name = [ "append", "attachment", "location", "send", "sendStatus", "set", "status", "type", "vary", @@ -516,16 +519,32 @@ module Express { } /** + * DEPRECATED: Use `ResponseNode` instead. * An Express response expression. */ - class ResponseExpr extends NodeJSLib::ResponseExpr { + deprecated class ResponseExpr extends NodeJSLib::ResponseExpr { + ResponseExpr() { this.flow() instanceof ResponseNode } + } + + /** + * An Express response expression. + */ + class ResponseNode extends NodeJSLib::ResponseNode { override ResponseSource src; } + /** + * DEPRECATED: Use `RequestNode` instead. + * An Express request expression. + */ + deprecated class RequestExpr extends NodeJSLib::RequestExpr { + RequestExpr() { this.flow() instanceof RequestNode } + } + /** * An Express request expression. */ - class RequestExpr extends NodeJSLib::RequestExpr { + class RequestNode extends NodeJSLib::RequestNode { override RequestSource src; } @@ -679,12 +698,12 @@ module Express { /** * Holds if `e` is an HTTP request object. */ - predicate isRequest(Expr e) { any(RouteHandler rh).getARequestExpr() = e } // TODO: DataFlow::Node + predicate isRequest(Expr e) { any(RouteHandler rh).getARequestNode().asExpr() = e } // TODO: DataFlow::Node /** * Holds if `e` is an HTTP response object. */ - predicate isResponse(Expr e) { any(RouteHandler rh).getAResponseExpr() = e } // TODO: DataFlow::Node + predicate isResponse(Expr e) { any(RouteHandler rh).getAResponseNode().asExpr() = e } // TODO: DataFlow::Node /** * An access to the HTTP request body. @@ -696,9 +715,7 @@ module Express { abstract private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { HeaderDefinition() { isResponse(this.getReceiver().asExpr()) } - override RouteHandler getRouteHandler() { - this.getReceiver().asExpr() = result.getAResponseExpr() - } + override RouteHandler getRouteHandler() { this.getReceiver() = result.getAResponseNode() } } /** @@ -876,9 +893,7 @@ module Express { * * Example: `router2` for `router1.use(router2)` or `router1.use("/route2", router2)` */ - RouterDefinition getASubRouter() { - result.ref().flowsTo(this.getARouteSetup().getAnArgument()) - } + RouterDefinition getASubRouter() { result.ref().flowsTo(this.getARouteSetup().getAnArgument()) } /** * Gets a route handler registered on this router. @@ -948,7 +963,7 @@ module Express { DataFlow::MethodCallNode { ResponseSendFileAsFileSystemAccess() { exists(string name | name = "sendFile" or name = "sendfile" | - this.calls(any(ResponseExpr res).flow(), name) + this.calls(any(ResponseNode res), name) ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll index 8ff456c36a14..626b29423c89 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll @@ -208,16 +208,30 @@ module HTTP { final Servers::ResponseSource getAResponseSource() { result.getRouteHandler() = this } /** + * DEPRECATED: Use `getARequestNode()` instead. * Gets an expression that contains a request object handled * by this handler. */ - RequestExpr getARequestExpr() { result.getRouteHandler() = this } // TODO: DataFlow::Node + deprecated RequestExpr getARequestExpr() { result.flow() = this.getARequestNode() } + + /** + * Gets an expression that contains a request object handled + * by this handler. + */ + RequestNode getARequestNode() { result.getRouteHandler() = this } + + /** + * DEPRECATED: Use `getAResponseNode()` instead. + * Gets an expression that contains a response object provided + * by this handler. + */ + deprecated ResponseExpr getAResponseExpr() { result.flow() = this.getAResponseNode() } /** * Gets an expression that contains a response object provided * by this handler. */ - ResponseExpr getAResponseExpr() { result.getRouteHandler() = this } // TODO: DataFlow::Node + ResponseNode getAResponseNode() { result.getRouteHandler() = this } } /** @@ -244,26 +258,40 @@ module HTTP { */ abstract class RouteSetup extends DataFlow::Node { } + /** A dataflow node that may contain a request object. */ + abstract class RequestNode extends DataFlow::Node { + /** Gets the route handler that handles this request. */ + abstract RouteHandler getRouteHandler(); + } + + /** An dataflow node that may contain a response object. */ + abstract class ResponseNode extends DataFlow::Node { + /** Gets the route handler that handles this request. */ + abstract RouteHandler getRouteHandler(); + } + /** + * DEPRECATED: Use `RequestNode` instead. * An expression that may contain a request object. */ - abstract class RequestExpr extends Expr { - // TODO: DataFlow::Node + deprecated class RequestExpr extends Expr { + RequestExpr() { this.flow() instanceof ResponseNode } + /** * Gets the route handler that handles this request. */ - abstract RouteHandler getRouteHandler(); + RouteHandler getRouteHandler() { result = this.flow().(ResponseNode).getRouteHandler() } } /** + * DEPRECATED: Use `ResponseNode` instead. * An expression that may contain a response object. */ - abstract class ResponseExpr extends Expr { - // TODO: DataFlow::Node + deprecated class ResponseExpr extends Expr { /** * Gets the route handler that handles this request. */ - abstract RouteHandler getRouteHandler(); + RouteHandler getRouteHandler() { result = this.flow().(ResponseNode).getRouteHandler() } } /** @@ -366,10 +394,10 @@ module HTTP { /** * A request expression arising from a request source. */ - class StandardRequestExpr extends RequestExpr { + class StandardRequestNode extends RequestNode { RequestSource src; - StandardRequestExpr() { src.ref().flowsTo(DataFlow::valueNode(this)) } + StandardRequestNode() { src.ref().flowsTo(this) } override RouteHandler getRouteHandler() { result = src.getRouteHandler() } } @@ -377,14 +405,38 @@ module HTTP { /** * A response expression arising from a response source. */ - class StandardResponseExpr extends ResponseExpr { + class StandardResponseNode extends ResponseNode { ResponseSource src; - StandardResponseExpr() { src.ref().flowsTo(DataFlow::valueNode(this)) } + StandardResponseNode() { src.ref().flowsTo(this) } override RouteHandler getRouteHandler() { result = src.getRouteHandler() } } + /** + * A request expression arising from a request source. + */ + deprecated class StandardRequestExpr extends RequestExpr { + RequestSource src; + + StandardRequestExpr() { src.ref().flowsToExpr(this) } + + override RouteHandler getRouteHandler() { result = src.getRouteHandler() } + } + + /** + * A response expression arising from a response source. + */ + deprecated class StandardResponseExpr extends ResponseExpr { + ResponseSource src; + + StandardResponseExpr() { src.ref().flowsToExpr(this) } + + override RouteHandler getRouteHandler() { + result = this.flow().(StandardResponseNode).getRouteHandler() + } + } + /** * A standard header definition. */ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll index 0b1923a24af7..a7f1fd0a56a7 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll @@ -49,9 +49,9 @@ module Hapi { * of a request object. */ private class ResponseSource extends HTTP::Servers::ResponseSource { - RequestExpr req; + RequestNode req; - ResponseSource() { asExpr().(PropAccess).accesses(req, "response") } + ResponseSource() { this.(DataFlow::PropRead).accesses(req, "response") } /** * Gets the route handler that provides this response. @@ -74,19 +74,33 @@ module Hapi { override RouteHandler getRouteHandler() { result = rh } } - // TODO: DataFlow::Node /** + * DEPRECATED: Use `ResponseNode` instead. * A Hapi response expression. */ - class ResponseExpr extends HTTP::Servers::StandardResponseExpr { + deprecated class ResponseExpr extends HTTP::Servers::StandardResponseExpr { + ResponseExpr() { this.flow() instanceof ResponseNode } + } + + /** + * A Hapi response node. + */ + class ResponseNode extends HTTP::Servers::StandardResponseNode { override ResponseSource src; } - // TODO: DataFlow::Node /** + * DEPRECATED: Use `RequestNode` instead. * An Hapi request expression. */ - class RequestExpr extends HTTP::Servers::StandardRequestExpr { + deprecated class RequestExpr extends HTTP::Servers::StandardRequestExpr { + RequestExpr() { this.flow() instanceof RequestNode } + } + + /** + * A Hapi request node. + */ + class RequestNode extends HTTP::Servers::StandardRequestNode { override RequestSource src; } @@ -98,38 +112,38 @@ module Hapi { string kind; RequestInputAccess() { - exists(Expr request | request = rh.getARequestExpr() | + exists(DataFlow::Node request | request = rh.getARequestNode() | kind = "body" and ( // `request.rawPayload` - this.asExpr().(PropAccess).accesses(request, "rawPayload") + this.(DataFlow::PropRead).accesses(request, "rawPayload") or - exists(PropAccess payload | + exists(DataFlow::PropRead payload | // `request.payload.name` payload.accesses(request, "payload") and - this.asExpr().(PropAccess).accesses(payload, _) + this.(DataFlow::PropRead).accesses(payload, _) ) ) or kind = "parameter" and - exists(PropAccess query | + exists(DataFlow::PropRead query | // `request.query.name` query.accesses(request, "query") and - this.asExpr().(PropAccess).accesses(query, _) + this.(DataFlow::PropRead).accesses(query, _) ) or - exists(PropAccess url | + exists(DataFlow::PropRead url | // `request.url.path` kind = "url" and url.accesses(request, "url") and - this.asExpr().(PropAccess).accesses(url, "path") + this.(DataFlow::PropRead).accesses(url, "path") ) or - exists(PropAccess state | + exists(DataFlow::PropRead state | // `request.state.` kind = "cookie" and state.accesses(request, "state") and - this.asExpr().(PropAccess).accesses(state, _) + this.(DataFlow::PropRead).accesses(state, _) ) ) or @@ -151,11 +165,11 @@ module Hapi { RouteHandler rh; RequestHeaderAccess() { - exists(Expr request | request = rh.getARequestExpr() | - exists(PropAccess headers | + exists(DataFlow::Node request | request = rh.getARequestNode() | + exists(DataFlow::PropRead headers | // `request.headers.` headers.accesses(request, "headers") and - this.asExpr().(PropAccess).accesses(headers, _) + this.(DataFlow::PropRead).accesses(headers, _) ) ) } @@ -173,11 +187,11 @@ module Hapi { * An HTTP header defined in a Hapi server. */ private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { - ResponseExpr res; + ResponseNode res; HeaderDefinition() { // request.response.header('Cache-Control', 'no-cache') - this.calls(res.flow(), "header") + this.calls(res, "header") } override RouteHandler getRouteHandler() { result = res.getRouteHandler() } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll index 7c5d2fe6655f..e45dfd90127e 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll @@ -27,7 +27,7 @@ module Koa { this.calls(rh.getAResponseOrContextExpr().flow(), "set") or // ctx.response.header('Cache-Control', 'no-cache') - this.calls(rh.getAResponseExpr().flow(), "header") + this.calls(rh.getAResponseNode(), "header") } override RouteHandler getRouteHandler() { result = rh } @@ -60,7 +60,7 @@ module Koa { */ Expr getAResponseOrContextExpr() { // TODO: DataFlow::Node - result = this.getAResponseExpr() or result = this.getAContextExpr() + result = this.getAResponseNode().asExpr() or result = this.getAContextExpr() } /** @@ -68,7 +68,8 @@ module Koa { * object of a route handler invocation. */ Expr getARequestOrContextExpr() { - result = this.getARequestExpr() or result = this.getAContextExpr() + // TODO: DataFlow::Node + result = this.getARequestNode().asExpr() or result = this.getAContextExpr() } /** @@ -265,17 +266,33 @@ module Koa { RouteHandler getRouteHandler() { result = src.getRouteHandler() } } + /** + * DEPRECATED: Use `RequestNode` instead. + * An expression that may hold a Koa request object. + */ + deprecated class RequestExpr extends HTTP::Servers::StandardRequestExpr { + RequestExpr() { this.flow() instanceof RequestNode } + } + /** * An expression that may hold a Koa request object. */ - class RequestExpr extends HTTP::Servers::StandardRequestExpr { + class RequestNode extends HTTP::Servers::StandardRequestNode { override RequestSource src; } + /** + * DEPRECATED: Use `ResponseNode` instead. + * An expression that may hold a Koa response object. + */ + deprecated class ResponseExpr extends HTTP::Servers::StandardResponseExpr { + ResponseExpr() { this.flow() instanceof ResponseNode } + } + /** * An expression that may hold a Koa response object. */ - class ResponseExpr extends HTTP::Servers::StandardResponseExpr { + class ResponseNode extends HTTP::Servers::StandardResponseNode { override ResponseSource src; } @@ -311,7 +328,7 @@ module Koa { this.asExpr().(PropAccess).accesses(e, "params") or // `ctx.request.body` - e instanceof RequestExpr and + e.flow() instanceof RequestNode and kind = "body" and this.asExpr().(PropAccess).accesses(e, "body") or diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Logging.qll b/javascript/ql/lib/semmle/javascript/frameworks/Logging.qll index 8f5938f4865a..ba99fc014d17 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Logging.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Logging.qll @@ -349,8 +349,8 @@ private module Pino { or // `pino` is installed as the "log" property on the request object in `Express` and similar libraries. // in `Hapi` the property is "logger". - exists(HTTP::RequestExpr req, API::Node reqNode | - reqNode.asSource() = req.flow().getALocalSource() and + exists(HTTP::RequestNode req, API::Node reqNode | + reqNode.asSource() = req.getALocalSource() and result = reqNode.getMember(["log", "logger"]) ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Micro.qll b/javascript/ql/lib/semmle/javascript/frameworks/Micro.qll index 349e44f2e6dc..7ac9b1349d8b 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Micro.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Micro.qll @@ -62,11 +62,19 @@ private module Micro { override HTTP::RouteHandler getRouteHandler() { result = h } } - class MicroRequestExpr extends NodeJSLib::RequestExpr { + deprecated class MicroRequestExpr extends NodeJSLib::RequestExpr { override MicroRequestSource src; } - class MicroReseponseExpr extends NodeJSLib::ResponseExpr { + class MicroRequestNode extends NodeJSLib::RequestNode { + override MicroRequestSource src; + } + + deprecated class MicroReseponseExpr extends NodeJSLib::ResponseExpr { + override MicroResponseSource src; + } + + class MicroResponseNode extends NodeJSLib::ResponseNode { override MicroResponseSource src; } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll index bd34abb12655..559b26df2e6b 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll @@ -66,12 +66,34 @@ module NodeJSLib { } /** + * DEPRECATED: Use `ResponseNode` instead. * A Node.js HTTP response. * * A server library that provides an (enhanced) NodesJS HTTP response * object should implement a library specific subclass of this class. */ - abstract class ResponseExpr extends HTTP::Servers::StandardResponseExpr { } + deprecated class ResponseExpr extends HTTP::Servers::StandardResponseExpr { + ResponseExpr() { this.flow() instanceof ResponseNode } + } + + /** + * A Node.js HTTP response. + * + * A server library that provides an (enhanced) NodesJS HTTP response + * object should implement a library specific subclass of this class. + */ + abstract class ResponseNode extends HTTP::Servers::StandardResponseNode { } + + /** + * DEPRECATED: Use `RequestNode` instead. + * A Node.js HTTP request. + * + * A server library that provides an (enhanced) NodesJS HTTP request + * object should implement a library specific subclass of this class. + */ + deprecated class RequestExpr extends HTTP::Servers::StandardRequestExpr { + RequestExpr() { this.flow() instanceof RequestNode } + } /** * A Node.js HTTP request. @@ -79,7 +101,7 @@ module NodeJSLib { * A server library that provides an (enhanced) NodesJS HTTP request * object should implement a library specific subclass of this class. */ - abstract class RequestExpr extends HTTP::Servers::StandardRequestExpr { } + abstract class RequestNode extends HTTP::Servers::StandardRequestNode { } /** * A function used as an Node.js server route handler. @@ -148,36 +170,52 @@ module NodeJSLib { } /** + * DEPRECATED: Use `BuiltinRouteHandlerResponseNode` instead. * A builtin Node.js HTTP response. */ - private class BuiltinRouteHandlerResponseExpr extends ResponseExpr { + deprecated private class BuiltinRouteHandlerResponseExpr extends ResponseExpr { BuiltinRouteHandlerResponseExpr() { src instanceof ResponseSource } } /** + * A builtin Node.js HTTP response. + */ + private class BuiltinRouteHandlerResponseNode extends ResponseNode { + BuiltinRouteHandlerResponseNode() { src instanceof ResponseSource } + } + + /** + * DEPRECATED: Use `BuiltinRouteHandlerRequestNode` instead. * A builtin Node.js HTTP request. */ - private class BuiltinRouteHandlerRequestExpr extends RequestExpr { + deprecated private class BuiltinRouteHandlerRequestExpr extends RequestExpr { BuiltinRouteHandlerRequestExpr() { src instanceof RequestSource } } + /** + * A builtin Node.js HTTP request. + */ + private class BuiltinRouteHandlerRequestNode extends RequestNode { + BuiltinRouteHandlerRequestNode() { src instanceof RequestSource } + } + /** * An access to a user-controlled Node.js request input. */ private class RequestInputAccess extends HTTP::RequestInputAccess { - RequestExpr request; + RequestNode request; string kind; RequestInputAccess() { // `req.url` / `req.body` kind = ["url", "body"] and - this.asExpr().(PropAccess).accesses(request, kind) + this.(DataFlow::PropRead).accesses(request, kind) or - exists(PropAccess headers | + exists(DataFlow::PropRead headers | // `req.headers.cookie` kind = "cookie" and headers.accesses(request, "headers") and - this.asExpr().(PropAccess).accesses(headers, "cookie") + this.(DataFlow::PropRead).accesses(headers, "cookie") ) or exists(RequestHeaderAccess access | this = access | @@ -195,14 +233,14 @@ module NodeJSLib { * An access to an HTTP header (other than "Cookie") on an incoming Node.js request object. */ private class RequestHeaderAccess extends HTTP::RequestHeaderAccess { - RequestExpr request; + RequestNode request; RequestHeaderAccess() { - exists(PropAccess headers, string name | + exists(DataFlow::PropRead headers, string name | // `req.headers.` name != "cookie" and headers.accesses(request, "headers") and - this.asExpr().(PropAccess).accesses(headers, name) + this.(DataFlow::PropRead).accesses(headers, name) ) } @@ -214,7 +252,7 @@ module NodeJSLib { override string getKind() { result = "header" } - RequestExpr getRequest() { result = request } + RequestNode getRequest() { result = request } } class RouteSetup extends DataFlow::CallNode, HTTP::Servers::StandardRouteSetup { @@ -258,9 +296,9 @@ module NodeJSLib { } abstract private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { - ResponseExpr r; + ResponseNode r; - HeaderDefinition() { this.getReceiver().asExpr() = r } + HeaderDefinition() { this.getReceiver() = r } override HTTP::RouteHandler getRouteHandler() { result = r.getRouteHandler() } } @@ -365,7 +403,7 @@ module NodeJSLib { ResponseSendArgument() { exists(DataFlow::MethodCallNode mcn, string m | m = "write" or m = "end" | - mcn.calls(any(ResponseExpr e | e.getRouteHandler() = rh).flow(), m) and + mcn.calls(any(ResponseNode e | e.getRouteHandler() = rh), m) and this = mcn.getArgument(0) and // don't mistake callback functions as data not this.analyze().getAValue() instanceof AbstractFunction diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll b/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll index 7f14e9040e7a..0a782b32f1c8 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll @@ -68,41 +68,55 @@ module Restify { override RouteHandler getRouteHandler() { result = rh } } - // TODO: DataFlow::Node /** + * DEPRECATED: Use `ResponseNode` instead. * A Node.js HTTP response provided by Restify. */ - class ResponseExpr extends NodeJSLib::ResponseExpr { + deprecated class ResponseExpr extends NodeJSLib::ResponseExpr { ResponseExpr() { src instanceof ResponseSource } } - // TODO: DataFlow::Node /** + * A Node.js HTTP response provided by Restify. + */ + class ResponseNode extends NodeJSLib::ResponseNode { + ResponseNode() { src instanceof ResponseSource } + } + + /** + * DEPRECATED: Use `RequestNode` instead. * A Node.js HTTP request provided by Restify. */ - class RequestExpr extends NodeJSLib::RequestExpr { + deprecated class RequestExpr extends NodeJSLib::RequestExpr { RequestExpr() { src instanceof RequestSource } } + /** + * A Node.js HTTP request provided by Restify. + */ + class RequestNode extends NodeJSLib::RequestNode { + RequestNode() { src instanceof RequestSource } + } + /** * An access to a user-controlled Restify request input. */ private class RequestInputAccess extends HTTP::RequestInputAccess { - RequestExpr request; + RequestNode request; string kind; RequestInputAccess() { - exists(MethodCallExpr query | + exists(DataFlow::MethodCallNode query | // `request.getQuery().` kind = "parameter" and query.calls(request, "getQuery") and - this.asExpr().(PropAccess).accesses(query, _) + this.(DataFlow::PropRead).accesses(query, _) ) or exists(string methodName | // `request.href()` or `request.getPath()` kind = "url" and - this.asExpr().(MethodCallExpr).calls(request, methodName) + this.(DataFlow::MethodCallNode).calls(request, methodName) | methodName = "href" or methodName = "getPath" @@ -110,13 +124,12 @@ module Restify { or // `request.getContentType()`, `request.userAgent()`, `request.trailer(...)`, `request.header(...)` kind = "header" and - this.asExpr() - .(MethodCallExpr) + this.(DataFlow::MethodCallNode) .calls(request, ["getContentType", "userAgent", "trailer", "header"]) or // `req.cookies kind = "cookie" and - this.asExpr().(PropAccess).accesses(request, "cookies") + this.(DataFlow::PropRead).accesses(request, "cookies") } override RouteHandler getRouteHandler() { result = request.getRouteHandler() } @@ -130,13 +143,11 @@ module Restify { private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { HeaderDefinition() { // response.header('Cache-Control', 'no-cache') - this.getReceiver().asExpr() instanceof ResponseExpr and + this.getReceiver() instanceof ResponseNode and this.getMethodName() = "header" } - override RouteHandler getRouteHandler() { - this.getReceiver().asExpr() = result.getAResponseExpr() - } + override RouteHandler getRouteHandler() { this.getReceiver() = result.getAResponseNode() } } /** diff --git a/javascript/ql/test/library-tests/frameworks/Express/RequestExpr.qll b/javascript/ql/test/library-tests/frameworks/Express/RequestExpr.qll index b2e780fa3a58..87c0bf32b0fe 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RequestExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RequestExpr.qll @@ -1,9 +1,9 @@ import javascript -query predicate test_RequestExpr(Express::RequestExpr e, HTTP::RouteHandler res) { +query predicate test_RequestExpr(Express::RequestNode e, HTTP::RouteHandler res) { res = e.getRouteHandler() } -query predicate test_RequestExprStandalone(Express::RequestExpr e) { +query predicate test_RequestExprStandalone(Express::RequestNode e) { not exists(e.getRouteHandler()) } diff --git a/javascript/ql/test/library-tests/frameworks/Express/ResponseExpr.qll b/javascript/ql/test/library-tests/frameworks/Express/ResponseExpr.qll index 25356cfd48cb..ad96e9435113 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/ResponseExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/ResponseExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_ResponseExpr(Express::ResponseExpr e, HTTP::RouteHandler res) { +query predicate test_ResponseExpr(Express::ResponseNode e, HTTP::RouteHandler res) { res = e.getRouteHandler() } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getARequestExpr.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getARequestExpr.qll index 77cbf26c64cb..652b0a1bbde8 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getARequestExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getARequestExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_RouteHandler_getARequestExpr(Express::RouteHandler rh, HTTP::RequestExpr res) { - res = rh.getARequestExpr() +query predicate test_RouteHandler_getARequestExpr(Express::RouteHandler rh, HTTP::RequestNode res) { + res = rh.getARequestNode() } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getAResponseExpr.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getAResponseExpr.qll index 499f53fc7df4..6f9fece338d6 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getAResponseExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getAResponseExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_RouteHandler_getAResponseExpr(Express::RouteHandler rh, HTTP::ResponseExpr res) { - res = rh.getAResponseExpr() +query predicate test_RouteHandler_getAResponseExpr(Express::RouteHandler rh, HTTP::ResponseNode res) { + res = rh.getAResponseNode() } diff --git a/javascript/ql/test/library-tests/frameworks/NodeJSLib/RequestExpr.qll b/javascript/ql/test/library-tests/frameworks/NodeJSLib/RequestExpr.qll index 50db052e6258..282c04ce3140 100644 --- a/javascript/ql/test/library-tests/frameworks/NodeJSLib/RequestExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/NodeJSLib/RequestExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_RequestExpr(NodeJSLib::RequestExpr e, HTTP::RouteHandler res) { +query predicate test_RequestExpr(NodeJSLib::RequestNode e, HTTP::RouteHandler res) { res = e.getRouteHandler() } diff --git a/javascript/ql/test/library-tests/frameworks/NodeJSLib/ResponseExpr.qll b/javascript/ql/test/library-tests/frameworks/NodeJSLib/ResponseExpr.qll index 106b07d90062..b509b70c884e 100644 --- a/javascript/ql/test/library-tests/frameworks/NodeJSLib/ResponseExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/NodeJSLib/ResponseExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_ResponseExpr(NodeJSLib::ResponseExpr e, HTTP::RouteHandler res) { +query predicate test_ResponseExpr(NodeJSLib::ResponseNode e, HTTP::RouteHandler res) { res = e.getRouteHandler() } diff --git a/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteHandler_getARequestExpr.qll b/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteHandler_getARequestExpr.qll index e43789bb1a7f..147e788d6423 100644 --- a/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteHandler_getARequestExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteHandler_getARequestExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_RouteHandler_getARequestExpr(NodeJSLib::RouteHandler rh, HTTP::RequestExpr res) { - res = rh.getARequestExpr() +query predicate test_RouteHandler_getARequestExpr(NodeJSLib::RouteHandler rh, HTTP::RequestNode res) { + res = rh.getARequestNode() } diff --git a/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteHandler_getAResponseExpr.qll b/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteHandler_getAResponseExpr.qll index fcef32d90e9c..f28717545510 100644 --- a/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteHandler_getAResponseExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/NodeJSLib/RouteHandler_getAResponseExpr.qll @@ -1,7 +1,7 @@ import javascript query predicate test_RouteHandler_getAResponseExpr( - NodeJSLib::RouteHandler rh, HTTP::ResponseExpr res + NodeJSLib::RouteHandler rh, HTTP::ResponseNode res ) { - res = rh.getAResponseExpr() + res = rh.getAResponseNode() } diff --git a/javascript/ql/test/library-tests/frameworks/connect/tests.ql b/javascript/ql/test/library-tests/frameworks/connect/tests.ql index 3a521d7f7e7d..17211377fbf5 100644 --- a/javascript/ql/test/library-tests/frameworks/connect/tests.ql +++ b/javascript/ql/test/library-tests/frameworks/connect/tests.ql @@ -18,7 +18,7 @@ query predicate test_HeaderDefinition_defines(HTTP::HeaderDefinition hd, string hd.defines(name, value) and hd.getRouteHandler() instanceof Connect::RouteHandler } -query predicate test_ResponseExpr(HTTP::ResponseExpr e, HTTP::RouteHandler res) { +query predicate test_ResponseExpr(HTTP::ResponseNode e, HTTP::RouteHandler res) { res = e.getRouteHandler() } @@ -36,8 +36,8 @@ query predicate test_HeaderDefinition_getAHeaderName(HTTP::HeaderDefinition hd, query predicate test_ServerDefinition(Connect::ServerDefinition s) { any() } -query predicate test_RouteHandler_getAResponseExpr(Connect::RouteHandler rh, HTTP::ResponseExpr res) { - res = rh.getAResponseExpr() +query predicate test_RouteHandler_getAResponseExpr(Connect::RouteHandler rh, HTTP::ResponseNode res) { + res = rh.getAResponseNode() } query predicate test_RouteSetup_getARouteHandler(Connect::RouteSetup r, DataFlow::SourceNode res) { @@ -48,7 +48,7 @@ query predicate test_RouteHandler(Connect::RouteHandler rh, DataFlow::Node res) res = rh.getServer() } -query predicate test_RequestExpr(HTTP::RequestExpr e, HTTP::RouteHandler res) { +query predicate test_RequestExpr(HTTP::RequestNode e, HTTP::RouteHandler res) { res = e.getRouteHandler() } @@ -56,6 +56,6 @@ query predicate test_Credentials(Connect::Credentials cr, string res) { res = cr.getCredentialsKind() } -query predicate test_RouteHandler_getARequestExpr(Connect::RouteHandler rh, HTTP::RequestExpr res) { - res = rh.getARequestExpr() +query predicate test_RouteHandler_getARequestExpr(Connect::RouteHandler rh, HTTP::RequestNode res) { + res = rh.getARequestNode() } diff --git a/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getARequestExpr.qll b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getARequestExpr.qll index dbc8d7cb8968..c709d84e745b 100644 --- a/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getARequestExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/fastify/RouteHandler_getARequestExpr.qll @@ -1,5 +1,5 @@ import semmle.javascript.frameworks.Express -query predicate test_RouteHandler_getARequestExpr(Fastify::RouteHandler rh, HTTP::RequestExpr res) { - res = rh.getARequestExpr() +query predicate test_RouteHandler_getARequestExpr(Fastify::RouteHandler rh, HTTP::RequestNode res) { + res = rh.getARequestNode() } diff --git a/javascript/ql/test/library-tests/frameworks/hapi/RequestExpr.qll b/javascript/ql/test/library-tests/frameworks/hapi/RequestExpr.qll index d412847a950e..6e3118f13452 100644 --- a/javascript/ql/test/library-tests/frameworks/hapi/RequestExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/hapi/RequestExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_RequestExpr(Hapi::RequestExpr e, HTTP::RouteHandler res) { +query predicate test_RequestExpr(Hapi::RequestNode e, HTTP::RouteHandler res) { res = e.getRouteHandler() } diff --git a/javascript/ql/test/library-tests/frameworks/hapi/ResponseExpr.qll b/javascript/ql/test/library-tests/frameworks/hapi/ResponseExpr.qll index 9acfedd73f79..93a356284fea 100644 --- a/javascript/ql/test/library-tests/frameworks/hapi/ResponseExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/hapi/ResponseExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_ResponseExpr(Hapi::ResponseExpr e, HTTP::RouteHandler res) { +query predicate test_ResponseExpr(Hapi::ResponseNode e, HTTP::RouteHandler res) { res = e.getRouteHandler() } diff --git a/javascript/ql/test/library-tests/frameworks/hapi/RouteHandler_getARequestExpr.qll b/javascript/ql/test/library-tests/frameworks/hapi/RouteHandler_getARequestExpr.qll index 51b719430d76..668ded20aea7 100644 --- a/javascript/ql/test/library-tests/frameworks/hapi/RouteHandler_getARequestExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/hapi/RouteHandler_getARequestExpr.qll @@ -1,5 +1,5 @@ import semmle.javascript.frameworks.Express -query predicate test_RouteHandler_getARequestExpr(Hapi::RouteHandler rh, HTTP::RequestExpr res) { - res = rh.getARequestExpr() +query predicate test_RouteHandler_getARequestExpr(Hapi::RouteHandler rh, HTTP::RequestNode res) { + res = rh.getARequestNode() } diff --git a/javascript/ql/test/library-tests/frameworks/koa/RequestExpr.qll b/javascript/ql/test/library-tests/frameworks/koa/RequestExpr.qll index cb80c0da255a..bcb3177b0534 100644 --- a/javascript/ql/test/library-tests/frameworks/koa/RequestExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/koa/RequestExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_RequestExpr(Koa::RequestExpr e, HTTP::RouteHandler res) { +query predicate test_RequestExpr(Koa::RequestNode e, HTTP::RouteHandler res) { res = e.getRouteHandler() } diff --git a/javascript/ql/test/library-tests/frameworks/koa/ResponseExpr.qll b/javascript/ql/test/library-tests/frameworks/koa/ResponseExpr.qll index dc846988cc23..908dcdc745fb 100644 --- a/javascript/ql/test/library-tests/frameworks/koa/ResponseExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/koa/ResponseExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_ResponseExpr(Koa::ResponseExpr e, HTTP::RouteHandler res) { +query predicate test_ResponseExpr(Koa::ResponseNode e, HTTP::RouteHandler res) { res = e.getRouteHandler() } diff --git a/javascript/ql/test/library-tests/frameworks/koa/RouteHandler_getARequestExpr.qll b/javascript/ql/test/library-tests/frameworks/koa/RouteHandler_getARequestExpr.qll index ca15b9b465b5..3c844c953e4c 100644 --- a/javascript/ql/test/library-tests/frameworks/koa/RouteHandler_getARequestExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/koa/RouteHandler_getARequestExpr.qll @@ -1,5 +1,5 @@ import semmle.javascript.frameworks.Express -query predicate test_RouteHandler_getARequestExpr(Koa::RouteHandler rh, HTTP::RequestExpr res) { - res = rh.getARequestExpr() +query predicate test_RouteHandler_getARequestExpr(Koa::RouteHandler rh, HTTP::RequestNode res) { + res = rh.getARequestNode() } diff --git a/javascript/ql/test/library-tests/frameworks/koa/RouteHandler_getAResponseExpr.qll b/javascript/ql/test/library-tests/frameworks/koa/RouteHandler_getAResponseExpr.qll index 6d5fa8ff7464..492386d40537 100644 --- a/javascript/ql/test/library-tests/frameworks/koa/RouteHandler_getAResponseExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/koa/RouteHandler_getAResponseExpr.qll @@ -1,5 +1,5 @@ import semmle.javascript.frameworks.Express -query predicate test_RouteHandler_getAResponseExpr(Koa::RouteHandler rh, HTTP::ResponseExpr res) { - res = rh.getAResponseExpr() +query predicate test_RouteHandler_getAResponseExpr(Koa::RouteHandler rh, HTTP::ResponseNode res) { + res = rh.getAResponseNode() } diff --git a/javascript/ql/test/library-tests/frameworks/restify/RequestExpr.qll b/javascript/ql/test/library-tests/frameworks/restify/RequestExpr.qll index 16facf7c3a91..c4759c6892fc 100644 --- a/javascript/ql/test/library-tests/frameworks/restify/RequestExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/restify/RequestExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_RequestExpr(Restify::RequestExpr e, HTTP::RouteHandler res) { +query predicate test_RequestExpr(Restify::RequestNode e, HTTP::RouteHandler res) { res = e.getRouteHandler() } diff --git a/javascript/ql/test/library-tests/frameworks/restify/ResponseExpr.qll b/javascript/ql/test/library-tests/frameworks/restify/ResponseExpr.qll index a02524c0b9fd..1384ad6c8501 100644 --- a/javascript/ql/test/library-tests/frameworks/restify/ResponseExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/restify/ResponseExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_ResponseExpr(Restify::ResponseExpr e, HTTP::RouteHandler res) { +query predicate test_ResponseExpr(Restify::ResponseNode e, HTTP::RouteHandler res) { res = e.getRouteHandler() } diff --git a/javascript/ql/test/library-tests/frameworks/restify/RouteHandler_getARequestExpr.qll b/javascript/ql/test/library-tests/frameworks/restify/RouteHandler_getARequestExpr.qll index 97c54cbceff7..d02c6f82ad32 100644 --- a/javascript/ql/test/library-tests/frameworks/restify/RouteHandler_getARequestExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/restify/RouteHandler_getARequestExpr.qll @@ -1,5 +1,5 @@ import semmle.javascript.frameworks.Express -query predicate test_RouteHandler_getARequestExpr(Restify::RouteHandler rh, HTTP::RequestExpr res) { - res = rh.getARequestExpr() +query predicate test_RouteHandler_getARequestExpr(Restify::RouteHandler rh, HTTP::RequestNode res) { + res = rh.getARequestNode() } diff --git a/javascript/ql/test/library-tests/frameworks/restify/RouteHandler_getAResponseExpr.qll b/javascript/ql/test/library-tests/frameworks/restify/RouteHandler_getAResponseExpr.qll index 749964afa526..e09d139d6517 100644 --- a/javascript/ql/test/library-tests/frameworks/restify/RouteHandler_getAResponseExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/restify/RouteHandler_getAResponseExpr.qll @@ -1,5 +1,5 @@ import semmle.javascript.frameworks.Express -query predicate test_RouteHandler_getAResponseExpr(Restify::RouteHandler rh, HTTP::ResponseExpr res) { - res = rh.getAResponseExpr() +query predicate test_RouteHandler_getAResponseExpr(Restify::RouteHandler rh, HTTP::ResponseNode res) { + res = rh.getAResponseNode() } From 288230d7cf414a53b0f3a9a3b6a25c779d848355 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 16:18:55 +0200 Subject: [PATCH 10/39] update tests to reflect the extra DataFlow::Nodes from `ResponseNode` and `RequestNode` --- .../frameworks/Express/tests.expected | 167 ++++++++++++++++++ .../frameworks/connect/tests.expected | 11 ++ .../frameworks/fastify/tests.expected | 5 + .../frameworks/hapi/tests.expected | 4 + .../frameworks/koa/tests.expected | 2 + .../frameworks/restify/tests.expected | 6 + 6 files changed, 195 insertions(+) diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index 898a778ce1bb..a4b5397d9508 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -1067,37 +1067,52 @@ test_ResponseExpr | src/advanced-routehandler-registration.js:24:12:24:14 | res | src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:25:12:25:14 | res | src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:46:25:46:27 | res | src/advanced-routehandler-registration.js:46:11:48:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:46:25:46:27 | res | src/advanced-routehandler-registration.js:46:11:48:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:46:25:46:27 | res | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:46:25:46:27 | res | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:47:32:47:34 | res | src/advanced-routehandler-registration.js:46:11:48:3 | functio ... s);\\n } | | src/advanced-routehandler-registration.js:47:32:47:34 | res | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:51:15:51:17 | res | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:51:15:51:17 | res | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:51:45:51:47 | res | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:59:25:59:27 | res | src/advanced-routehandler-registration.js:59:11:61:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:59:25:59:27 | res | src/advanced-routehandler-registration.js:59:11:61:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:59:25:59:27 | res | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:59:25:59:27 | res | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:60:23:60:25 | res | src/advanced-routehandler-registration.js:59:11:61:3 | functio ... s);\\n } | | src/advanced-routehandler-registration.js:60:23:60:25 | res | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:64:15:64:17 | res | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:64:15:64:17 | res | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:64:50:64:52 | res | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:68:18:68:20 | res | src/advanced-routehandler-registration.js:68:12:68:41 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:68:18:68:20 | res | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | | src/advanced-routehandler-registration.js:68:18:68:20 | res | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:69:25:69:27 | res | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:69:25:69:27 | res | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:69:25:69:27 | res | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:69:25:69:27 | res | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:70:23:70:25 | res | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | | src/advanced-routehandler-registration.js:70:23:70:25 | res | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:73:15:73:17 | res | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:73:15:73:17 | res | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:73:52:73:54 | res | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:81:25:81:27 | res | src/advanced-routehandler-registration.js:81:11:83:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:81:25:81:27 | res | src/advanced-routehandler-registration.js:81:11:83:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:81:25:81:27 | res | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:81:25:81:27 | res | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:82:32:82:34 | res | src/advanced-routehandler-registration.js:81:11:83:3 | functio ... s);\\n } | | src/advanced-routehandler-registration.js:82:32:82:34 | res | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:92:15:92:17 | res | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:92:15:92:17 | res | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:92:45:92:47 | res | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:100:25:100:27 | res | src/advanced-routehandler-registration.js:100:11:102:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:100:25:100:27 | res | src/advanced-routehandler-registration.js:100:11:102:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:100:25:100:27 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:100:25:100:27 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:101:36:101:38 | res | src/advanced-routehandler-registration.js:100:11:102:3 | functio ... s);\\n } | | src/advanced-routehandler-registration.js:101:36:101:38 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:111:15:111:17 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:111:15:111:17 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:111:45:111:47 | res | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:123:26:123:28 | res | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:124:26:124:28 | res | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | @@ -1106,32 +1121,40 @@ test_ResponseExpr | src/advanced-routehandler-registration.js:157:33:157:35 | res | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | | src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | | src/csurf-example.js:20:33:20:35 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | +| src/csurf-example.js:20:33:20:35 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:22:3:22:5 | res | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:25:37:25:39 | res | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | +| src/csurf-example.js:25:37:25:39 | res | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | | src/csurf-example.js:26:3:26:5 | res | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | | src/csurf-example.js:26:3:26:43 | res.sen ... here') | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | | src/csurf-example.js:32:45:32:47 | res | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | +| src/csurf-example.js:32:45:32:47 | res | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | | src/csurf-example.js:33:5:33:7 | res | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | | src/csurf-example.js:33:5:33:35 | res.sen ... here') | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | | src/csurf-example.js:39:41:39:43 | res | src/csurf-example.js:39:26:39:47 | functio ... res) {} | | src/csurf-example.js:40:42:40:44 | res | src/csurf-example.js:40:27:40:48 | functio ... res) {} | | src/exportedHandler.js:1:49:1:51 | res | src/exportedHandler.js:1:19:1:55 | functio ... res) {} | | src/express2.js:3:39:3:41 | res | src/express2.js:3:25:3:55 | functio ... , res } | +| src/express2.js:3:39:3:41 | res | src/express2.js:3:25:3:55 | functio ... , res } | | src/express2.js:3:46:3:53 | req, res | src/express2.js:3:25:3:55 | functio ... , res } | | src/express2.js:3:51:3:53 | res | src/express2.js:3:25:3:55 | functio ... , res } | | src/express2.js:4:50:4:55 | result | src/express2.js:4:32:4:76 | functio ... esult } | +| src/express2.js:4:50:4:55 | result | src/express2.js:4:32:4:76 | functio ... esult } | | src/express2.js:4:60:4:74 | request, result | src/express2.js:4:32:4:76 | functio ... esult } | | src/express2.js:4:69:4:74 | result | src/express2.js:4:32:4:76 | functio ... esult } | | src/express3.js:4:37:4:39 | res | src/express3.js:4:23:7:1 | functio ... al");\\n} | +| src/express3.js:4:37:4:39 | res | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:5:3:5:5 | res | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:5:3:5:51 | res.hea ... "val")) | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:6:3:6:5 | res | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:6:3:6:17 | res.send("val") | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:10:27:10:29 | res | src/express3.js:10:12:10:32 | functio ... res){} | | src/express4.js:4:37:4:39 | res | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | +| src/express4.js:4:37:4:39 | res | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:8:3:8:5 | res | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:8:3:8:20 | res.send(dynamic1) | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:4:37:4:39 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | +| src/express.js:4:37:4:39 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:5:3:5:5 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:6:3:6:5 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:6:3:6:45 | res.hea ... rget")) | src/express.js:4:23:9:1 | functio ... res);\\n} | @@ -1139,18 +1162,22 @@ test_ResponseExpr | src/express.js:7:3:7:42 | res.hea ... plain") | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:8:7:8:9 | res | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:11:14:11:16 | arg | src/express.js:4:23:9:1 | functio ... res);\\n} | +| src/express.js:11:14:11:16 | arg | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:12:3:12:5 | arg | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:12:3:12:54 | arg.hea ... , true) | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:16:33:16:35 | res | src/express.js:16:19:18:3 | functio ... ");\\n } | +| src/express.js:16:33:16:35 | res | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:17:5:17:7 | res | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:17:5:17:24 | res.send("Go away.") | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:22:44:22:46 | res | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:22:44:22:46 | res | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:31:3:31:5 | res | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:31:3:31:26 | res.coo ... 'bar') | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:37:27:37:29 | res | src/express.js:37:12:37:32 | functio ... res){} | | src/express.js:42:18:42:20 | res | src/express.js:42:12:42:28 | (req, res) => f() | | src/express.js:46:36:46:38 | res | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:4:29:4:31 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/inheritedFromNode.js:4:29:4:31 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:5:2:5:4 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:6:2:6:4 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/middleware-flow.js:5:25:5:27 | res | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | @@ -1159,20 +1186,27 @@ test_ResponseExpr | src/middleware-flow.js:24:23:24:25 | res | src/middleware-flow.js:24:17:24:41 | (req, r ... q.db; } | | src/middleware-flow.js:39:29:39:31 | res | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | | src/params.js:4:24:4:26 | res | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:4:24:4:26 | res | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:8:9:8:11 | res | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:8:9:8:23 | res.send(value) | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:14:38:14:40 | res | src/params.js:14:24:16:1 | functio ... lo");\\n} | +| src/params.js:14:38:14:40 | res | src/params.js:14:24:16:1 | functio ... lo");\\n} | | src/params.js:15:3:15:5 | res | src/params.js:14:24:16:1 | functio ... lo");\\n} | | src/params.js:15:3:15:19 | res.send("Hello") | src/params.js:14:24:16:1 | functio ... lo");\\n} | | src/responseExprs.js:4:37:4:40 | res1 | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | +| src/responseExprs.js:4:37:4:40 | res1 | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:5:5:5:8 | res1 | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:37:7:40 | res2 | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | +| src/responseExprs.js:7:37:7:40 | res2 | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:8:5:8:8 | res2 | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:44:10:47 | res3 | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | +| src/responseExprs.js:10:44:10:47 | res3 | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | | src/responseExprs.js:11:5:11:8 | res3 | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | | src/responseExprs.js:13:37:13:40 | res4 | src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | +| src/responseExprs.js:13:37:13:40 | res4 | src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | | src/responseExprs.js:14:5:14:8 | res4 | src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | | src/responseExprs.js:16:44:16:46 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:16:44:16:46 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:19:5:19:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:19:5:19:16 | res.append() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:20:5:20:7 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | @@ -1210,6 +1244,8 @@ test_ResponseExpr | src/responseExprs.js:37:5:37:28 | f(res.a ... ppend() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:37:7:37:9 | res | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:37:7:37:18 | res.append() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:39:5:41:5 | return of function f | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:39:16:39:21 | resArg | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:39:16:39:21 | resArg | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:40:16:40:21 | resArg | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:40:16:40:30 | resArg.append() | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | @@ -1611,37 +1647,52 @@ test_RouteHandler_getAResponseExpr | src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:24:12:24:14 | res | | src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:25:12:25:14 | res | | src/advanced-routehandler-registration.js:46:11:48:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:46:25:46:27 | res | +| src/advanced-routehandler-registration.js:46:11:48:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:46:25:46:27 | res | | src/advanced-routehandler-registration.js:46:11:48:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:47:32:47:34 | res | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:46:25:46:27 | res | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:46:25:46:27 | res | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:47:32:47:34 | res | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:15:51:17 | res | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:15:51:17 | res | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:45:51:47 | res | | src/advanced-routehandler-registration.js:59:11:61:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:59:25:59:27 | res | +| src/advanced-routehandler-registration.js:59:11:61:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:59:25:59:27 | res | | src/advanced-routehandler-registration.js:59:11:61:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:60:23:60:25 | res | | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:59:25:59:27 | res | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:59:25:59:27 | res | | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:60:23:60:25 | res | | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:15:64:17 | res | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:15:64:17 | res | | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:50:64:52 | res | | src/advanced-routehandler-registration.js:68:12:68:41 | (req, r ... og(req) | src/advanced-routehandler-registration.js:68:18:68:20 | res | | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:68:18:68:20 | res | | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:69:25:69:27 | res | +| src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:69:25:69:27 | res | | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:70:23:70:25 | res | | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:68:18:68:20 | res | | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:69:25:69:27 | res | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:69:25:69:27 | res | | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:70:23:70:25 | res | | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:15:73:17 | res | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:15:73:17 | res | | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:52:73:54 | res | | src/advanced-routehandler-registration.js:81:11:83:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:81:25:81:27 | res | +| src/advanced-routehandler-registration.js:81:11:83:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:81:25:81:27 | res | | src/advanced-routehandler-registration.js:81:11:83:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:82:32:82:34 | res | | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:81:25:81:27 | res | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:81:25:81:27 | res | | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:82:32:82:34 | res | | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:15:92:17 | res | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:15:92:17 | res | | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:45:92:47 | res | | src/advanced-routehandler-registration.js:100:11:102:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:100:25:100:27 | res | +| src/advanced-routehandler-registration.js:100:11:102:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:100:25:100:27 | res | | src/advanced-routehandler-registration.js:100:11:102:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:101:36:101:38 | res | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:100:25:100:27 | res | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:100:25:100:27 | res | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:101:36:101:38 | res | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:15:111:17 | res | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:15:111:17 | res | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:45:111:47 | res | | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:26:123:28 | res | | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:26:124:28 | res | @@ -1650,32 +1701,40 @@ test_RouteHandler_getAResponseExpr | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | src/advanced-routehandler-registration.js:157:33:157:35 | res | | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:33:20:35 | res | +| src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:22:3:22:5 | res | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:37:25:39 | res | +| src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:37:25:39 | res | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:26:3:26:5 | res | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:26:3:26:43 | res.sen ... here') | | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | src/csurf-example.js:32:45:32:47 | res | +| src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | src/csurf-example.js:32:45:32:47 | res | | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | src/csurf-example.js:33:5:33:7 | res | | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | src/csurf-example.js:33:5:33:35 | res.sen ... here') | | src/csurf-example.js:39:26:39:47 | functio ... res) {} | src/csurf-example.js:39:41:39:43 | res | | src/csurf-example.js:40:27:40:48 | functio ... res) {} | src/csurf-example.js:40:42:40:44 | res | | src/exportedHandler.js:1:19:1:55 | functio ... res) {} | src/exportedHandler.js:1:49:1:51 | res | | src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:3:39:3:41 | res | +| src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:3:39:3:41 | res | | src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:3:46:3:53 | req, res | | src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:3:51:3:53 | res | | src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:50:4:55 | result | +| src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:50:4:55 | result | | src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:60:4:74 | request, result | | src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:69:4:74 | result | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:37:4:39 | res | +| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:37:4:39 | res | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:3:5:5 | res | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:3:5:51 | res.hea ... "val")) | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:6:3:6:5 | res | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:6:3:6:17 | res.send("val") | | src/express3.js:10:12:10:32 | functio ... res){} | src/express3.js:10:27:10:29 | res | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:4:37:4:39 | res | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:4:37:4:39 | res | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:8:3:8:5 | res | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:8:3:8:20 | res.send(dynamic1) | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:37:4:39 | res | +| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:37:4:39 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:5:3:5:5 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:3:6:5 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:3:6:45 | res.hea ... rget")) | @@ -1683,18 +1742,22 @@ test_RouteHandler_getAResponseExpr | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:7:3:7:42 | res.hea ... plain") | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:8:7:8:9 | res | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:11:14:11:16 | arg | +| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:11:14:11:16 | arg | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:12:3:12:5 | arg | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:12:3:12:54 | arg.hea ... , true) | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:16:33:16:35 | res | +| src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:16:33:16:35 | res | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:17:5:17:7 | res | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:17:5:17:24 | res.send("Go away.") | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:44:22:46 | res | +| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:44:22:46 | res | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:31:3:31:5 | res | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:31:3:31:26 | res.coo ... 'bar') | | src/express.js:37:12:37:32 | functio ... res){} | src/express.js:37:27:37:29 | res | | src/express.js:42:12:42:28 | (req, res) => f() | src/express.js:42:18:42:20 | res | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:36:46:38 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:29:4:31 | res | +| src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:29:4:31 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:5:2:5:4 | res | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:6:2:6:4 | res | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:5:25:5:27 | res | @@ -1703,20 +1766,27 @@ test_RouteHandler_getAResponseExpr | src/middleware-flow.js:24:17:24:41 | (req, r ... q.db; } | src/middleware-flow.js:24:23:24:25 | res | | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:39:29:39:31 | res | | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:4:24:4:26 | res | +| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:4:24:4:26 | res | | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:8:9:8:11 | res | | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:8:9:8:23 | res.send(value) | | src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:14:38:14:40 | res | +| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:14:38:14:40 | res | | src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:15:3:15:5 | res | | src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:15:3:15:19 | res.send("Hello") | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:37:4:40 | res1 | +| src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:37:4:40 | res1 | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:5:5:5:8 | res1 | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:37:7:40 | res2 | +| src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:37:7:40 | res2 | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:8:5:8:8 | res2 | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:44:10:47 | res3 | +| src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:44:10:47 | res3 | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:11:5:11:8 | res3 | | src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | src/responseExprs.js:13:37:13:40 | res4 | +| src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | src/responseExprs.js:13:37:13:40 | res4 | | src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | src/responseExprs.js:14:5:14:8 | res4 | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:16:44:16:46 | res | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:16:44:16:46 | res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:19:5:19:7 | res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:19:5:19:16 | res.append() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:20:5:20:7 | res | @@ -1754,6 +1824,8 @@ test_RouteHandler_getAResponseExpr | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:37:5:37:28 | f(res.a ... ppend() | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:37:7:37:9 | res | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:37:7:37:18 | res.append() | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:39:5:41:5 | return of function f | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:39:16:39:21 | resArg | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:39:16:39:21 | resArg | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:40:16:40:21 | resArg | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:40:16:40:30 | resArg.append() | @@ -2547,64 +2619,93 @@ test_RouteHandlerExpr_getPreviousMiddleware | src/subrouter.js:5:14:5:28 | makeSubRouter() | src/subrouter.js:4:19:4:25 | protect | test_RequestExpr | src/advanced-routehandler-registration.js:6:7:6:9 | req | src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:6:7:6:9 | req | src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:6:32:6:34 | req | src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:7:7:7:9 | req | src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:7:7:7:9 | req | src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:7:32:7:34 | req | src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:15:7:15:9 | req | src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:15:7:15:9 | req | src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:15:32:15:34 | req | src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:16:7:16:9 | req | src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:16:7:16:9 | req | src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:16:32:16:34 | req | src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:24:7:24:9 | req | src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:24:7:24:9 | req | src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:24:32:24:34 | req | src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:25:7:25:9 | req | src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:25:7:25:9 | req | src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:25:32:25:34 | req | src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:46:20:46:22 | req | src/advanced-routehandler-registration.js:46:11:48:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:46:20:46:22 | req | src/advanced-routehandler-registration.js:46:11:48:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:46:20:46:22 | req | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:46:20:46:22 | req | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:47:27:47:29 | req | src/advanced-routehandler-registration.js:46:11:48:3 | functio ... s);\\n } | | src/advanced-routehandler-registration.js:47:27:47:29 | req | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:51:10:51:12 | req | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:51:10:51:12 | req | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:51:40:51:42 | req | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:59:20:59:22 | req | src/advanced-routehandler-registration.js:59:11:61:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:59:20:59:22 | req | src/advanced-routehandler-registration.js:59:11:61:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:59:20:59:22 | req | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:59:20:59:22 | req | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:60:18:60:20 | req | src/advanced-routehandler-registration.js:59:11:61:3 | functio ... s);\\n } | | src/advanced-routehandler-registration.js:60:18:60:20 | req | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:64:10:64:12 | req | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:64:10:64:12 | req | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:64:45:64:47 | req | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:68:13:68:15 | req | src/advanced-routehandler-registration.js:68:12:68:41 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:68:13:68:15 | req | src/advanced-routehandler-registration.js:68:12:68:41 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:68:13:68:15 | req | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:68:13:68:15 | req | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:68:13:68:15 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:68:13:68:15 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:68:38:68:40 | req | src/advanced-routehandler-registration.js:68:12:68:41 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:68:38:68:40 | req | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | | src/advanced-routehandler-registration.js:68:38:68:40 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:69:20:69:22 | req | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:69:20:69:22 | req | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:69:20:69:22 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:69:20:69:22 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:70:18:70:20 | req | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | | src/advanced-routehandler-registration.js:70:18:70:20 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:73:10:73:12 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | +| src/advanced-routehandler-registration.js:73:10:73:12 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:73:47:73:49 | req | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | | src/advanced-routehandler-registration.js:81:20:81:22 | req | src/advanced-routehandler-registration.js:81:11:83:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:81:20:81:22 | req | src/advanced-routehandler-registration.js:81:11:83:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:81:20:81:22 | req | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:81:20:81:22 | req | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:82:27:82:29 | req | src/advanced-routehandler-registration.js:81:11:83:3 | functio ... s);\\n } | | src/advanced-routehandler-registration.js:82:27:82:29 | req | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:92:10:92:12 | req | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:92:10:92:12 | req | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:92:40:92:42 | req | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:100:20:100:22 | req | src/advanced-routehandler-registration.js:100:11:102:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:100:20:100:22 | req | src/advanced-routehandler-registration.js:100:11:102:3 | functio ... s);\\n } | +| src/advanced-routehandler-registration.js:100:20:100:22 | req | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:100:20:100:22 | req | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:101:31:101:33 | req | src/advanced-routehandler-registration.js:100:11:102:3 | functio ... s);\\n } | | src/advanced-routehandler-registration.js:101:31:101:33 | req | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:111:10:111:12 | req | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | +| src/advanced-routehandler-registration.js:111:10:111:12 | req | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:111:40:111:42 | req | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | | src/advanced-routehandler-registration.js:123:21:123:23 | req | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:123:21:123:23 | req | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:123:46:123:48 | req | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:124:21:124:23 | req | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:124:21:124:23 | req | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:124:46:124:48 | req | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:146:29:146:31 | req | src/advanced-routehandler-registration.js:146:28:146:50 | (req, r ... defined | | src/advanced-routehandler-registration.js:156:22:156:24 | req | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:156:22:156:24 | req | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:156:47:156:49 | req | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:157:28:157:30 | req | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | +| src/advanced-routehandler-registration.js:157:28:157:30 | req | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | | src/advanced-routehandler-registration.js:157:53:157:55 | req | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | | src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | | src/csurf-example.js:20:28:20:30 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | +| src/csurf-example.js:20:28:20:30 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:22:35:22:37 | req | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | | src/csurf-example.js:25:32:25:34 | req | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | | src/csurf-example.js:32:40:32:42 | req | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | @@ -2612,22 +2713,28 @@ test_RequestExpr | src/csurf-example.js:40:37:40:39 | req | src/csurf-example.js:40:27:40:48 | functio ... res) {} | | src/exportedHandler.js:1:44:1:46 | req | src/exportedHandler.js:1:19:1:55 | functio ... res) {} | | src/express2.js:3:34:3:36 | req | src/express2.js:3:25:3:55 | functio ... , res } | +| src/express2.js:3:34:3:36 | req | src/express2.js:3:25:3:55 | functio ... , res } | | src/express2.js:3:46:3:48 | req | src/express2.js:3:25:3:55 | functio ... , res } | | src/express2.js:4:41:4:47 | request | src/express2.js:4:32:4:76 | functio ... esult } | +| src/express2.js:4:41:4:47 | request | src/express2.js:4:32:4:76 | functio ... esult } | | src/express2.js:4:60:4:66 | request | src/express2.js:4:32:4:76 | functio ... esult } | | src/express3.js:4:32:4:34 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} | +| src/express3.js:4:32:4:34 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:5:14:5:16 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:5:35:5:37 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} | | src/express3.js:10:22:10:24 | req | src/express3.js:10:12:10:32 | functio ... res){} | | src/express4.js:4:32:4:34 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | +| src/express4.js:4:32:4:34 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:5:27:5:29 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:6:18:6:20 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express4.js:7:18:7:20 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | | src/express.js:4:32:4:34 | req | src/express.js:4:23:9:1 | functio ... res);\\n} | +| src/express.js:4:32:4:34 | req | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:5:16:5:18 | req | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:6:26:6:28 | req | src/express.js:4:23:9:1 | functio ... res);\\n} | | src/express.js:16:28:16:30 | req | src/express.js:16:19:18:3 | functio ... ");\\n } | | src/express.js:22:39:22:41 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | +| src/express.js:22:39:22:41 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:23:3:23:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:24:3:24:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | | src/express.js:25:3:25:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} | @@ -2639,47 +2746,60 @@ test_RequestExpr | src/express.js:37:22:37:24 | req | src/express.js:37:12:37:32 | functio ... res){} | | src/express.js:42:13:42:15 | req | src/express.js:42:12:42:28 | (req, res) => f() | | src/express.js:46:31:46:33 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | +| src/express.js:46:31:46:33 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:47:3:47:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:48:3:48:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:49:3:49:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/express.js:50:3:50:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} | | src/inheritedFromNode.js:4:24:4:26 | req | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | +| src/inheritedFromNode.js:4:24:4:26 | req | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/inheritedFromNode.js:7:2:7:4 | req | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | | src/middleware-flow.js:5:20:5:22 | req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | +| src/middleware-flow.js:5:20:5:22 | req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:6:5:6:7 | req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:7:5:7:7 | req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:8:5:8:7 | req | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | | src/middleware-flow.js:17:25:17:27 | req | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | +| src/middleware-flow.js:17:25:17:27 | req | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:18:9:18:11 | req | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:19:9:19:11 | req | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:20:9:20:11 | req | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | | src/middleware-flow.js:23:18:23:20 | req | src/middleware-flow.js:23:17:23:41 | (req, r ... q.db; } | +| src/middleware-flow.js:23:18:23:20 | req | src/middleware-flow.js:23:17:23:41 | (req, r ... q.db; } | | src/middleware-flow.js:23:33:23:35 | req | src/middleware-flow.js:23:17:23:41 | (req, r ... q.db; } | | src/middleware-flow.js:24:18:24:20 | req | src/middleware-flow.js:24:17:24:41 | (req, r ... q.db; } | +| src/middleware-flow.js:24:18:24:20 | req | src/middleware-flow.js:24:17:24:41 | (req, r ... q.db; } | | src/middleware-flow.js:24:33:24:35 | req | src/middleware-flow.js:24:17:24:41 | (req, r ... q.db; } | | src/middleware-flow.js:39:24:39:26 | req | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | +| src/middleware-flow.js:39:24:39:26 | req | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | | src/middleware-flow.js:40:5:40:7 | req | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | | src/middleware-flow.js:41:5:41:7 | req | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | | src/middleware-flow.js:42:5:42:7 | req | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | | src/params.js:4:19:4:21 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} | +| src/params.js:4:19:4:21 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:5:17:5:19 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:6:17:6:19 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} | | src/params.js:14:33:14:35 | req | src/params.js:14:24:16:1 | functio ... lo");\\n} | | src/passport.js:27:13:27:15 | req | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | +| src/passport.js:27:13:27:15 | req | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | | src/passport.js:28:2:28:4 | req | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | | src/responseExprs.js:4:32:4:34 | req | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | | src/responseExprs.js:7:32:7:34 | req | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | | src/responseExprs.js:10:39:10:41 | req | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | | src/responseExprs.js:13:32:13:34 | req | src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | | src/responseExprs.js:16:39:16:41 | req | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | +| src/responseExprs.js:16:39:16:41 | req | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/responseExprs.js:17:5:17:7 | req | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | | src/route-collection.js:2:7:2:9 | req | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | +| src/route-collection.js:2:7:2:9 | req | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | | src/route-collection.js:2:32:2:34 | req | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | | src/route-collection.js:3:7:3:9 | req | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | +| src/route-collection.js:3:7:3:9 | req | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | | src/route-collection.js:3:32:3:34 | req | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | | src/route.js:5:21:5:23 | req | src/route.js:5:12:5:38 | functio ... ext) {} | test_RequestExprStandalone | typed_src/tst.ts:5:15:5:15 | x | +| typed_src/tst.ts:5:15:5:15 | x | | typed_src/tst.ts:6:3:6:3 | x | test_RouteHandlerExpr_getAsSubRouter | src/csurf-example.js:13:17:13:19 | api | src/csurf-example.js:30:16:30:35 | new express.Router() | @@ -2690,64 +2810,93 @@ test_Credentials | src/auth.js:4:39:4:48 | 'passw0rd' | password | test_RouteHandler_getARequestExpr | src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:6:7:6:9 | req | +| src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:6:7:6:9 | req | | src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:6:32:6:34 | req | | src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:7:7:7:9 | req | +| src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:7:7:7:9 | req | | src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:7:32:7:34 | req | | src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:15:7:15:9 | req | +| src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:15:7:15:9 | req | | src/advanced-routehandler-registration.js:15:6:15:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:15:32:15:34 | req | | src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:16:7:16:9 | req | +| src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:16:7:16:9 | req | | src/advanced-routehandler-registration.js:16:6:16:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:16:32:16:34 | req | | src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:24:7:24:9 | req | +| src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:24:7:24:9 | req | | src/advanced-routehandler-registration.js:24:6:24:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:24:32:24:34 | req | | src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:25:7:25:9 | req | +| src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:25:7:25:9 | req | | src/advanced-routehandler-registration.js:25:6:25:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:25:32:25:34 | req | | src/advanced-routehandler-registration.js:46:11:48:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:46:20:46:22 | req | +| src/advanced-routehandler-registration.js:46:11:48:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:46:20:46:22 | req | | src/advanced-routehandler-registration.js:46:11:48:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:47:27:47:29 | req | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:46:20:46:22 | req | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:46:20:46:22 | req | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:47:27:47:29 | req | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:10:51:12 | req | +| src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:10:51:12 | req | | src/advanced-routehandler-registration.js:51:9:51:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:51:40:51:42 | req | | src/advanced-routehandler-registration.js:59:11:61:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:59:20:59:22 | req | +| src/advanced-routehandler-registration.js:59:11:61:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:59:20:59:22 | req | | src/advanced-routehandler-registration.js:59:11:61:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:60:18:60:20 | req | | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:59:20:59:22 | req | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:59:20:59:22 | req | | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:60:18:60:20 | req | | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:10:64:12 | req | +| src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:10:64:12 | req | | src/advanced-routehandler-registration.js:64:9:64:53 | (req, r ... q, res) | src/advanced-routehandler-registration.js:64:45:64:47 | req | | src/advanced-routehandler-registration.js:68:12:68:41 | (req, r ... og(req) | src/advanced-routehandler-registration.js:68:13:68:15 | req | +| src/advanced-routehandler-registration.js:68:12:68:41 | (req, r ... og(req) | src/advanced-routehandler-registration.js:68:13:68:15 | req | | src/advanced-routehandler-registration.js:68:12:68:41 | (req, r ... og(req) | src/advanced-routehandler-registration.js:68:38:68:40 | req | | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:68:13:68:15 | req | +| src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:68:13:68:15 | req | | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:68:38:68:40 | req | | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:69:20:69:22 | req | +| src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:69:20:69:22 | req | | src/advanced-routehandler-registration.js:69:11:71:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:70:18:70:20 | req | | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:68:13:68:15 | req | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:68:13:68:15 | req | | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:68:38:68:40 | req | | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:69:20:69:22 | req | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:69:20:69:22 | req | | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:70:18:70:20 | req | | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:10:73:12 | req | +| src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:10:73:12 | req | | src/advanced-routehandler-registration.js:73:9:73:55 | (req, r ... q, res) | src/advanced-routehandler-registration.js:73:47:73:49 | req | | src/advanced-routehandler-registration.js:81:11:83:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:81:20:81:22 | req | +| src/advanced-routehandler-registration.js:81:11:83:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:81:20:81:22 | req | | src/advanced-routehandler-registration.js:81:11:83:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:82:27:82:29 | req | | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:81:20:81:22 | req | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:81:20:81:22 | req | | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:82:27:82:29 | req | | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:10:92:12 | req | +| src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:10:92:12 | req | | src/advanced-routehandler-registration.js:92:9:92:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:92:40:92:42 | req | | src/advanced-routehandler-registration.js:100:11:102:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:100:20:100:22 | req | +| src/advanced-routehandler-registration.js:100:11:102:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:100:20:100:22 | req | | src/advanced-routehandler-registration.js:100:11:102:3 | functio ... s);\\n } | src/advanced-routehandler-registration.js:101:31:101:33 | req | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:100:20:100:22 | req | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:100:20:100:22 | req | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:101:31:101:33 | req | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:10:111:12 | req | +| src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:10:111:12 | req | | src/advanced-routehandler-registration.js:111:9:111:60 | (req, r ... tever") | src/advanced-routehandler-registration.js:111:40:111:42 | req | | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:21:123:23 | req | +| src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:21:123:23 | req | | src/advanced-routehandler-registration.js:123:20:123:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:123:46:123:48 | req | | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:21:124:23 | req | +| src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:21:124:23 | req | | src/advanced-routehandler-registration.js:124:20:124:49 | (req, r ... og(req) | src/advanced-routehandler-registration.js:124:46:124:48 | req | | src/advanced-routehandler-registration.js:146:28:146:50 | (req, r ... defined | src/advanced-routehandler-registration.js:146:29:146:31 | req | | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:156:22:156:24 | req | +| src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:156:22:156:24 | req | | src/advanced-routehandler-registration.js:156:21:156:50 | (req, r ... og(req) | src/advanced-routehandler-registration.js:156:47:156:49 | req | | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | src/advanced-routehandler-registration.js:157:28:157:30 | req | +| src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | src/advanced-routehandler-registration.js:157:28:157:30 | req | | src/advanced-routehandler-registration.js:157:27:157:56 | (req, r ... og(req) | src/advanced-routehandler-registration.js:157:53:157:55 | req | | src/controllers/handler-in-bulk-require.js:1:44:1:66 | (req, r ... defined | src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:28:20:30 | req | +| src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:20:28:20:30 | req | | src/csurf-example.js:20:18:23:1 | functio ... () })\\n} | src/csurf-example.js:22:35:22:37 | req | | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} | src/csurf-example.js:25:32:25:34 | req | | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } | src/csurf-example.js:32:40:32:42 | req | @@ -2755,22 +2904,28 @@ test_RouteHandler_getARequestExpr | src/csurf-example.js:40:27:40:48 | functio ... res) {} | src/csurf-example.js:40:37:40:39 | req | | src/exportedHandler.js:1:19:1:55 | functio ... res) {} | src/exportedHandler.js:1:44:1:46 | req | | src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:3:34:3:36 | req | +| src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:3:34:3:36 | req | | src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:3:46:3:48 | req | | src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:41:4:47 | request | +| src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:41:4:47 | request | | src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:60:4:66 | request | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:32:4:34 | req | +| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:32:4:34 | req | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:14:5:16 | req | | src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:35:5:37 | req | | src/express3.js:10:12:10:32 | functio ... res){} | src/express3.js:10:22:10:24 | req | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:4:32:4:34 | req | +| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:4:32:4:34 | req | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:5:27:5:29 | req | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:6:18:6:20 | req | | src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:7:18:7:20 | req | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:32:4:34 | req | +| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:32:4:34 | req | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:5:16:5:18 | req | | src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:26:6:28 | req | | src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:16:28:16:30 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:39:22:41 | req | +| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:39:22:41 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:23:3:23:5 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:24:3:24:5 | req | | src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:25:3:25:5 | req | @@ -2782,43 +2937,55 @@ test_RouteHandler_getARequestExpr | src/express.js:37:12:37:32 | functio ... res){} | src/express.js:37:22:37:24 | req | | src/express.js:42:12:42:28 | (req, res) => f() | src/express.js:42:13:42:15 | req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:31:46:33 | req | +| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:31:46:33 | req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:47:3:47:5 | req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:48:3:48:5 | req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:49:3:49:5 | req | | src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:50:3:50:5 | req | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:24:4:26 | req | +| src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:24:4:26 | req | | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:7:2:7:4 | req | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:5:20:5:22 | req | +| src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:5:20:5:22 | req | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:6:5:6:7 | req | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:7:5:7:7 | req | | src/middleware-flow.js:5:1:10:1 | functio ... xt();\\n} | src/middleware-flow.js:8:5:8:7 | req | | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:17:25:17:27 | req | +| src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:17:25:17:27 | req | | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:18:9:18:11 | req | | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:19:9:19:11 | req | | src/middleware-flow.js:17:24:21:5 | (req, r ... ;\\n } | src/middleware-flow.js:20:9:20:11 | req | | src/middleware-flow.js:23:17:23:41 | (req, r ... q.db; } | src/middleware-flow.js:23:18:23:20 | req | +| src/middleware-flow.js:23:17:23:41 | (req, r ... q.db; } | src/middleware-flow.js:23:18:23:20 | req | | src/middleware-flow.js:23:17:23:41 | (req, r ... q.db; } | src/middleware-flow.js:23:33:23:35 | req | | src/middleware-flow.js:24:17:24:41 | (req, r ... q.db; } | src/middleware-flow.js:24:18:24:20 | req | +| src/middleware-flow.js:24:17:24:41 | (req, r ... q.db; } | src/middleware-flow.js:24:18:24:20 | req | | src/middleware-flow.js:24:17:24:41 | (req, r ... q.db; } | src/middleware-flow.js:24:33:24:35 | req | | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:39:24:39:26 | req | +| src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:39:24:39:26 | req | | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:40:5:40:7 | req | | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:41:5:41:7 | req | | src/middleware-flow.js:39:23:43:1 | (req, r ... s.db;\\n} | src/middleware-flow.js:42:5:42:7 | req | | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:4:19:4:21 | req | +| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:4:19:4:21 | req | | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:5:17:5:19 | req | | src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:6:17:6:19 | req | | src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:14:33:14:35 | req | | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | src/passport.js:27:13:27:15 | req | +| src/passport.js:27:4:29:1 | functio ... ccss`\\n} | src/passport.js:27:13:27:15 | req | | src/passport.js:27:4:29:1 | functio ... ccss`\\n} | src/passport.js:28:2:28:4 | req | | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:32:4:34 | req | | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:32:7:34 | req | | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:39:10:41 | req | | src/responseExprs.js:13:23:15:1 | functio ... res4;\\n} | src/responseExprs.js:13:32:13:34 | req | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:16:39:16:41 | req | +| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:16:39:16:41 | req | | src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:17:5:17:7 | req | | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | src/route-collection.js:2:7:2:9 | req | +| src/route-collection.js:2:6:2:35 | (req, r ... og(req) | src/route-collection.js:2:7:2:9 | req | | src/route-collection.js:2:6:2:35 | (req, r ... og(req) | src/route-collection.js:2:32:2:34 | req | | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | src/route-collection.js:3:7:3:9 | req | +| src/route-collection.js:3:6:3:35 | (req, r ... og(req) | src/route-collection.js:3:7:3:9 | req | | src/route-collection.js:3:6:3:35 | (req, r ... og(req) | src/route-collection.js:3:32:3:34 | req | | src/route.js:5:12:5:38 | functio ... ext) {} | src/route.js:5:21:5:23 | req | getRouteHandlerContainerStep diff --git a/javascript/ql/test/library-tests/frameworks/connect/tests.expected b/javascript/ql/test/library-tests/frameworks/connect/tests.expected index 65e9bf665e34..f383805827ab 100644 --- a/javascript/ql/test/library-tests/frameworks/connect/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/connect/tests.expected @@ -9,6 +9,7 @@ test_RouteSetup | src/test.js:32:1:35:2 | app.use ... rl);\\n}) | test_RequestInputAccess | src/test.js:8:5:8:26 | req.coo ... ('foo') | cookie | src/test.js:6:9:9:1 | functio ... oo');\\n} | +| src/test.js:28:20:28:22 | url | url | src/test.js:28:9:30:1 | functio ... bar);\\n} | | src/test.js:33:15:33:21 | req.url | url | src/test.js:32:9:35:1 | functio ... url);\\n} | test_RouteHandler_getAResponseHeader | src/test.js:6:9:9:1 | functio ... oo');\\n} | header1 | src/test.js:7:5:7:32 | res.set ... 1', '') | @@ -18,14 +19,17 @@ test_HeaderDefinition_defines | src/test.js:25:5:25:32 | res.set ... 2', '') | header2 | | test_ResponseExpr | src/test.js:6:32:6:34 | res | src/test.js:6:9:9:1 | functio ... oo');\\n} | +| src/test.js:6:32:6:34 | res | src/test.js:6:9:9:1 | functio ... oo');\\n} | | src/test.js:7:5:7:7 | res | src/test.js:6:9:9:1 | functio ... oo');\\n} | | src/test.js:15:27:15:29 | res | src/test.js:15:12:15:32 | functio ... res){} | | src/test.js:19:22:19:24 | res | src/test.js:19:9:19:27 | function(req,res){} | | src/test.js:20:23:20:25 | res | src/test.js:20:10:20:28 | function(req,res){} | | src/test.js:24:31:24:33 | res | src/test.js:24:9:26:1 | functio ... '');\\n} | +| src/test.js:24:31:24:33 | res | src/test.js:24:9:26:1 | functio ... '');\\n} | | src/test.js:25:5:25:7 | res | src/test.js:24:9:26:1 | functio ... '');\\n} | | src/test.js:28:42:28:44 | res | src/test.js:28:9:30:1 | functio ... bar);\\n} | | src/test.js:32:24:32:26 | res | src/test.js:32:9:35:1 | functio ... url);\\n} | +| src/test.js:32:24:32:26 | res | src/test.js:32:9:35:1 | functio ... url);\\n} | | src/test.js:34:5:34:7 | res | src/test.js:32:9:35:1 | functio ... url);\\n} | test_HeaderDefinition | src/test.js:7:5:7:32 | res.set ... 1', '') | src/test.js:6:9:9:1 | functio ... oo');\\n} | @@ -46,14 +50,17 @@ test_ServerDefinition | src/test.js:4:11:4:19 | connect() | test_RouteHandler_getAResponseExpr | src/test.js:6:9:9:1 | functio ... oo');\\n} | src/test.js:6:32:6:34 | res | +| src/test.js:6:9:9:1 | functio ... oo');\\n} | src/test.js:6:32:6:34 | res | | src/test.js:6:9:9:1 | functio ... oo');\\n} | src/test.js:7:5:7:7 | res | | src/test.js:15:12:15:32 | functio ... res){} | src/test.js:15:27:15:29 | res | | src/test.js:19:9:19:27 | function(req,res){} | src/test.js:19:22:19:24 | res | | src/test.js:20:10:20:28 | function(req,res){} | src/test.js:20:23:20:25 | res | | src/test.js:24:9:26:1 | functio ... '');\\n} | src/test.js:24:31:24:33 | res | +| src/test.js:24:9:26:1 | functio ... '');\\n} | src/test.js:24:31:24:33 | res | | src/test.js:24:9:26:1 | functio ... '');\\n} | src/test.js:25:5:25:7 | res | | src/test.js:28:9:30:1 | functio ... bar);\\n} | src/test.js:28:42:28:44 | res | | src/test.js:32:9:35:1 | functio ... url);\\n} | src/test.js:32:24:32:26 | res | +| src/test.js:32:9:35:1 | functio ... url);\\n} | src/test.js:32:24:32:26 | res | | src/test.js:32:9:35:1 | functio ... url);\\n} | src/test.js:34:5:34:7 | res | test_RouteSetup_getARouteHandler | src/test.js:6:1:9:2 | app.use ... o');\\n}) | src/test.js:6:9:9:1 | functio ... oo');\\n} | @@ -76,6 +83,7 @@ test_RouteHandler | src/test.js:32:9:35:1 | functio ... url);\\n} | src/test.js:4:11:4:19 | connect() | test_RequestExpr | src/test.js:6:27:6:29 | req | src/test.js:6:9:9:1 | functio ... oo');\\n} | +| src/test.js:6:27:6:29 | req | src/test.js:6:9:9:1 | functio ... oo');\\n} | | src/test.js:8:5:8:7 | req | src/test.js:6:9:9:1 | functio ... oo');\\n} | | src/test.js:15:22:15:24 | req | src/test.js:15:12:15:32 | functio ... res){} | | src/test.js:19:18:19:20 | req | src/test.js:19:9:19:27 | function(req,res){} | @@ -83,12 +91,14 @@ test_RequestExpr | src/test.js:24:26:24:28 | req | src/test.js:24:9:26:1 | functio ... '');\\n} | | src/test.js:28:19:28:39 | {url, q ... ookies} | src/test.js:28:9:30:1 | functio ... bar);\\n} | | src/test.js:32:19:32:21 | req | src/test.js:32:9:35:1 | functio ... url);\\n} | +| src/test.js:32:19:32:21 | req | src/test.js:32:9:35:1 | functio ... url);\\n} | | src/test.js:33:15:33:17 | req | src/test.js:32:9:35:1 | functio ... url);\\n} | test_Credentials | src/test.js:12:19:12:28 | 'username' | user name | | src/test.js:12:31:12:40 | 'password' | password | test_RouteHandler_getARequestExpr | src/test.js:6:9:9:1 | functio ... oo');\\n} | src/test.js:6:27:6:29 | req | +| src/test.js:6:9:9:1 | functio ... oo');\\n} | src/test.js:6:27:6:29 | req | | src/test.js:6:9:9:1 | functio ... oo');\\n} | src/test.js:8:5:8:7 | req | | src/test.js:15:12:15:32 | functio ... res){} | src/test.js:15:22:15:24 | req | | src/test.js:19:9:19:27 | function(req,res){} | src/test.js:19:18:19:20 | req | @@ -96,4 +106,5 @@ test_RouteHandler_getARequestExpr | src/test.js:24:9:26:1 | functio ... '');\\n} | src/test.js:24:26:24:28 | req | | src/test.js:28:9:30:1 | functio ... bar);\\n} | src/test.js:28:19:28:39 | {url, q ... ookies} | | src/test.js:32:9:35:1 | functio ... url);\\n} | src/test.js:32:19:32:21 | req | +| src/test.js:32:9:35:1 | functio ... url);\\n} | src/test.js:32:19:32:21 | req | | src/test.js:32:9:35:1 | functio ... url);\\n} | src/test.js:33:15:33:17 | req | diff --git a/javascript/ql/test/library-tests/frameworks/fastify/tests.expected b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected index 1371bf551c84..36a5420a1789 100644 --- a/javascript/ql/test/library-tests/frameworks/fastify/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/fastify/tests.expected @@ -97,23 +97,28 @@ test_RouteHandler_getARequestExpr | src/fastify.js:20:26:20:47 | (reques ... ) => {} | src/fastify.js:20:27:20:33 | request | | src/fastify.js:26:17:28:3 | (reques ... nse\\n } | src/fastify.js:26:18:26:24 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:34:26:34:32 | request | +| src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:34:26:34:32 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:36:5:36:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:37:5:37:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:38:5:38:11 | request | | src/fastify.js:34:17:46:3 | functio ... eam\\n } | src/fastify.js:39:5:39:11 | request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:54:26:54:32 | request | +| src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:54:26:54:32 | request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:55:5:55:11 | request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:56:5:56:11 | request | | src/fastify.js:54:17:58:3 | functio ... ms;\\n } | src/fastify.js:57:5:57:11 | request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:65:26:65:32 | request | +| src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:65:26:65:32 | request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:66:5:66:11 | request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:67:5:67:11 | request | | src/fastify.js:65:17:69:3 | functio ... ms;\\n } | src/fastify.js:68:5:68:11 | request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:76:26:76:32 | request | +| src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:76:26:76:32 | request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:77:5:77:11 | request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:78:5:78:11 | request | | src/fastify.js:76:17:80:3 | functio ... ms;\\n } | src/fastify.js:79:5:79:11 | request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:87:26:87:32 | request | +| src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:87:26:87:32 | request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:88:5:88:11 | request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:89:5:89:11 | request | | src/fastify.js:87:17:91:3 | functio ... ms;\\n } | src/fastify.js:90:5:90:11 | request | diff --git a/javascript/ql/test/library-tests/frameworks/hapi/tests.expected b/javascript/ql/test/library-tests/frameworks/hapi/tests.expected index 2579ed7a75aa..fb73a32acf62 100644 --- a/javascript/ql/test/library-tests/frameworks/hapi/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/hapi/tests.expected @@ -48,9 +48,11 @@ test_RouteHandler | src/hapi.js:34:12:34:30 | function (req, h){} | src/hapi.js:4:15:4:31 | new Hapi.Server() | test_RequestExpr | src/hapi.js:13:32:13:38 | request | src/hapi.js:13:14:15:5 | functio ... n\\n } | +| src/hapi.js:13:32:13:38 | request | src/hapi.js:13:14:15:5 | functio ... n\\n } | | src/hapi.js:14:9:14:15 | request | src/hapi.js:13:14:15:5 | functio ... n\\n } | | src/hapi.js:17:48:17:54 | request | src/hapi.js:17:30:18:1 | functio ... ndler\\n} | | src/hapi.js:20:19:20:25 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | +| src/hapi.js:20:19:20:25 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:21:3:21:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:22:3:22:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | | src/hapi.js:23:3:23:9 | request | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | @@ -60,9 +62,11 @@ test_RequestExpr | src/hapi.js:34:22:34:24 | req | src/hapi.js:34:12:34:30 | function (req, h){} | test_RouteHandler_getARequestExpr | src/hapi.js:13:14:15:5 | functio ... n\\n } | src/hapi.js:13:32:13:38 | request | +| src/hapi.js:13:14:15:5 | functio ... n\\n } | src/hapi.js:13:32:13:38 | request | | src/hapi.js:13:14:15:5 | functio ... n\\n } | src/hapi.js:14:9:14:15 | request | | src/hapi.js:17:30:18:1 | functio ... ndler\\n} | src/hapi.js:17:48:17:54 | request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:20:19:20:25 | request | +| src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:20:19:20:25 | request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:21:3:21:9 | request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:22:3:22:9 | request | | src/hapi.js:20:1:27:1 | functio ... oken;\\n} | src/hapi.js:23:3:23:9 | request | diff --git a/javascript/ql/test/library-tests/frameworks/koa/tests.expected b/javascript/ql/test/library-tests/frameworks/koa/tests.expected index e0a56e4e5328..9e983ccca926 100644 --- a/javascript/ql/test/library-tests/frameworks/koa/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/koa/tests.expected @@ -41,6 +41,7 @@ test_HeaderDefinition_defines test_ResponseExpr | src/koa.js:12:3:12:15 | this.response | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:14:3:14:14 | ctx.response | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:15:7:15:24 | rsp | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:15:13:15:24 | ctx.response | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:16:3:16:5 | rsp | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:18:3:18:14 | ctx.response | src/koa.js:10:10:28:1 | functio ... az');\\n} | @@ -111,6 +112,7 @@ test_HeaderAccess test_RouteHandler_getAResponseExpr | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:12:3:12:15 | this.response | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:14:3:14:14 | ctx.response | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:15:7:15:24 | rsp | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:15:13:15:24 | ctx.response | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:16:3:16:5 | rsp | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:18:3:18:14 | ctx.response | diff --git a/javascript/ql/test/library-tests/frameworks/restify/tests.expected b/javascript/ql/test/library-tests/frameworks/restify/tests.expected index 618b05e7cca4..3f26379a3fa0 100644 --- a/javascript/ql/test/library-tests/frameworks/restify/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/restify/tests.expected @@ -18,8 +18,10 @@ test_HeaderDefinition_defines | src/test.js:13:5:13:37 | respons ... 2', '') | header2 | | test_ResponseExpr | src/test.js:9:46:9:53 | response | src/test.js:9:19:11:1 | functio ... ition\\n} | +| src/test.js:9:46:9:53 | response | src/test.js:9:19:11:1 | functio ... ition\\n} | | src/test.js:10:5:10:12 | response | src/test.js:9:19:11:1 | functio ... ition\\n} | | src/test.js:12:46:12:53 | response | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:12:46:12:53 | response | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:13:5:13:12 | response | src/test.js:12:19:22:1 | functio ... okie;\\n} | test_HeaderDefinition | src/test.js:10:5:10:34 | respons ... 1', '') | src/test.js:9:19:11:1 | functio ... ition\\n} | @@ -36,8 +38,10 @@ test_ServerDefinition | src/test.js:4:15:4:36 | restify ... erver() | test_RouteHandler_getAResponseExpr | src/test.js:9:19:11:1 | functio ... ition\\n} | src/test.js:9:46:9:53 | response | +| src/test.js:9:19:11:1 | functio ... ition\\n} | src/test.js:9:46:9:53 | response | | src/test.js:9:19:11:1 | functio ... ition\\n} | src/test.js:10:5:10:12 | response | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:12:46:12:53 | response | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:12:46:12:53 | response | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:13:5:13:12 | response | test_RouteSetup_getARouteHandler | src/test.js:7:1:7:26 | server2 ... ndler1) | src/test.js:6:1:6:21 | functio ... er1(){} | @@ -50,6 +54,7 @@ test_RouteHandler test_RequestExpr | src/test.js:9:37:9:43 | request | src/test.js:9:19:11:1 | functio ... ition\\n} | | src/test.js:12:37:12:43 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | +| src/test.js:12:37:12:43 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:14:5:14:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:15:5:15:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | | src/test.js:16:5:16:11 | request | src/test.js:12:19:22:1 | functio ... okie;\\n} | @@ -61,6 +66,7 @@ test_RequestExpr test_RouteHandler_getARequestExpr | src/test.js:9:19:11:1 | functio ... ition\\n} | src/test.js:9:37:9:43 | request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:12:37:12:43 | request | +| src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:12:37:12:43 | request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:14:5:14:11 | request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:15:5:15:11 | request | | src/test.js:12:19:22:1 | functio ... okie;\\n} | src/test.js:16:5:16:11 | request | From dfb7782be01be4f07661f9e5ec0a7589153f1df9 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 16:52:09 +0200 Subject: [PATCH 11/39] replace `getA?RouteHandlerExpr` with `getA?RouteHandlerNode` --- .../semmle/javascript/frameworks/Connect.qll | 14 ++++- .../semmle/javascript/frameworks/Express.qll | 56 ++++++++++++++----- .../semmle/javascript/frameworks/Fastify.qll | 12 +++- .../lib/semmle/javascript/frameworks/Hapi.qll | 2 +- .../javascript/frameworks/NodeJSLib.qll | 8 ++- .../RouteSetup_getARouteHandlerExpr.qll | 4 +- .../RouteSetup_getLastRouteHandlerExpr.qll | 4 +- .../RouteSetup_getRouteHandlerExpr.qll | 4 +- 8 files changed, 77 insertions(+), 27 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll b/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll index 20efe1b97688..04e2bd43f377 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll @@ -79,15 +79,23 @@ module Connect { private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { t.start() and - result = getARouteHandlerExpr().flow().getALocalSource() + result = getARouteHandlerNode().getALocalSource() or exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t)) } override DataFlow::Node getServer() { result = server } - /** Gets an argument that represents a route handler being registered. */ - Expr getARouteHandlerExpr() { result = getAnArgument().asExpr() } // TODO: DataFlow::Node + /** + * DEPRECATED: Use `getARouteHandlerNode` instead. + * Gets an argument that represents a route handler being registered. + */ + deprecated Expr getARouteHandlerExpr() { result = getARouteHandlerNode().asExpr() } + + /** + * Gets an argument that represents a route handler being registered. + */ + DataFlow::Node getARouteHandlerNode() { result = getAnArgument() } } /** An expression that is passed as `basicAuthConnect(, )`. */ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 6041cab9f759..bf2e6b8a25a0 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -157,39 +157,65 @@ module Express { predicate isUseCall() { this.getMethodName() = "use" } /** + * DEPRECATED: Use `getRouteHandlerNode` instead. * Gets the `n`th handler registered by this setup, with 0 being the first. * * This differs from `getARouteHandler` in that the argument expression is * returned, not its dataflow source. */ - Expr getRouteHandlerExpr(int index) { - // TODO: DataFlow::Node + deprecated Expr getRouteHandlerExpr(int index) { result = getRouteHandlerNode(index).asExpr() } + + /** + * Gets the `n`th handler registered by this setup, with 0 being the first. + * + * This differs from `getARouteHandler` in that the argument expression is + * returned, not its dataflow source. + */ + DataFlow::Node getRouteHandlerNode(int index) { // The first argument is a URI pattern if it is a string. If it could possibly be // a function, we consider it to be a route handler, otherwise a URI pattern. exists(AnalyzedNode firstArg | firstArg = this.getArgument(0).analyze() | if firstArg.getAType() = TTFunction() - then result = this.getArgument(index).asExpr() + then result = this.getArgument(index) else ( - index >= 0 and result = this.getArgument(index + 1).asExpr() + index >= 0 and result = this.getArgument(index + 1) ) ) } - /** Gets an argument that represents a route handler being registered. */ - Expr getARouteHandlerExpr() { result = this.getRouteHandlerExpr(_) } + /** + * DEPRECATED: Use `getARouteHandlerNode` instead. + * Gets an argument that represents a route handler being registered. + */ + deprecated Expr getARouteHandlerExpr() { result = this.getRouteHandlerExpr(_) } - /** Gets the last argument representing a route handler being registered. */ - Expr getLastRouteHandlerExpr() { + /** + * Gets an argument that represents a route handler being registered. + */ + DataFlow::Node getARouteHandlerNode() { result = this.getRouteHandlerNode(_) } + + /** + * DEPRECATED: Use `getLastRouteHandlerExpr` instead. + * Gets the last argument representing a route handler being registered. + */ + deprecated Expr getLastRouteHandlerExpr() { result = max(int i | | this.getRouteHandlerExpr(i) order by i) } + /** + * Gets the last argument representing a route handler being registered. + */ + DataFlow::Node getLastRouteHandlerNode() { + result = max(int i | | this.getRouteHandlerNode(i) order by i) + } + override DataFlow::SourceNode getARouteHandler() { result = this.getARouteHandler(DataFlow::TypeBackTracker::end()) } private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { t.start() and - result = this.getARouteHandlerExpr().flow().getALocalSource() + result = this.getARouteHandlerNode().getALocalSource() or exists(DataFlow::TypeBackTracker t2, DataFlow::SourceNode succ | succ = this.getARouteHandler(t2) @@ -284,10 +310,11 @@ module Express { * a function that flows into such an argument. */ class RouteHandlerExpr extends Expr { + // TODO: DataFlow::Node RouteSetup setup; int index; - RouteHandlerExpr() { this = setup.getRouteHandlerExpr(index) } + RouteHandlerExpr() { this = setup.getRouteHandlerNode(index).asExpr() } /** * Gets the setup call that registers this route handler. @@ -310,7 +337,7 @@ module Express { */ predicate isLastHandler() { not setup.isUseCall() and - not exists(setup.getRouteHandlerExpr(index + 1)) + not exists(setup.getRouteHandlerNode(index + 1)) } /** @@ -339,7 +366,7 @@ module Express { index = 0 and result = setup.getRouter().getMiddlewareStackAt(setup.asExpr().getAPredecessor()) or - index > 0 and result = setup.getRouteHandlerExpr(index - 1) + index > 0 and result = setup.getRouteHandlerNode(index - 1).asExpr() or // Outside the router's original container, use the flow-insensitive model of its middleware stack. // Its state is not tracked to CFG nodes outside its original container. @@ -920,11 +947,14 @@ module Express { * If `node` is not in the same container where `router` was defined, the predicate has no result. */ Express::RouteHandlerExpr getMiddlewareStackAt(ControlFlowNode node) { + // TODO: DataFlow::Node? if exists(Express::RouteSetup setup | node = setup.asExpr() and setup.getRouter() = this | setup.isUseCall() ) - then result = node.(AST::ValueNode).flow().(Express::RouteSetup).getLastRouteHandlerExpr() + then + result = + node.(AST::ValueNode).flow().(Express::RouteSetup).getLastRouteHandlerNode().asExpr() else result = this.getMiddlewareStackAt(node.getAPredecessor()) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll index b80baeb7a90c..76d1c9825b32 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll @@ -147,15 +147,21 @@ module Fastify { private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { t.start() and - result = this.getARouteHandlerExpr().getALocalSource() + result = this.getARouteHandlerNode().getALocalSource() or exists(DataFlow::TypeBackTracker t2 | result = this.getARouteHandler(t2).backtrack(t2, t)) } override DataFlow::SourceNode getServer() { result = server } - /** Gets an argument that represents a route handler being registered. */ - DataFlow::Node getARouteHandlerExpr() { + /** + * DEPRECATED: Use `getARouteHandlerNode` instead. + * Gets an argument that represents a route handler being registered. + */ + deprecated DataFlow::Node getARouteHandlerExpr() { result = this.getARouteHandlerNode() } + + /** Gets an argument that represents a route handler being registered. */ + DataFlow::Node getARouteHandlerNode() { if methodName = "route" then result = this.getOptionArgument(0, getNthHandlerName(_)) else result = this.getLastArgument() diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll index a7f1fd0a56a7..860538735492 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll @@ -231,7 +231,7 @@ module Hapi { pragma[noinline] private DataFlow::Node getRouteHandler() { result = handler } - Expr getRouteHandlerExpr() { result = handler.asExpr() } // TODO: DataFlow::Node + deprecated Expr getRouteHandlerExpr() { result = handler.asExpr() } override DataFlow::Node getServer() { result = server } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll index 559b26df2e6b..59b2d6d9137e 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll @@ -290,9 +290,15 @@ module NodeJSLib { override DataFlow::Node getServer() { result = server } /** + * DEPRECATED: Use `getRouteHandlerNode` instead. * Gets the expression for the handler registered by this setup. */ - Expr getRouteHandlerExpr() { result = handler.asExpr() } // TODO: DataFlow::Node + deprecated Expr getRouteHandlerExpr() { result = handler.asExpr() } + + /** + * Gets the expression for the handler registered by this setup. + */ + DataFlow::Node getRouteHandlerNode() { result = handler } } abstract private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getARouteHandlerExpr.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getARouteHandlerExpr.qll index 605747a2581b..97673b157735 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getARouteHandlerExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getARouteHandlerExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_RouteSetup_getARouteHandlerExpr(Express::RouteSetup r, Expr res) { - res = r.getARouteHandlerExpr() +query predicate test_RouteSetup_getARouteHandlerExpr(Express::RouteSetup r, DataFlow::Node res) { + res = r.getARouteHandlerNode() } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getLastRouteHandlerExpr.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getLastRouteHandlerExpr.qll index fd21c22a11e1..0c3336c4a75b 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getLastRouteHandlerExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getLastRouteHandlerExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_RouteSetup_getLastRouteHandlerExpr(Express::RouteSetup r, Expr res) { - res = r.getLastRouteHandlerExpr() +query predicate test_RouteSetup_getLastRouteHandlerExpr(Express::RouteSetup r, DataFlow::Node res) { + res = r.getLastRouteHandlerNode() } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRouteHandlerExpr.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRouteHandlerExpr.qll index db5dccb8d005..680ef07b2ee9 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRouteHandlerExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteSetup_getRouteHandlerExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_RouteSetup_getRouteHandlerExpr(Express::RouteSetup r, int i, Expr res) { - res = r.getRouteHandlerExpr(i) +query predicate test_RouteSetup_getRouteHandlerExpr(Express::RouteSetup r, int i, DataFlow::Node res) { + res = r.getRouteHandlerNode(i) } From 92240384a9a1f64815ba84a0066e741a5a432321 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 16:53:02 +0200 Subject: [PATCH 12/39] update the tests to reflect the extra `DataFlow::Node`s --- .../frameworks/NodeJSLib/tests.expected | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected b/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected index 2677e7854877..7d2d6abfddbe 100644 --- a/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected @@ -45,43 +45,61 @@ test_ResponseExpr | createServer.js:3:38:3:40 | res | createServer.js:3:23:3:44 | functio ... res) {} | | createServer.js:4:37:4:39 | res | createServer.js:4:31:4:46 | (req, res) => {} | | createServer.js:25:52:25:54 | res | createServer.js:25:37:27:5 | functio ... ;\\n } | +| createServer.js:25:52:25:54 | res | createServer.js:25:37:27:5 | functio ... ;\\n } | | createServer.js:26:9:26:11 | res | createServer.js:25:37:27:5 | functio ... ;\\n } | | src/http.js:4:46:4:48 | res | src/http.js:4:32:10:1 | functio ... .foo;\\n} | +| src/http.js:4:46:4:48 | res | src/http.js:4:32:10:1 | functio ... .foo;\\n} | | src/http.js:7:3:7:5 | res | src/http.js:4:32:10:1 | functio ... .foo;\\n} | | src/http.js:12:33:12:35 | res | src/http.js:12:19:16:1 | functio ... ar");\\n} | +| src/http.js:12:33:12:35 | res | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:13:3:13:5 | res | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:14:3:14:5 | res | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:15:3:15:5 | res | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:55:25:55:27 | res | src/http.js:55:12:55:30 | function(req,res){} | | src/http.js:60:27:60:29 | res | src/http.js:60:14:60:32 | function(req,res){} | | src/http.js:62:33:62:35 | res | src/http.js:62:19:65:1 | functio ... r2");\\n} | +| src/http.js:62:33:62:35 | res | src/http.js:62:19:65:1 | functio ... r2");\\n} | | src/http.js:63:3:63:5 | res | src/http.js:62:19:65:1 | functio ... r2");\\n} | | src/http.js:64:3:64:5 | res | src/http.js:62:19:65:1 | functio ... r2");\\n} | | src/http.js:68:17:68:19 | res | src/http.js:68:12:68:27 | (req,res) => f() | | src/http.js:72:34:72:36 | res | src/http.js:72:19:76:1 | functio ... \\n })\\n} | +| src/http.js:72:34:72:36 | res | src/http.js:72:19:76:1 | functio ... \\n })\\n} | +| src/http.js:72:34:72:36 | res | src/http.js:72:19:76:1 | functio ... \\n })\\n} | +| src/http.js:73:18:73:17 | res | src/http.js:72:19:76:1 | functio ... \\n })\\n} | | src/http.js:74:5:74:7 | res | src/http.js:72:19:76:1 | functio ... \\n })\\n} | | src/http.js:81:46:81:48 | res | src/http.js:81:22:86:1 | functio ... la");\\n} | +| src/http.js:81:46:81:48 | res | src/http.js:81:22:86:1 | functio ... la");\\n} | +| src/http.js:81:46:81:48 | res | src/http.js:81:22:86:1 | functio ... la");\\n} | +| src/http.js:82:18:82:17 | res | src/http.js:81:22:86:1 | functio ... la");\\n} | | src/http.js:83:5:83:7 | res | src/http.js:81:22:86:1 | functio ... la");\\n} | | src/http.js:85:3:85:5 | res | src/http.js:81:22:86:1 | functio ... la");\\n} | | src/https.js:4:47:4:49 | res | src/https.js:4:33:10:1 | functio ... .foo;\\n} | +| src/https.js:4:47:4:49 | res | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:7:3:7:5 | res | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:12:34:12:36 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | +| src/https.js:12:34:12:36 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/https.js:13:3:13:5 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/https.js:14:3:14:5 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/https.js:15:3:15:5 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/indirect2.js:9:19:9:21 | res | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | +| src/indirect2.js:9:19:9:21 | res | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:10:47:10:49 | res | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:13:33:13:35 | res | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | +| src/indirect2.js:13:33:13:35 | res | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | +| src/indirect2.js:13:33:13:35 | res | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | | src/indirect2.js:13:33:13:35 | res | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | | src/indirect2.js:14:3:14:5 | res | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:14:3:14:5 | res | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | | src/indirect2.js:15:3:15:5 | res | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:15:3:15:5 | res | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | | src/indirect.js:16:26:16:28 | res | src/indirect.js:16:12:20:5 | functio ... ;\\n } | +| src/indirect.js:16:26:16:28 | res | src/indirect.js:16:12:20:5 | functio ... ;\\n } | | src/indirect.js:19:38:19:40 | res | src/indirect.js:16:12:20:5 | functio ... ;\\n } | | src/indirect.js:25:30:25:32 | res | src/indirect.js:25:24:27:3 | (req, r ... ");\\n } | +| src/indirect.js:25:30:25:32 | res | src/indirect.js:25:24:27:3 | (req, r ... ");\\n } | | src/indirect.js:26:5:26:7 | res | src/indirect.js:25:24:27:3 | (req, r ... ");\\n } | | src/indirect.js:28:29:28:31 | res | src/indirect.js:28:15:30:3 | functio ... ");\\n } | +| src/indirect.js:28:29:28:31 | res | src/indirect.js:28:15:30:3 | functio ... ");\\n } | | src/indirect.js:29:5:29:7 | res | src/indirect.js:28:15:30:3 | functio ... ");\\n } | test_HeaderDefinition | src/http.js:7:3:7:42 | res.wri ... rget }) | src/http.js:4:32:10:1 | functio ... .foo;\\n} | @@ -150,43 +168,61 @@ test_RouteHandler_getAResponseExpr | createServer.js:3:23:3:44 | functio ... res) {} | createServer.js:3:38:3:40 | res | | createServer.js:4:31:4:46 | (req, res) => {} | createServer.js:4:37:4:39 | res | | createServer.js:25:37:27:5 | functio ... ;\\n } | createServer.js:25:52:25:54 | res | +| createServer.js:25:37:27:5 | functio ... ;\\n } | createServer.js:25:52:25:54 | res | | createServer.js:25:37:27:5 | functio ... ;\\n } | createServer.js:26:9:26:11 | res | | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:4:46:4:48 | res | +| src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:4:46:4:48 | res | | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:7:3:7:5 | res | | src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:12:33:12:35 | res | +| src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:12:33:12:35 | res | | src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:13:3:13:5 | res | | src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:14:3:14:5 | res | | src/http.js:12:19:16:1 | functio ... ar");\\n} | src/http.js:15:3:15:5 | res | | src/http.js:55:12:55:30 | function(req,res){} | src/http.js:55:25:55:27 | res | | src/http.js:60:14:60:32 | function(req,res){} | src/http.js:60:27:60:29 | res | | src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:62:33:62:35 | res | +| src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:62:33:62:35 | res | | src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:63:3:63:5 | res | | src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:64:3:64:5 | res | | src/http.js:68:12:68:27 | (req,res) => f() | src/http.js:68:17:68:19 | res | | src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:72:34:72:36 | res | +| src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:72:34:72:36 | res | +| src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:72:34:72:36 | res | +| src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:73:18:73:17 | res | | src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:74:5:74:7 | res | | src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:81:46:81:48 | res | +| src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:81:46:81:48 | res | +| src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:81:46:81:48 | res | +| src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:82:18:82:17 | res | | src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:83:5:83:7 | res | | src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:85:3:85:5 | res | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:4:47:4:49 | res | +| src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:4:47:4:49 | res | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:7:3:7:5 | res | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:12:34:12:36 | res | +| src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:12:34:12:36 | res | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:13:3:13:5 | res | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:14:3:14:5 | res | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:15:3:15:5 | res | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:9:19:9:21 | res | +| src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:9:19:9:21 | res | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:10:47:10:49 | res | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:13:33:13:35 | res | +| src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:13:33:13:35 | res | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:14:3:14:5 | res | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:15:3:15:5 | res | | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | src/indirect2.js:13:33:13:35 | res | +| src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | src/indirect2.js:13:33:13:35 | res | | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | src/indirect2.js:14:3:14:5 | res | | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | src/indirect2.js:15:3:15:5 | res | | src/indirect.js:16:12:20:5 | functio ... ;\\n } | src/indirect.js:16:26:16:28 | res | +| src/indirect.js:16:12:20:5 | functio ... ;\\n } | src/indirect.js:16:26:16:28 | res | | src/indirect.js:16:12:20:5 | functio ... ;\\n } | src/indirect.js:19:38:19:40 | res | | src/indirect.js:25:24:27:3 | (req, r ... ");\\n } | src/indirect.js:25:30:25:32 | res | +| src/indirect.js:25:24:27:3 | (req, r ... ");\\n } | src/indirect.js:25:30:25:32 | res | | src/indirect.js:25:24:27:3 | (req, r ... ");\\n } | src/indirect.js:26:5:26:7 | res | | src/indirect.js:28:15:30:3 | functio ... ");\\n } | src/indirect.js:28:29:28:31 | res | +| src/indirect.js:28:15:30:3 | functio ... ");\\n } | src/indirect.js:28:29:28:31 | res | | src/indirect.js:28:15:30:3 | functio ... ");\\n } | src/indirect.js:29:5:29:7 | res | test_ServerDefinition_getARouteHandler | createServer.js:2:1:2:42 | https.c ... es) {}) | createServer.js:2:20:2:41 | functio ... res) {} | @@ -294,6 +330,7 @@ test_RequestExpr | createServer.js:4:32:4:34 | req | createServer.js:4:31:4:46 | (req, res) => {} | | createServer.js:25:47:25:49 | req | createServer.js:25:37:27:5 | functio ... ;\\n } | | src/http.js:4:41:4:43 | req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | +| src/http.js:4:41:4:43 | req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | | src/http.js:6:26:6:28 | req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | | src/http.js:8:3:8:5 | req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | | src/http.js:9:3:9:5 | req | src/http.js:4:32:10:1 | functio ... .foo;\\n} | @@ -301,23 +338,29 @@ test_RequestExpr | src/http.js:55:21:55:23 | req | src/http.js:55:12:55:30 | function(req,res){} | | src/http.js:60:23:60:25 | req | src/http.js:60:14:60:32 | function(req,res){} | | src/http.js:62:28:62:30 | req | src/http.js:62:19:65:1 | functio ... r2");\\n} | +| src/http.js:62:28:62:30 | req | src/http.js:62:19:65:1 | functio ... r2");\\n} | | src/http.js:63:17:63:19 | req | src/http.js:62:19:65:1 | functio ... r2");\\n} | | src/http.js:68:13:68:15 | req | src/http.js:68:12:68:27 | (req,res) => f() | | src/http.js:72:29:72:31 | req | src/http.js:72:19:76:1 | functio ... \\n })\\n} | +| src/http.js:72:29:72:31 | req | src/http.js:72:19:76:1 | functio ... \\n })\\n} | | src/http.js:73:3:73:5 | req | src/http.js:72:19:76:1 | functio ... \\n })\\n} | | src/http.js:81:41:81:43 | req | src/http.js:81:22:86:1 | functio ... la");\\n} | +| src/http.js:81:41:81:43 | req | src/http.js:81:22:86:1 | functio ... la");\\n} | | src/http.js:82:3:82:5 | req | src/http.js:81:22:86:1 | functio ... la");\\n} | | src/https.js:4:42:4:44 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | +| src/https.js:4:42:4:44 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:6:26:6:28 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:8:3:8:5 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:9:3:9:5 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:12:29:12:31 | req | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/indirect2.js:9:14:9:16 | req | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | +| src/indirect2.js:9:14:9:16 | req | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:10:12:10:14 | req | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:10:42:10:44 | req | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:13:28:13:30 | req | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | | src/indirect2.js:13:28:13:30 | req | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | | src/indirect.js:16:21:16:23 | req | src/indirect.js:16:12:20:5 | functio ... ;\\n } | +| src/indirect.js:16:21:16:23 | req | src/indirect.js:16:12:20:5 | functio ... ;\\n } | | src/indirect.js:17:28:17:30 | req | src/indirect.js:16:12:20:5 | functio ... ;\\n } | | src/indirect.js:19:33:19:35 | req | src/indirect.js:16:12:20:5 | functio ... ;\\n } | | src/indirect.js:25:25:25:27 | req | src/indirect.js:25:24:27:3 | (req, r ... ");\\n } | @@ -337,6 +380,7 @@ test_RouteHandler_getARequestExpr | createServer.js:4:31:4:46 | (req, res) => {} | createServer.js:4:32:4:34 | req | | createServer.js:25:37:27:5 | functio ... ;\\n } | createServer.js:25:47:25:49 | req | | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:4:41:4:43 | req | +| src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:4:41:4:43 | req | | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:6:26:6:28 | req | | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:8:3:8:5 | req | | src/http.js:4:32:10:1 | functio ... .foo;\\n} | src/http.js:9:3:9:5 | req | @@ -344,23 +388,29 @@ test_RouteHandler_getARequestExpr | src/http.js:55:12:55:30 | function(req,res){} | src/http.js:55:21:55:23 | req | | src/http.js:60:14:60:32 | function(req,res){} | src/http.js:60:23:60:25 | req | | src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:62:28:62:30 | req | +| src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:62:28:62:30 | req | | src/http.js:62:19:65:1 | functio ... r2");\\n} | src/http.js:63:17:63:19 | req | | src/http.js:68:12:68:27 | (req,res) => f() | src/http.js:68:13:68:15 | req | | src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:72:29:72:31 | req | +| src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:72:29:72:31 | req | | src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:73:3:73:5 | req | | src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:81:41:81:43 | req | +| src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:81:41:81:43 | req | | src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:82:3:82:5 | req | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:4:42:4:44 | req | +| src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:4:42:4:44 | req | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:6:26:6:28 | req | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:8:3:8:5 | req | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:9:3:9:5 | req | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:12:29:12:31 | req | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:9:14:9:16 | req | +| src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:9:14:9:16 | req | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:10:12:10:14 | req | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:10:42:10:44 | req | | src/indirect2.js:9:1:11:1 | functio ... res);\\n} | src/indirect2.js:13:28:13:30 | req | | src/indirect2.js:13:1:16:1 | functio ... \\"");\\n} | src/indirect2.js:13:28:13:30 | req | | src/indirect.js:16:12:20:5 | functio ... ;\\n } | src/indirect.js:16:21:16:23 | req | +| src/indirect.js:16:12:20:5 | functio ... ;\\n } | src/indirect.js:16:21:16:23 | req | | src/indirect.js:16:12:20:5 | functio ... ;\\n } | src/indirect.js:17:28:17:30 | req | | src/indirect.js:16:12:20:5 | functio ... ;\\n } | src/indirect.js:19:33:19:35 | req | | src/indirect.js:25:24:27:3 | (req, r ... ");\\n } | src/indirect.js:25:25:25:27 | req | From 3eb486610b95840d54a91033d60cccc82a635913 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 17:02:56 +0200 Subject: [PATCH 13/39] update `Express::RouterDefinition` to a `DataFlow::InvokeNode` --- .../semmle/javascript/frameworks/Express.qll | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index bf2e6b8a25a0..f0946720ec9c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -84,7 +84,7 @@ module Express { private class RouterRange extends Routing::Router::Range { RouterDefinition def; - RouterRange() { this = def.flow() } + RouterRange() { this = def } override DataFlow::SourceNode getAReference() { result = def.ref() } } @@ -878,20 +878,17 @@ module Express { * Gets a route handler of the application, regardless of nesting. */ override HTTP::RouteHandler getARouteHandler() { - result = this.asExpr().(RouterDefinition).getASubRouter*().getARouteHandler() + result = this.(RouterDefinition).getASubRouter*().getARouteHandler() } } - /** - * An Express router. - */ - class RouterDefinition extends InvokeExpr { - // TODO: DataFlow::Node - RouterDefinition() { this = routerCreation().asExpr() } + /** An Express router. */ + class RouterDefinition extends DataFlow::Node instanceof DataFlow::InvokeNode { + RouterDefinition() { this = routerCreation() } private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { t.start() and - result = DataFlow::exprNode(this) + result = this or exists(string name | result = this.ref(t.continue()).getAMethodCall(name) | name = "route" or @@ -904,12 +901,6 @@ module Express { /** Gets a data flow node referring to this router. */ DataFlow::SourceNode ref() { result = this.ref(DataFlow::TypeTracker::end()) } - /** - * DEPRECATED: Use `ref().flowsToExpr()` instead. - * Holds if `sink` may refer to this router. - */ - deprecated predicate flowsTo(Expr sink) { this.ref().flowsToExpr(sink) } - /** * Gets a `RouteSetup` that was used for setting up a route on this router. */ From 3da34ca7a077d1d5e4bab6637deb0f934e123f6f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 17:18:18 +0200 Subject: [PATCH 14/39] update `Express::RouteExpr` to a `DataFlow::Node` --- .../semmle/javascript/frameworks/Express.qll | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index f0946720ec9c..c675bdb51314 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -40,28 +40,25 @@ module Express { ) } - /** - * Holds if `e` may refer to the given `router` object. - */ - private predicate isRouter(Expr e, RouterDefinition router) { router.ref().flowsToExpr(e) } // TODO: DataFlow::Node + /** Holds if `e` may refer to the given `router` object. */ + private predicate isRouter(DataFlow::Node e, RouterDefinition router) { router.ref().flowsTo(e) } /** * Holds if `e` may refer to a router object. */ - private predicate isRouter(Expr e) { - // TODO: DataFlow::Node + private predicate isRouter(DataFlow::Node e) { isRouter(e, _) or - e.getType().hasUnderlyingType("express", "Router") + e.asExpr().getType().hasUnderlyingType("express", "Router") or // created by `webpack-dev-server` - WebpackDevServer::webpackDevServerApp().flowsToExpr(e) + WebpackDevServer::webpackDevServerApp().flowsTo(e) } /** * An expression that refers to a route. */ - class RouteExpr extends MethodCallExpr { + class RouteExpr extends DataFlow::MethodCallNode { RouteExpr() { isRouter(this) } /** Gets the router from which this route was created, if it is known. */ @@ -143,7 +140,7 @@ module Express { */ class RouteSetup extends HTTP::Servers::StandardRouteSetup, DataFlow::MethodCallNode { RouteSetup() { - isRouter(this.getReceiver().asExpr()) and + isRouter(this.getReceiver()) and this.getMethodName() = routeSetupMethodName() } @@ -151,7 +148,7 @@ module Express { string getPath() { this.getArgument(0).mayHaveStringValue(result) } /** Gets the router on which handlers are being registered. */ - RouterDefinition getRouter() { isRouter(this.getReceiver().asExpr(), result) } + RouterDefinition getRouter() { isRouter(this.getReceiver(), result) } /** Holds if this is a call `use`, such as `app.use(handler)`. */ predicate isUseCall() { this.getMethodName() = "use" } @@ -420,7 +417,7 @@ module Express { /** * Gets the router being registered as a sub-router here, if any. */ - RouterDefinition getAsSubRouter() { isRouter(this, result) } + RouterDefinition getAsSubRouter() { isRouter(this.flow(), result) } } /** From 4cfbf15d18d95493caf6ef81235c052091297785 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 17:33:22 +0200 Subject: [PATCH 15/39] deprecate `RouteHandlerExpr` and make `RouteHandlerNode` instead --- .../semmle/javascript/frameworks/Express.qll | 74 +++++++++++++++---- .../frameworks/Express/RouteHandlerExpr.qll | 2 +- .../RouteHandlerExpr_getAMatchingAncestor.qll | 2 +- .../RouteHandlerExpr_getAsSubRouter.qll | 2 +- .../Express/RouteHandlerExpr_getBody.qll | 2 +- .../RouteHandlerExpr_getNextMiddleware.qll | 2 +- ...RouteHandlerExpr_getPreviousMiddleware.qll | 2 +- .../RouterDefinition_getMiddlewareStack.qll | 2 +- .../RouterDefinition_getMiddlewareStackAt.qll | 2 +- 9 files changed, 66 insertions(+), 24 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index c675bdb51314..7716d00d88a5 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -298,6 +298,7 @@ module Express { } /** + * DEPRECATED: Use `RouteHandlerNode` instead. * An expression used as an Express route handler, such as `submitHandler` below: * ``` * app.post('/submit', submitHandler) @@ -306,12 +307,56 @@ module Express { * Unlike `RouterHandler`, this is the argument passed to a setup, as opposed to * a function that flows into such an argument. */ - class RouteHandlerExpr extends Expr { - // TODO: DataFlow::Node + deprecated class RouteHandlerExpr extends Expr { + RouteHandlerNode node; + + RouteHandlerExpr() { this.flow() = node } + + /** Gets the setup call that registers this route handler. */ + deprecated RouteSetup getSetup() { result = node.getSetup() } + + /** Gets the function body of this handler, if it is defined locally. */ + deprecated RouteHandler getBody() { result = node.getBody() } + + /** Holds if this is not followed by more handlers. */ + deprecated predicate isLastHandler() { node.isLastHandler() } + + /** Gets a route handler that immediately precedes this in the route stack. */ + deprecated Express::RouteHandlerExpr getPreviousMiddleware() { + result = node.getPreviousMiddleware().asExpr() + } + + /** Gets a route handler that may follow immediately after this one in its route stack. */ + deprecated Express::RouteHandlerExpr getNextMiddleware() { + result = node.getNextMiddleware().asExpr() + } + + /** + * Gets a route handler that precedes this one (not necessarily immediately), may handle + * same request method, and matches on the same path or a prefix. + */ + deprecated Express::RouteHandlerExpr getAMatchingAncestor() { + result = node.getAMatchingAncestor().asExpr() + } + + /** Gets the router being registered as a sub-router here, if any. */ + deprecated RouterDefinition getAsSubRouter() { result = node.getAsSubRouter() } + } + + /** + * An expression used as an Express route handler, such as `submitHandler` below: + * ``` + * app.post('/submit', submitHandler) + * ``` + * + * Unlike `RouterHandler`, this is the argument passed to a setup, as opposed to + * a function that flows into such an argument. + */ + class RouteHandlerNode extends DataFlow::Node { RouteSetup setup; int index; - RouteHandlerExpr() { this = setup.getRouteHandlerNode(index).asExpr() } + RouteHandlerNode() { this = setup.getRouteHandlerNode(index) } /** * Gets the setup call that registers this route handler. @@ -322,7 +367,7 @@ module Express { * Gets the function body of this handler, if it is defined locally. */ RouteHandler getBody() { - exists(DataFlow::SourceNode source | source = this.flow().getALocalSource() | + exists(DataFlow::SourceNode source | source = this.getALocalSource() | result = source or DataFlow::functionOneWayForwardingStep(result.(DataFlow::SourceNode).getALocalUse(), source) @@ -359,11 +404,11 @@ module Express { * In this case, the previous from `foo` is `auth` although they do not act on the * same requests. */ - Express::RouteHandlerExpr getPreviousMiddleware() { + Express::RouteHandlerNode getPreviousMiddleware() { index = 0 and result = setup.getRouter().getMiddlewareStackAt(setup.asExpr().getAPredecessor()) or - index > 0 and result = setup.getRouteHandlerNode(index - 1).asExpr() + index > 0 and result = setup.getRouteHandlerNode(index - 1) or // Outside the router's original container, use the flow-insensitive model of its middleware stack. // Its state is not tracked to CFG nodes outside its original container. @@ -377,7 +422,7 @@ module Express { /** * Gets a route handler that may follow immediately after this one in its route stack. */ - Express::RouteHandlerExpr getNextMiddleware() { result.getPreviousMiddleware() = this } + Express::RouteHandlerNode getNextMiddleware() { result.getPreviousMiddleware() = this } /** * Gets a route handler that precedes this one (not necessarily immediately), may handle @@ -390,7 +435,7 @@ module Express { * router installs a route handler `r1` on a path that matches the path of a route handler * `r2` installed on a subrouter, `r1` will not be recognized as an ancestor of `r2`. */ - Express::RouteHandlerExpr getAMatchingAncestor() { + Express::RouteHandlerNode getAMatchingAncestor() { result = this.getPreviousMiddleware+() and exists(RouteSetup resSetup | resSetup = result.getSetup() | // check whether request methods are compatible @@ -407,7 +452,7 @@ module Express { or // if this is a sub-router, any previously installed middleware for the same // request method will necessarily match - exists(RouteHandlerExpr outer | + exists(RouteHandlerNode outer | setup.getRouter() = outer.getAsSubRouter() and outer.getSetup().handlesSameRequestMethodAs(setup) and result = outer.getAMatchingAncestor() @@ -417,7 +462,7 @@ module Express { /** * Gets the router being registered as a sub-router here, if any. */ - RouterDefinition getAsSubRouter() { isRouter(this.flow(), result) } + RouterDefinition getAsSubRouter() { isRouter(this, result) } } /** @@ -934,22 +979,19 @@ module Express { * * If `node` is not in the same container where `router` was defined, the predicate has no result. */ - Express::RouteHandlerExpr getMiddlewareStackAt(ControlFlowNode node) { - // TODO: DataFlow::Node? + Express::RouteHandlerNode getMiddlewareStackAt(ControlFlowNode node) { if exists(Express::RouteSetup setup | node = setup.asExpr() and setup.getRouter() = this | setup.isUseCall() ) - then - result = - node.(AST::ValueNode).flow().(Express::RouteSetup).getLastRouteHandlerNode().asExpr() + then result = node.(AST::ValueNode).flow().(Express::RouteSetup).getLastRouteHandlerNode() else result = this.getMiddlewareStackAt(node.getAPredecessor()) } /** * Gets the final middleware registered on this router. */ - Express::RouteHandlerExpr getMiddlewareStack() { + Express::RouteHandlerNode getMiddlewareStack() { result = this.getMiddlewareStackAt(this.getContainer().getExit()) } } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr.qll index a6c008294dd0..4d3190d34fee 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr.qll @@ -1,7 +1,7 @@ import javascript query predicate test_RouteHandlerExpr( - Express::RouteHandlerExpr rhe, Express::RouteSetup res0, boolean isLast + Express::RouteHandlerNode rhe, Express::RouteSetup res0, boolean isLast ) { (if rhe.isLastHandler() then isLast = true else isLast = false) and res0 = rhe.getSetup() diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getAMatchingAncestor.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getAMatchingAncestor.qll index b42d063bbfae..4cf5088b28d6 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getAMatchingAncestor.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getAMatchingAncestor.qll @@ -1,7 +1,7 @@ import javascript query predicate test_RouteHandlerExpr_getAMatchingAncestor( - Express::RouteHandlerExpr expr, Express::RouteHandlerExpr res + Express::RouteHandlerNode expr, Express::RouteHandlerNode res ) { res = expr.getAMatchingAncestor() } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getAsSubRouter.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getAsSubRouter.qll index 3bb2799d7fbf..10fa029b1782 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getAsSubRouter.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getAsSubRouter.qll @@ -1,7 +1,7 @@ import javascript query predicate test_RouteHandlerExpr_getAsSubRouter( - Express::RouteHandlerExpr expr, Express::RouterDefinition res + Express::RouteHandlerNode expr, Express::RouterDefinition res ) { res = expr.getAsSubRouter() } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getBody.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getBody.qll index 962ef8aab5b4..7a58c892ef50 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getBody.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getBody.qll @@ -1,7 +1,7 @@ import javascript query predicate test_RouteHandlerExpr_getBody( - Express::RouteHandlerExpr rhe, Express::RouteHandler res + Express::RouteHandlerNode rhe, Express::RouteHandler res ) { res = rhe.getBody() } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getNextMiddleware.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getNextMiddleware.qll index 93d7457b2f1e..ac513215c40f 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getNextMiddleware.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getNextMiddleware.qll @@ -1,7 +1,7 @@ import javascript query predicate test_RouteHandlerExpr_getNextMiddleware( - Express::RouteHandlerExpr expr, Express::RouteHandlerExpr res + Express::RouteHandlerNode expr, Express::RouteHandlerNode res ) { res = expr.getNextMiddleware() } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getPreviousMiddleware.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getPreviousMiddleware.qll index a202198b2050..ebe1982a7bf1 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getPreviousMiddleware.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandlerExpr_getPreviousMiddleware.qll @@ -1,7 +1,7 @@ import javascript query predicate test_RouteHandlerExpr_getPreviousMiddleware( - Express::RouteHandlerExpr expr, Express::RouteHandlerExpr res + Express::RouteHandlerNode expr, Express::RouteHandlerNode res ) { res = expr.getPreviousMiddleware() } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getMiddlewareStack.qll b/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getMiddlewareStack.qll index ba7f8a435760..93a0d53b3ac6 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getMiddlewareStack.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getMiddlewareStack.qll @@ -1,7 +1,7 @@ import javascript query predicate test_RouterDefinition_getMiddlewareStack( - Express::RouterDefinition r, Express::RouteHandlerExpr res + Express::RouterDefinition r, Express::RouteHandlerNode res ) { res = r.getMiddlewareStack() } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getMiddlewareStackAt.qll b/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getMiddlewareStackAt.qll index 36b9447abf0e..7de8ccc7114e 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getMiddlewareStackAt.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouterDefinition_getMiddlewareStackAt.qll @@ -1,7 +1,7 @@ import javascript query predicate test_RouterDefinition_getMiddlewareStackAt( - Express::RouterDefinition r, ControlFlowNode nd, Express::RouteHandlerExpr res + Express::RouterDefinition r, ControlFlowNode nd, Express::RouteHandlerNode res ) { res = r.getMiddlewareStackAt(nd) } From 8266b083d7c8e9d4f440d9f1fa8ce89382e96c0b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 17:55:45 +0200 Subject: [PATCH 16/39] update the predicates on `Express::RouteHandler` to use dataflow nodes --- .../semmle/javascript/frameworks/Connect.qll | 18 ++++---- .../frameworks/ConnectExpressShared.qll | 14 +++--- .../semmle/javascript/frameworks/Express.qll | 46 +++++++++---------- .../semmle/javascript/frameworks/Firebase.qll | 10 ++-- .../javascript/frameworks/HttpProxy.qll | 12 ++--- .../javascript/frameworks/LiveServer.qll | 4 +- .../lib/semmle/javascript/frameworks/Next.qll | 6 +-- .../javascript/frameworks/NodeJSLib.qll | 8 ++-- .../heuristics/AdditionalRouteHandlers.qll | 8 ++-- .../security/dataflow/MissingRateLimiting.qll | 2 +- .../frameworks/Express/RouteHandler.qll | 4 +- .../RouteHandler_getARequestBodyAccess.qll | 2 +- .../Express/StandardRouteHandler.qll | 3 +- 13 files changed, 69 insertions(+), 68 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll b/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll index 04e2bd43f377..f662faf9a5b7 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll @@ -30,29 +30,31 @@ module Connect { * * `kind` is one of: "error", "request", "response", "next". */ - abstract Parameter getRouteHandlerParameter(string kind); + abstract DataFlow::ParameterNode getRouteHandlerParameter(string kind); /** * Gets the parameter of the route handler that contains the request object. */ - override Parameter getRequestParameter() { result = getRouteHandlerParameter("request") } + override DataFlow::ParameterNode getRequestParameter() { + result = getRouteHandlerParameter("request") + } /** * Gets the parameter of the route handler that contains the response object. */ - override Parameter getResponseParameter() { result = getRouteHandlerParameter("response") } + override DataFlow::ParameterNode getResponseParameter() { + result = getRouteHandlerParameter("response") + } } /** * A Connect route handler installed by a route setup. */ - class StandardRouteHandler extends RouteHandler { - override Function astNode; - + class StandardRouteHandler extends RouteHandler, DataFlow::FunctionNode { StandardRouteHandler() { this = any(RouteSetup setup).getARouteHandler() } - override Parameter getRouteHandlerParameter(string kind) { - result = getRouteHandlerParameter(astNode, kind) + override DataFlow::ParameterNode getRouteHandlerParameter(string kind) { + result = getRouteHandlerParameter(this, kind) } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ConnectExpressShared.qll b/javascript/ql/lib/semmle/javascript/frameworks/ConnectExpressShared.qll index 489fcf550c41..f0ea2f03f683 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ConnectExpressShared.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ConnectExpressShared.qll @@ -52,7 +52,7 @@ module ConnectExpressShared { /** * Holds if `function` appears to match the given signature based on parameter naming. */ - private predicate matchesSignature(Function function, RouteHandlerSignature sig) { + private predicate matchesSignature(DataFlow::FunctionNode function, RouteHandlerSignature sig) { function.getNumParameter() = sig.getArity() and function.getParameter(sig.getParameterIndex("request")).getName() = ["req", "request"] and function.getParameter(sig.getParameterIndex("response")).getName() = ["res", "response"] and @@ -71,8 +71,8 @@ module ConnectExpressShared { * so the caller should restrict the function accordingly. */ pragma[inline] - private Parameter getRouteHandlerParameter( - Function routeHandler, RouteHandlerSignature sig, string kind + private DataFlow::ParameterNode getRouteHandlerParameter( + DataFlow::FunctionNode routeHandler, RouteHandlerSignature sig, string kind ) { result = routeHandler.getParameter(sig.getParameterIndex(kind)) } @@ -83,7 +83,9 @@ module ConnectExpressShared { * `kind` is one of: "error", "request", "response", "next". */ pragma[inline] - Parameter getRouteParameterHandlerParameter(Function routeHandler, string kind) { + DataFlow::ParameterNode getRouteParameterHandlerParameter( + DataFlow::FunctionNode routeHandler, string kind + ) { result = getRouteHandlerParameter(routeHandler, RouteHandlerSignature::requestResponseNextParameter(), kind) @@ -95,7 +97,7 @@ module ConnectExpressShared { * `kind` is one of: "error", "request", "response", "next". */ pragma[inline] - Parameter getRouteHandlerParameter(Function routeHandler, string kind) { + DataFlow::ParameterNode getRouteHandlerParameter(DataFlow::FunctionNode routeHandler, string kind) { if routeHandler.getNumParameter() = 4 then // For arity 4 there is ambiguity between (err, req, res, next) and (req, res, next, param) @@ -115,7 +117,7 @@ module ConnectExpressShared { */ class RouteHandlerCandidate extends HTTP::RouteHandlerCandidate { RouteHandlerCandidate() { - matchesSignature(astNode, _) and + matchesSignature(this, _) and not ( // heuristic: not a class method (the server invokes this with a function call) astNode = any(MethodDefinition def).getBody() diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 7716d00d88a5..8e597758c45e 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -286,14 +286,12 @@ module Express { * The callback given to passport in PassportRouteSetup. */ private class PassportRouteHandler extends RouteHandler, HTTP::Servers::StandardRouteHandler, - DataFlow::ValueNode { - override Function astNode; - + DataFlow::FunctionNode { PassportRouteHandler() { this = any(PassportRouteSetup setup).getARouteHandler() } - override Parameter getRouteHandlerParameter(string kind) { + override DataFlow::ParameterNode getRouteHandlerParameter(string kind) { kind = "request" and - result = astNode.getParameter(0) + result = this.getParameter(0) } } @@ -478,40 +476,41 @@ module Express { * * `kind` is one of: "error", "request", "response", "next", or "parameter". */ - abstract Parameter getRouteHandlerParameter(string kind); // TODO: DataFlow::ParameterNode + abstract DataFlow::ParameterNode getRouteHandlerParameter(string kind); /** * Gets the parameter of the route handler that contains the request object. */ - Parameter getRequestParameter() { result = this.getRouteHandlerParameter("request") } // TODO: DataFlow::ParameterNode + DataFlow::ParameterNode getRequestParameter() { + result = this.getRouteHandlerParameter("request") + } /** * Gets the parameter of the route handler that contains the response object. */ - Parameter getResponseParameter() { result = this.getRouteHandlerParameter("response") } // TODO: DataFlow::ParameterNode + DataFlow::ParameterNode getResponseParameter() { + result = this.getRouteHandlerParameter("response") + } /** * Gets a request body access of this handler. */ - Expr getARequestBodyAccess() { - result.(PropAccess).accesses(this.getARequestNode().asExpr(), "body") - } // TODO: DataFlow::Node + DataFlow::PropRead getARequestBodyAccess() { result.accesses(this.getARequestNode(), "body") } } /** * An Express route handler installed by a route setup. */ class StandardRouteHandler extends RouteHandler, HTTP::Servers::StandardRouteHandler, - DataFlow::ValueNode { - override Function astNode; + DataFlow::FunctionNode { RouteSetup routeSetup; StandardRouteHandler() { this = routeSetup.getARouteHandler() } - override Parameter getRouteHandlerParameter(string kind) { + override DataFlow::ParameterNode getRouteHandlerParameter(string kind) { if routeSetup.isParameterHandler() - then result = getRouteParameterHandlerParameter(astNode, kind) - else result = getRouteHandlerParameter(astNode, kind) + then result = getRouteParameterHandlerParameter(this, kind) + else result = getRouteHandlerParameter(this, kind) } } @@ -540,7 +539,7 @@ module Express { RouteHandler rh; ExplicitResponseSource() { - this = DataFlow::parameterNode(rh.getResponseParameter()) + this = rh.getResponseParameter() or isChainableResponseMethodCall(rh, this.asExpr()) } @@ -570,7 +569,7 @@ module Express { private class ExplicitRequestSource extends RequestSource { RouteHandler rh; - ExplicitRequestSource() { this = DataFlow::parameterNode(rh.getRequestParameter()) } + ExplicitRequestSource() { this = rh.getRequestParameter() } /** * Gets the route handler that handles this request. @@ -637,7 +636,7 @@ module Express { ParamHandlerInputAccess() { exists(RouteSetup setup | rh = setup.getARouteHandler() | - this = DataFlow::parameterNode(rh.getRouteHandlerParameter("parameter")) + this = rh.getRouteHandlerParameter("parameter") ) } @@ -778,7 +777,8 @@ module Express { * An access to the HTTP request body. */ class RequestBodyAccess extends Expr { - RequestBodyAccess() { any(RouteHandler h).getARequestBodyAccess() = this } + // TODO: DataFlow::Node + RequestBodyAccess() { any(RouteHandler h).getARequestBodyAccess().asExpr() = this } } abstract private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { @@ -1049,10 +1049,10 @@ module Express { TrackedRouteHandlerCandidateWithSetup() { this = routeSetup.getARouteHandler() } - override Parameter getRouteHandlerParameter(string kind) { + override DataFlow::ParameterNode getRouteHandlerParameter(string kind) { if routeSetup.isParameterHandler() - then result = getRouteParameterHandlerParameter(astNode, kind) - else result = getRouteHandlerParameter(astNode, kind) + then result = getRouteParameterHandlerParameter(this, kind) + else result = getRouteHandlerParameter(this, kind) } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/lib/semmle/javascript/frameworks/Firebase.qll index 626943688154..5327fc1bf461 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Firebase.qll @@ -216,15 +216,13 @@ module Firebase { * A function used as a route handler. */ private class RouteHandler extends Express::RouteHandler, HTTP::Servers::StandardRouteHandler, - DataFlow::ValueNode { - override Function astNode; - + DataFlow::FunctionNode { RouteHandler() { this = any(RouteSetup setup).getARouteHandler() } - override Parameter getRouteHandlerParameter(string kind) { - kind = "request" and result = astNode.getParameter(0) + override DataFlow::ParameterNode getRouteHandlerParameter(string kind) { + kind = "request" and result = this.getParameter(0) or - kind = "response" and result = astNode.getParameter(1) + kind = "response" and result = this.getParameter(1) } } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/HttpProxy.qll b/javascript/ql/lib/semmle/javascript/frameworks/HttpProxy.qll index 24e694ca8d9d..b471dd344314 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/HttpProxy.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/HttpProxy.qll @@ -83,16 +83,12 @@ private module HttpProxy { ) } - override Parameter getRequestParameter() { - exists(int req | routeHandlingEventHandler(event, req, _) | - result = getFunction().getParameter(req) - ) + override DataFlow::ParameterNode getRequestParameter() { + exists(int req | routeHandlingEventHandler(event, req, _) | result = getParameter(req)) } - override Parameter getResponseParameter() { - exists(int res | routeHandlingEventHandler(event, _, res) | - result = getFunction().getParameter(res) - ) + override DataFlow::ParameterNode getResponseParameter() { + exists(int res | routeHandlingEventHandler(event, _, res) | result = getParameter(res)) } } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll b/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll index da23907ee8f5..cc90dc8d7207 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll @@ -22,8 +22,8 @@ private module LiveServer { class RouteHandler extends Connect::RouteHandler, DataFlow::FunctionNode { RouteHandler() { this = any(RouteSetup setup).getARouteHandler() } - override Parameter getRouteHandlerParameter(string kind) { - result = ConnectExpressShared::getRouteHandlerParameter(astNode, kind) + override DataFlow::ParameterNode getRouteHandlerParameter(string kind) { + result = ConnectExpressShared::getRouteHandlerParameter(this, kind) } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Next.qll b/javascript/ql/lib/semmle/javascript/frameworks/Next.qll index 091aa8ba1af6..604577c6a706 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Next.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Next.qll @@ -230,10 +230,10 @@ module NextJS { ) } - override Parameter getRouteHandlerParameter(string kind) { - kind = "request" and result = this.getFunction().getParameter(0) + override DataFlow::ParameterNode getRouteHandlerParameter(string kind) { + kind = "request" and result = this.getParameter(0) or - kind = "response" and result = this.getFunction().getParameter(1) + kind = "response" and result = this.getParameter(1) } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll index 59b2d6d9137e..0abc70760187 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll @@ -114,12 +114,12 @@ module NodeJSLib { /** * Gets the parameter of the route handler that contains the request object. */ - Parameter getRequestParameter() { result = this.getFunction().getParameter(0) } + DataFlow::ParameterNode getRequestParameter() { result = this.getParameter(0) } /** * Gets the parameter of the route handler that contains the response object. */ - Parameter getResponseParameter() { result = this.getFunction().getParameter(1) } + DataFlow::ParameterNode getResponseParameter() { result = this.getParameter(1) } } /** @@ -141,7 +141,7 @@ module NodeJSLib { private class StandardResponseSource extends ResponseSource { RouteHandler rh; - StandardResponseSource() { this = DataFlow::parameterNode(rh.getResponseParameter()) } + StandardResponseSource() { this = rh.getResponseParameter() } /** * Gets the route handler that provides this response. @@ -161,7 +161,7 @@ module NodeJSLib { private class StandardRequestSource extends RequestSource { RouteHandler rh; - StandardRequestSource() { this = DataFlow::parameterNode(rh.getRequestParameter()) } + StandardRequestSource() { this = rh.getRequestParameter() } /** * Gets the route handler that handles this request. diff --git a/javascript/ql/lib/semmle/javascript/heuristics/AdditionalRouteHandlers.qll b/javascript/ql/lib/semmle/javascript/heuristics/AdditionalRouteHandlers.qll index 3b9c3b1bb79f..1d873a3f2a97 100644 --- a/javascript/ql/lib/semmle/javascript/heuristics/AdditionalRouteHandlers.qll +++ b/javascript/ql/lib/semmle/javascript/heuristics/AdditionalRouteHandlers.qll @@ -29,8 +29,8 @@ private class PromotedExpressCandidate extends Express::RouteHandler, HTTP::Servers::StandardRouteHandler { PromotedExpressCandidate() { this instanceof ConnectExpressShared::RouteHandlerCandidate } - override Parameter getRouteHandlerParameter(string kind) { - result = ConnectExpressShared::getRouteHandlerParameter(getAstNode(), kind) + override DataFlow::ParameterNode getRouteHandlerParameter(string kind) { + result = ConnectExpressShared::getRouteHandlerParameter(this, kind) } } @@ -41,7 +41,7 @@ private class PromotedConnectCandidate extends Connect::RouteHandler, HTTP::Servers::StandardRouteHandler { PromotedConnectCandidate() { this instanceof ConnectExpressShared::RouteHandlerCandidate } - override Parameter getRouteHandlerParameter(string kind) { - result = ConnectExpressShared::getRouteHandlerParameter(getAstNode(), kind) + override DataFlow::ParameterNode getRouteHandlerParameter(string kind) { + result = ConnectExpressShared::getRouteHandlerParameter(this, kind) } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll index b4acd922498c..7d3958d83d8d 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll @@ -199,7 +199,7 @@ class RateLimiterFlexibleRateLimiter extends DataFlow::FunctionNode { rateLimiterClassName.matches("RateLimiter%") and rateLimiterClass = API::moduleImport("rate-limiter-flexible").getMember(rateLimiterClassName) and rateLimiterConsume = rateLimiterClass.getInstance().getMember("consume") and - request.getParameter() = getRouteHandlerParameter(this.getFunction(), "request") and + request = getRouteHandlerParameter(this, "request") and request.getAPropertyRead().flowsTo(rateLimiterConsume.getAParameter().asSink()) ) } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandler.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteHandler.qll index 4873bcf2d997..5a737738b626 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandler.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandler.qll @@ -1,5 +1,7 @@ import javascript -query predicate test_RouteHandler(Express::RouteHandler rh, Parameter res0, Parameter res1) { +query predicate test_RouteHandler( + Express::RouteHandler rh, DataFlow::ParameterNode res0, DataFlow::ParameterNode res1 +) { res0 = rh.getRequestParameter() and res1 = rh.getResponseParameter() } diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getARequestBodyAccess.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getARequestBodyAccess.qll index 805200c7f8d3..80800ecd7552 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getARequestBodyAccess.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/RouteHandler_getARequestBodyAccess.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_RouteHandler_getARequestBodyAccess(Express::RouteHandler rh, Expr res) { +query predicate test_RouteHandler_getARequestBodyAccess(Express::RouteHandler rh, DataFlow::Node res) { res = rh.getARequestBodyAccess() } diff --git a/javascript/ql/test/library-tests/frameworks/Express/StandardRouteHandler.qll b/javascript/ql/test/library-tests/frameworks/Express/StandardRouteHandler.qll index 26f06678dc8e..2ffc514a6d05 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/StandardRouteHandler.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/StandardRouteHandler.qll @@ -1,7 +1,8 @@ import javascript query predicate test_StandardRouteHandler( - Express::StandardRouteHandler rh, DataFlow::Node res0, SimpleParameter res1, SimpleParameter res2 + Express::StandardRouteHandler rh, DataFlow::Node res0, DataFlow::ParameterNode res1, + DataFlow::ParameterNode res2 ) { res0 = rh.getServer() and res1 = rh.getRequestParameter() and res2 = rh.getResponseParameter() } From fc54ba823ba633511f1b5c206670f8b3dd054bc8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 19:29:54 +0200 Subject: [PATCH 17/39] update the existing expression based Express models --- .../semmle/javascript/frameworks/Express.qll | 20 +-- .../dataflow/TaintedPathCustomizations.qll | 6 +- .../frameworks/Express/isRequest.qll | 2 +- .../frameworks/Express/isResponse.qll | 2 +- .../frameworks/Express/tests.expected | 150 +++++++++--------- 5 files changed, 86 insertions(+), 94 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 8e597758c45e..26e4bc20002b 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -517,9 +517,10 @@ module Express { /** * Holds if `call` is a chainable method call on the response object of `handler`. */ - private predicate isChainableResponseMethodCall(RouteHandler handler, MethodCallExpr call) { - // TODO: DataFlow::MethodCallNode - exists(string name | call.calls(handler.getAResponseNode().asExpr(), name) | + private predicate isChainableResponseMethodCall( + RouteHandler handler, DataFlow::MethodCallNode call + ) { + exists(string name | call.calls(handler.getAResponseNode(), name) | name = [ "append", "attachment", "location", "send", "sendStatus", "set", "status", "type", "vary", @@ -541,7 +542,7 @@ module Express { ExplicitResponseSource() { this = rh.getResponseParameter() or - isChainableResponseMethodCall(rh, this.asExpr()) + isChainableResponseMethodCall(rh, this) } /** @@ -766,23 +767,22 @@ module Express { /** * Holds if `e` is an HTTP request object. */ - predicate isRequest(Expr e) { any(RouteHandler rh).getARequestNode().asExpr() = e } // TODO: DataFlow::Node + predicate isRequest(DataFlow::Node e) { any(RouteHandler rh).getARequestNode() = e } /** * Holds if `e` is an HTTP response object. */ - predicate isResponse(Expr e) { any(RouteHandler rh).getAResponseNode().asExpr() = e } // TODO: DataFlow::Node + predicate isResponse(DataFlow::Node e) { any(RouteHandler rh).getAResponseNode() = e } /** * An access to the HTTP request body. */ - class RequestBodyAccess extends Expr { - // TODO: DataFlow::Node - RequestBodyAccess() { any(RouteHandler h).getARequestBodyAccess().asExpr() = this } + class RequestBodyAccess extends DataFlow::Node { + RequestBodyAccess() { any(RouteHandler h).getARequestBodyAccess() = this } } abstract private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { - HeaderDefinition() { isResponse(this.getReceiver().asExpr()) } + HeaderDefinition() { isResponse(this.getReceiver()) } override RouteHandler getRouteHandler() { this.getReceiver() = result.getAResponseNode() } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index 03b1211326a5..c463b1d3ecbd 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -647,12 +647,12 @@ module TaintedPath { /** * A path argument to the Express `res.render` method. */ - class ExpressRenderSink extends Sink, DataFlow::ValueNode { + class ExpressRenderSink extends Sink { ExpressRenderSink() { - exists(MethodCallExpr mce | + exists(DataFlow::MethodCallNode mce | Express::isResponse(mce.getReceiver()) and mce.getMethodName() = "render" and - astNode = mce.getArgument(0) + this = mce.getArgument(0) ) } } diff --git a/javascript/ql/test/library-tests/frameworks/Express/isRequest.qll b/javascript/ql/test/library-tests/frameworks/Express/isRequest.qll index 90c641e5be1f..9aa8ef4c9fa6 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/isRequest.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/isRequest.qll @@ -1,3 +1,3 @@ import javascript -query predicate test_isRequest(Expr nd) { Express::isRequest(nd) } +query predicate test_isRequest(DataFlow::Node nd) { Express::isRequest(nd) } diff --git a/javascript/ql/test/library-tests/frameworks/Express/isResponse.qll b/javascript/ql/test/library-tests/frameworks/Express/isResponse.qll index edc219adb67b..0ebf42be544b 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/isResponse.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/isResponse.qll @@ -1,3 +1,3 @@ import javascript -query predicate test_isResponse(Expr nd) { Express::isResponse(nd) } +query predicate test_isResponse(DataFlow::Node nd) { Express::isResponse(nd) } diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.expected b/javascript/ql/test/library-tests/frameworks/Express/tests.expected index a4b5397d9508..cce9e29c9467 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.expected @@ -769,50 +769,72 @@ test_RouterDefinition_getMiddlewareStackAt | src/subrouter.js:2:11:2:19 | express() | src/subrouter.js:13:1:13:0 | exit node of | src/subrouter.js:5:14:5:28 | makeSubRouter() | test_isRequest | src/advanced-routehandler-registration.js:6:7:6:9 | req | +| src/advanced-routehandler-registration.js:6:7:6:9 | req | | src/advanced-routehandler-registration.js:6:32:6:34 | req | | src/advanced-routehandler-registration.js:7:7:7:9 | req | +| src/advanced-routehandler-registration.js:7:7:7:9 | req | | src/advanced-routehandler-registration.js:7:32:7:34 | req | | src/advanced-routehandler-registration.js:15:7:15:9 | req | +| src/advanced-routehandler-registration.js:15:7:15:9 | req | | src/advanced-routehandler-registration.js:15:32:15:34 | req | | src/advanced-routehandler-registration.js:16:7:16:9 | req | +| src/advanced-routehandler-registration.js:16:7:16:9 | req | | src/advanced-routehandler-registration.js:16:32:16:34 | req | | src/advanced-routehandler-registration.js:24:7:24:9 | req | +| src/advanced-routehandler-registration.js:24:7:24:9 | req | | src/advanced-routehandler-registration.js:24:32:24:34 | req | | src/advanced-routehandler-registration.js:25:7:25:9 | req | +| src/advanced-routehandler-registration.js:25:7:25:9 | req | | src/advanced-routehandler-registration.js:25:32:25:34 | req | | src/advanced-routehandler-registration.js:46:20:46:22 | req | +| src/advanced-routehandler-registration.js:46:20:46:22 | req | | src/advanced-routehandler-registration.js:47:27:47:29 | req | | src/advanced-routehandler-registration.js:51:10:51:12 | req | +| src/advanced-routehandler-registration.js:51:10:51:12 | req | | src/advanced-routehandler-registration.js:51:40:51:42 | req | | src/advanced-routehandler-registration.js:59:20:59:22 | req | +| src/advanced-routehandler-registration.js:59:20:59:22 | req | | src/advanced-routehandler-registration.js:60:18:60:20 | req | | src/advanced-routehandler-registration.js:64:10:64:12 | req | +| src/advanced-routehandler-registration.js:64:10:64:12 | req | | src/advanced-routehandler-registration.js:64:45:64:47 | req | | src/advanced-routehandler-registration.js:68:13:68:15 | req | +| src/advanced-routehandler-registration.js:68:13:68:15 | req | | src/advanced-routehandler-registration.js:68:38:68:40 | req | | src/advanced-routehandler-registration.js:69:20:69:22 | req | +| src/advanced-routehandler-registration.js:69:20:69:22 | req | | src/advanced-routehandler-registration.js:70:18:70:20 | req | | src/advanced-routehandler-registration.js:73:10:73:12 | req | +| src/advanced-routehandler-registration.js:73:10:73:12 | req | | src/advanced-routehandler-registration.js:73:47:73:49 | req | | src/advanced-routehandler-registration.js:81:20:81:22 | req | +| src/advanced-routehandler-registration.js:81:20:81:22 | req | | src/advanced-routehandler-registration.js:82:27:82:29 | req | | src/advanced-routehandler-registration.js:92:10:92:12 | req | +| src/advanced-routehandler-registration.js:92:10:92:12 | req | | src/advanced-routehandler-registration.js:92:40:92:42 | req | | src/advanced-routehandler-registration.js:100:20:100:22 | req | +| src/advanced-routehandler-registration.js:100:20:100:22 | req | | src/advanced-routehandler-registration.js:101:31:101:33 | req | | src/advanced-routehandler-registration.js:111:10:111:12 | req | +| src/advanced-routehandler-registration.js:111:10:111:12 | req | | src/advanced-routehandler-registration.js:111:40:111:42 | req | | src/advanced-routehandler-registration.js:123:21:123:23 | req | +| src/advanced-routehandler-registration.js:123:21:123:23 | req | | src/advanced-routehandler-registration.js:123:46:123:48 | req | | src/advanced-routehandler-registration.js:124:21:124:23 | req | +| src/advanced-routehandler-registration.js:124:21:124:23 | req | | src/advanced-routehandler-registration.js:124:46:124:48 | req | | src/advanced-routehandler-registration.js:146:29:146:31 | req | | src/advanced-routehandler-registration.js:156:22:156:24 | req | +| src/advanced-routehandler-registration.js:156:22:156:24 | req | | src/advanced-routehandler-registration.js:156:47:156:49 | req | | src/advanced-routehandler-registration.js:157:28:157:30 | req | +| src/advanced-routehandler-registration.js:157:28:157:30 | req | | src/advanced-routehandler-registration.js:157:53:157:55 | req | | src/controllers/handler-in-bulk-require.js:1:45:1:47 | req | | src/csurf-example.js:20:28:20:30 | req | +| src/csurf-example.js:20:28:20:30 | req | | src/csurf-example.js:22:35:22:37 | req | | src/csurf-example.js:25:32:25:34 | req | | src/csurf-example.js:32:40:32:42 | req | @@ -820,22 +842,28 @@ test_isRequest | src/csurf-example.js:40:37:40:39 | req | | src/exportedHandler.js:1:44:1:46 | req | | src/express2.js:3:34:3:36 | req | +| src/express2.js:3:34:3:36 | req | | src/express2.js:3:46:3:48 | req | | src/express2.js:4:41:4:47 | request | +| src/express2.js:4:41:4:47 | request | | src/express2.js:4:60:4:66 | request | | src/express3.js:4:32:4:34 | req | +| src/express3.js:4:32:4:34 | req | | src/express3.js:5:14:5:16 | req | | src/express3.js:5:35:5:37 | req | | src/express3.js:10:22:10:24 | req | | src/express4.js:4:32:4:34 | req | +| src/express4.js:4:32:4:34 | req | | src/express4.js:5:27:5:29 | req | | src/express4.js:6:18:6:20 | req | | src/express4.js:7:18:7:20 | req | | src/express.js:4:32:4:34 | req | +| src/express.js:4:32:4:34 | req | | src/express.js:5:16:5:18 | req | | src/express.js:6:26:6:28 | req | | src/express.js:16:28:16:30 | req | | src/express.js:22:39:22:41 | req | +| src/express.js:22:39:22:41 | req | | src/express.js:23:3:23:5 | req | | src/express.js:24:3:24:5 | req | | src/express.js:25:3:25:5 | req | @@ -847,43 +875,55 @@ test_isRequest | src/express.js:37:22:37:24 | req | | src/express.js:42:13:42:15 | req | | src/express.js:46:31:46:33 | req | +| src/express.js:46:31:46:33 | req | | src/express.js:47:3:47:5 | req | | src/express.js:48:3:48:5 | req | | src/express.js:49:3:49:5 | req | | src/express.js:50:3:50:5 | req | | src/inheritedFromNode.js:4:24:4:26 | req | +| src/inheritedFromNode.js:4:24:4:26 | req | | src/inheritedFromNode.js:7:2:7:4 | req | | src/middleware-flow.js:5:20:5:22 | req | +| src/middleware-flow.js:5:20:5:22 | req | | src/middleware-flow.js:6:5:6:7 | req | | src/middleware-flow.js:7:5:7:7 | req | | src/middleware-flow.js:8:5:8:7 | req | | src/middleware-flow.js:17:25:17:27 | req | +| src/middleware-flow.js:17:25:17:27 | req | | src/middleware-flow.js:18:9:18:11 | req | | src/middleware-flow.js:19:9:19:11 | req | | src/middleware-flow.js:20:9:20:11 | req | | src/middleware-flow.js:23:18:23:20 | req | +| src/middleware-flow.js:23:18:23:20 | req | | src/middleware-flow.js:23:33:23:35 | req | | src/middleware-flow.js:24:18:24:20 | req | +| src/middleware-flow.js:24:18:24:20 | req | | src/middleware-flow.js:24:33:24:35 | req | | src/middleware-flow.js:39:24:39:26 | req | +| src/middleware-flow.js:39:24:39:26 | req | | src/middleware-flow.js:40:5:40:7 | req | | src/middleware-flow.js:41:5:41:7 | req | | src/middleware-flow.js:42:5:42:7 | req | | src/params.js:4:19:4:21 | req | +| src/params.js:4:19:4:21 | req | | src/params.js:5:17:5:19 | req | | src/params.js:6:17:6:19 | req | | src/params.js:14:33:14:35 | req | | src/passport.js:27:13:27:15 | req | +| src/passport.js:27:13:27:15 | req | | src/passport.js:28:2:28:4 | req | | src/responseExprs.js:4:32:4:34 | req | | src/responseExprs.js:7:32:7:34 | req | | src/responseExprs.js:10:39:10:41 | req | | src/responseExprs.js:13:32:13:34 | req | | src/responseExprs.js:16:39:16:41 | req | +| src/responseExprs.js:16:39:16:41 | req | | src/responseExprs.js:17:5:17:7 | req | | src/route-collection.js:2:7:2:9 | req | +| src/route-collection.js:2:7:2:9 | req | | src/route-collection.js:2:32:2:34 | req | | src/route-collection.js:3:7:3:9 | req | +| src/route-collection.js:3:7:3:9 | req | | src/route-collection.js:3:32:3:34 | req | | src/route.js:5:21:5:23 | req | test_RouteSetup_getRouter @@ -1560,85 +1600,6 @@ test_RouteSetup_getRequestMethod | src/routesetups.js:12:1:12:16 | root.post('', h) | POST | | src/subrouter.js:9:3:9:35 | router. ... ndler1) | POST | | src/subrouter.js:10:3:10:41 | router. ... ndler2) | POST | -test_RouteExpr -| src/advanced-routehandler-registration.js:10:3:10:24 | app.get ... es0[p]) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:19:3:19:18 | app.use(handler) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:28:3:28:24 | app.get ... es2[p]) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:37:3:37:12 | app.use(h) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:51:1:51:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:64:1:64:54 | app.use ... , res)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:73:1:73:56 | app.use ... , res)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:92:1:92:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:111:1:111:61 | app.use ... ever")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:116:3:116:31 | app.get ... tes[p]) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:118:1:118:30 | app.get ... utes.a) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:119:1:119:30 | app.get ... utes.b) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:125:29:125:41 | app.get(k, v) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:126:1:126:32 | app.get ... t("a")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:127:1:127:32 | app.get ... t("b")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:135:2:135:53 | app.get ... andler) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:139:1:139:58 | app.get ... andler) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:144:1:144:32 | app.use ... , args) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:147:1:147:37 | app.use ... (data)) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:150:2:150:14 | app.get(k, v) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:153:1:153:41 | app.get ... KEY!")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:160:1:160:33 | app.get ... t("c")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:161:1:161:39 | app.get ... own())) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:162:1:162:23 | app.get ... nown()) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/advanced-routehandler-registration.js:163:1:163:33 | app.get ... t("f")) | src/advanced-routehandler-registration.js:2:11:2:19 | express() | -| src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:1:13:1:32 | require('express')() | -| src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:7:11:7:19 | express() | -| src/csurf-example.js:16:1:16:51 | app.use ... lse })) | src/csurf-example.js:7:11:7:19 | express() | -| src/csurf-example.js:17:1:17:23 | app.use ... rser()) | src/csurf-example.js:7:11:7:19 | express() | -| src/csurf-example.js:18:1:18:31 | app.use ... rue })) | src/csurf-example.js:7:11:7:19 | express() | -| src/csurf-example.js:20:1:23:2 | app.get ... ) })\\n}) | src/csurf-example.js:7:11:7:19 | express() | -| src/csurf-example.js:25:1:27:2 | app.pos ... re')\\n}) | src/csurf-example.js:7:11:7:19 | express() | -| src/csurf-example.js:32:3:34:4 | router. ... ')\\n }) | src/csurf-example.js:30:16:30:35 | new express.Router() | -| src/csurf-example.js:39:1:39:48 | app.get ... es) {}) | src/csurf-example.js:7:11:7:19 | express() | -| src/csurf-example.js:40:1:40:49 | app.pos ... es) {}) | src/csurf-example.js:7:11:7:19 | express() | -| src/express2.js:2:14:2:23 | e.Router() | src/express2.js:2:14:2:23 | e.Router() | -| src/express2.js:3:1:3:56 | router. ... res }) | src/express2.js:2:14:2:23 | e.Router() | -| src/express2.js:3:1:4:77 | router. ... sult }) | src/express2.js:2:14:2:23 | e.Router() | -| src/express2.js:6:1:6:15 | app.use(router) | src/express2.js:5:11:5:13 | e() | -| src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:2:11:2:19 | express() | -| src/express3.js:12:1:12:21 | app.use ... dler()) | src/express3.js:2:11:2:19 | express() | -| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:2:11:2:19 | express() | -| src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() | -| src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:2:11:2:19 | express() | -| src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() | -| src/express.js:34:1:34:53 | app.get ... andler) | src/express.js:2:11:2:19 | express() | -| src/express.js:39:1:39:21 | app.use ... dler()) | src/express.js:2:11:2:19 | express() | -| src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:2:11:2:19 | express() | -| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() | -| src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() | -| src/middleware-flow.js:13:5:13:25 | router. ... tallDb) | src/middleware-flow.js:2:13:2:21 | express() | -| src/middleware-flow.js:17:5:21:6 | router. ... \\n }) | src/middleware-flow.js:2:13:2:21 | express() | -| src/middleware-flow.js:27:9:27:33 | router. ... ers[p]) | src/middleware-flow.js:2:13:2:21 | express() | -| src/middleware-flow.js:39:1:43:2 | unrelat ... .db;\\n}) | src/middleware-flow.js:37:22:37:30 | express() | -| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() | -| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:4:1:12:2 | app.par ... }\\n}) | -| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() | -| src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() | -| src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() | -| src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() | -| src/responseExprs.js:13:1:15:2 | app.get ... es4;\\n}) | src/responseExprs.js:2:11:2:19 | express() | -| src/responseExprs.js:16:1:42:2 | app.pos ... }\\n}) | src/responseExprs.js:2:11:2:19 | express() | -| src/route.js:2:14:2:29 | express.Router() | src/route.js:2:14:2:29 | express.Router() | -| src/route.js:4:1:4:31 | router. ... er_id') | src/route.js:2:14:2:29 | express.Router() | -| src/route.js:4:1:5:39 | router. ... xt) {}) | src/route.js:2:14:2:29 | express.Router() | -| src/routesetups.js:3:1:3:16 | express.Router() | src/routesetups.js:3:1:3:16 | express.Router() | -| src/routesetups.js:3:1:4:14 | express ... ('', h) | src/routesetups.js:3:1:3:16 | express.Router() | -| src/routesetups.js:3:1:5:12 | express ... ('', h) | src/routesetups.js:3:1:3:16 | express.Router() | -| src/routesetups.js:7:11:7:32 | express ... erver() | src/routesetups.js:7:11:7:32 | express ... erver() | -| src/routesetups.js:8:1:8:12 | app.error(h) | src/routesetups.js:7:11:7:32 | express ... erver() | -| src/routesetups.js:10:14:10:29 | express.Router() | src/routesetups.js:10:14:10:29 | express.Router() | -| src/routesetups.js:11:12:11:28 | router.route('/') | src/routesetups.js:10:14:10:29 | express.Router() | -| src/routesetups.js:12:1:12:16 | root.post('', h) | src/routesetups.js:10:14:10:29 | express.Router() | -| src/subrouter.js:4:1:4:26 | app.use ... rotect) | src/subrouter.js:2:11:2:19 | express() | -| src/subrouter.js:5:1:5:29 | app.use ... uter()) | src/subrouter.js:2:11:2:19 | express() | -| src/subrouter.js:8:16:8:31 | express.Router() | src/subrouter.js:8:16:8:31 | express.Router() | -| src/subrouter.js:9:3:9:35 | router. ... ndler1) | src/subrouter.js:8:16:8:31 | express.Router() | -| src/subrouter.js:10:3:10:41 | router. ... ndler2) | src/subrouter.js:8:16:8:31 | express.Router() | test_RouteHandler_getAResponseExpr | src/advanced-routehandler-registration.js:6:6:6:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:6:12:6:14 | res | | src/advanced-routehandler-registration.js:7:6:7:35 | (req, r ... og(req) | src/advanced-routehandler-registration.js:7:12:7:14 | res | @@ -1840,25 +1801,35 @@ test_isResponse | src/advanced-routehandler-registration.js:24:12:24:14 | res | | src/advanced-routehandler-registration.js:25:12:25:14 | res | | src/advanced-routehandler-registration.js:46:25:46:27 | res | +| src/advanced-routehandler-registration.js:46:25:46:27 | res | | src/advanced-routehandler-registration.js:47:32:47:34 | res | | src/advanced-routehandler-registration.js:51:15:51:17 | res | +| src/advanced-routehandler-registration.js:51:15:51:17 | res | | src/advanced-routehandler-registration.js:51:45:51:47 | res | | src/advanced-routehandler-registration.js:59:25:59:27 | res | +| src/advanced-routehandler-registration.js:59:25:59:27 | res | | src/advanced-routehandler-registration.js:60:23:60:25 | res | | src/advanced-routehandler-registration.js:64:15:64:17 | res | +| src/advanced-routehandler-registration.js:64:15:64:17 | res | | src/advanced-routehandler-registration.js:64:50:64:52 | res | | src/advanced-routehandler-registration.js:68:18:68:20 | res | | src/advanced-routehandler-registration.js:69:25:69:27 | res | +| src/advanced-routehandler-registration.js:69:25:69:27 | res | | src/advanced-routehandler-registration.js:70:23:70:25 | res | | src/advanced-routehandler-registration.js:73:15:73:17 | res | +| src/advanced-routehandler-registration.js:73:15:73:17 | res | | src/advanced-routehandler-registration.js:73:52:73:54 | res | | src/advanced-routehandler-registration.js:81:25:81:27 | res | +| src/advanced-routehandler-registration.js:81:25:81:27 | res | | src/advanced-routehandler-registration.js:82:32:82:34 | res | | src/advanced-routehandler-registration.js:92:15:92:17 | res | +| src/advanced-routehandler-registration.js:92:15:92:17 | res | | src/advanced-routehandler-registration.js:92:45:92:47 | res | | src/advanced-routehandler-registration.js:100:25:100:27 | res | +| src/advanced-routehandler-registration.js:100:25:100:27 | res | | src/advanced-routehandler-registration.js:101:36:101:38 | res | | src/advanced-routehandler-registration.js:111:15:111:17 | res | +| src/advanced-routehandler-registration.js:111:15:111:17 | res | | src/advanced-routehandler-registration.js:111:45:111:47 | res | | src/advanced-routehandler-registration.js:123:26:123:28 | res | | src/advanced-routehandler-registration.js:124:26:124:28 | res | @@ -1867,32 +1838,40 @@ test_isResponse | src/advanced-routehandler-registration.js:157:33:157:35 | res | | src/controllers/handler-in-bulk-require.js:1:50:1:52 | res | | src/csurf-example.js:20:33:20:35 | res | +| src/csurf-example.js:20:33:20:35 | res | | src/csurf-example.js:22:3:22:5 | res | | src/csurf-example.js:25:37:25:39 | res | +| src/csurf-example.js:25:37:25:39 | res | | src/csurf-example.js:26:3:26:5 | res | | src/csurf-example.js:26:3:26:43 | res.sen ... here') | | src/csurf-example.js:32:45:32:47 | res | +| src/csurf-example.js:32:45:32:47 | res | | src/csurf-example.js:33:5:33:7 | res | | src/csurf-example.js:33:5:33:35 | res.sen ... here') | | src/csurf-example.js:39:41:39:43 | res | | src/csurf-example.js:40:42:40:44 | res | | src/exportedHandler.js:1:49:1:51 | res | | src/express2.js:3:39:3:41 | res | +| src/express2.js:3:39:3:41 | res | | src/express2.js:3:46:3:53 | req, res | | src/express2.js:3:51:3:53 | res | | src/express2.js:4:50:4:55 | result | +| src/express2.js:4:50:4:55 | result | | src/express2.js:4:60:4:74 | request, result | | src/express2.js:4:69:4:74 | result | | src/express3.js:4:37:4:39 | res | +| src/express3.js:4:37:4:39 | res | | src/express3.js:5:3:5:5 | res | | src/express3.js:5:3:5:51 | res.hea ... "val")) | | src/express3.js:6:3:6:5 | res | | src/express3.js:6:3:6:17 | res.send("val") | | src/express3.js:10:27:10:29 | res | | src/express4.js:4:37:4:39 | res | +| src/express4.js:4:37:4:39 | res | | src/express4.js:8:3:8:5 | res | | src/express4.js:8:3:8:20 | res.send(dynamic1) | | src/express.js:4:37:4:39 | res | +| src/express.js:4:37:4:39 | res | | src/express.js:5:3:5:5 | res | | src/express.js:6:3:6:5 | res | | src/express.js:6:3:6:45 | res.hea ... rget")) | @@ -1900,18 +1879,22 @@ test_isResponse | src/express.js:7:3:7:42 | res.hea ... plain") | | src/express.js:8:7:8:9 | res | | src/express.js:11:14:11:16 | arg | +| src/express.js:11:14:11:16 | arg | | src/express.js:12:3:12:5 | arg | | src/express.js:12:3:12:54 | arg.hea ... , true) | | src/express.js:16:33:16:35 | res | +| src/express.js:16:33:16:35 | res | | src/express.js:17:5:17:7 | res | | src/express.js:17:5:17:24 | res.send("Go away.") | | src/express.js:22:44:22:46 | res | +| src/express.js:22:44:22:46 | res | | src/express.js:31:3:31:5 | res | | src/express.js:31:3:31:26 | res.coo ... 'bar') | | src/express.js:37:27:37:29 | res | | src/express.js:42:18:42:20 | res | | src/express.js:46:36:46:38 | res | | src/inheritedFromNode.js:4:29:4:31 | res | +| src/inheritedFromNode.js:4:29:4:31 | res | | src/inheritedFromNode.js:5:2:5:4 | res | | src/inheritedFromNode.js:6:2:6:4 | res | | src/middleware-flow.js:5:25:5:27 | res | @@ -1920,20 +1903,27 @@ test_isResponse | src/middleware-flow.js:24:23:24:25 | res | | src/middleware-flow.js:39:29:39:31 | res | | src/params.js:4:24:4:26 | res | +| src/params.js:4:24:4:26 | res | | src/params.js:8:9:8:11 | res | | src/params.js:8:9:8:23 | res.send(value) | | src/params.js:14:38:14:40 | res | +| src/params.js:14:38:14:40 | res | | src/params.js:15:3:15:5 | res | | src/params.js:15:3:15:19 | res.send("Hello") | | src/responseExprs.js:4:37:4:40 | res1 | +| src/responseExprs.js:4:37:4:40 | res1 | | src/responseExprs.js:5:5:5:8 | res1 | | src/responseExprs.js:7:37:7:40 | res2 | +| src/responseExprs.js:7:37:7:40 | res2 | | src/responseExprs.js:8:5:8:8 | res2 | | src/responseExprs.js:10:44:10:47 | res3 | +| src/responseExprs.js:10:44:10:47 | res3 | | src/responseExprs.js:11:5:11:8 | res3 | | src/responseExprs.js:13:37:13:40 | res4 | +| src/responseExprs.js:13:37:13:40 | res4 | | src/responseExprs.js:14:5:14:8 | res4 | | src/responseExprs.js:16:44:16:46 | res | +| src/responseExprs.js:16:44:16:46 | res | | src/responseExprs.js:19:5:19:7 | res | | src/responseExprs.js:19:5:19:16 | res.append() | | src/responseExprs.js:20:5:20:7 | res | @@ -1971,6 +1961,8 @@ test_isResponse | src/responseExprs.js:37:5:37:28 | f(res.a ... ppend() | | src/responseExprs.js:37:7:37:9 | res | | src/responseExprs.js:37:7:37:18 | res.append() | +| src/responseExprs.js:39:5:41:5 | return of function f | +| src/responseExprs.js:39:16:39:21 | resArg | | src/responseExprs.js:39:16:39:21 | resArg | | src/responseExprs.js:40:16:40:21 | resArg | | src/responseExprs.js:40:16:40:30 | resArg.append() | From 136124fbaa6a7b28d328301b045c775c42b89795 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 19:48:23 +0200 Subject: [PATCH 18/39] convert the remaining Koa models to DataFlow nodes --- .../lib/semmle/javascript/frameworks/Koa.qll | 110 +++++++++++------- .../javascript/frameworks/NodeJSLib.qll | 7 +- .../CleartextStorageCustomizations.qll | 4 +- .../ClientSideUrlRedirectCustomizations.qll | 4 +- .../javascript/security/dataflow/DOM.qll | 7 +- .../frameworks/NodeJSLib/isCreateServer.qll | 2 +- .../frameworks/koa/ContextExpr.qll | 2 +- .../koa/RouteHandler_getAContextExpr.qll | 4 +- .../frameworks/koa/tests.expected | 12 ++ 9 files changed, 97 insertions(+), 55 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll index e45dfd90127e..801ed7fc9e80 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll @@ -24,7 +24,7 @@ module Koa { HeaderDefinition() { // ctx.set('Cache-Control', 'no-cache'); - this.calls(rh.getAResponseOrContextExpr().flow(), "set") + this.calls(rh.getAResponseOrContextNode(), "set") or // ctx.response.header('Cache-Control', 'no-cache') this.calls(rh.getAResponseNode(), "header") @@ -40,10 +40,17 @@ module Koa { /** * Gets the parameter of the route handler that contains the context object. */ - Parameter getContextParameter() { - result = this.getAFunctionValue().getFunction().getParameter(0) + DataFlow::ParameterNode getContextParameter() { + result = this.getAFunctionValue().getParameter(0) } + /** + * DEPRECATED: Use `getAContextNode` instead. + * Gets an expression that contains the "context" object of + * a route handler invocation. + */ + deprecated Expr getAContextExpr() { result.(ContextExpr).getRouteHandler() = this } + /** * Gets an expression that contains the "context" object of * a route handler invocation. @@ -52,26 +59,42 @@ module Koa { * `this` or `ctx`, given as the first and only argument to the * route handler. */ - Expr getAContextExpr() { result.(ContextExpr).getRouteHandler() = this } + DataFlow::Node getAContextNode() { result.(ContextNode).getRouteHandler() = this } /** + * DEPRECATED: Use `getAResponseOrContextNode` instead. * Gets an expression that contains the context or response * object of a route handler invocation. */ - Expr getAResponseOrContextExpr() { - // TODO: DataFlow::Node + deprecated Expr getAResponseOrContextExpr() { result = this.getAResponseNode().asExpr() or result = this.getAContextExpr() } /** + * Gets an expression that contains the context or response + * object of a route handler invocation. + */ + DataFlow::Node getAResponseOrContextNode() { + result = this.getAResponseNode() or result = this.getAContextNode() + } + + /** + * DEPRECATED: Use `getARequestOrContextNode` instead. * Gets an expression that contains the context or request * object of a route handler invocation. */ - Expr getARequestOrContextExpr() { - // TODO: DataFlow::Node + deprecated Expr getARequestOrContextExpr() { result = this.getARequestNode().asExpr() or result = this.getAContextExpr() } + /** + * Gets an expression that contains the context or request + * object of a route handler invocation. + */ + DataFlow::Node getARequestOrContextNode() { + result = this.getARequestNode() or result = this.getAContextNode() + } + /** * Gets a reference to a request parameter defined by this route handler. */ @@ -110,7 +133,7 @@ module Koa { RouteHandler rh; ContextSource() { - this = DataFlow::parameterNode(rh.getContextParameter()) + this = rh.getContextParameter() or this.(DataFlow::ThisNode).getBinder() = rh } @@ -206,10 +229,10 @@ module Koa { * A Koa request source, that is, an access to the `request` property * of a context object. */ - private class RequestSource extends HTTP::Servers::RequestSource { - ContextExpr ctx; + private class RequestSource extends HTTP::Servers::RequestSource instanceof DataFlow::PropRead { + ContextNode ctx; - RequestSource() { this.asExpr().(PropAccess).accesses(ctx, "request") } + RequestSource() { super.accesses(ctx, "request") } /** * Gets the route handler that provides this response. @@ -241,10 +264,10 @@ module Koa { * A Koa response source, that is, an access to the `response` property * of a context object. */ - private class ResponseSource extends HTTP::Servers::ResponseSource { - ContextExpr ctx; + private class ResponseSource extends HTTP::Servers::ResponseSource instanceof DataFlow::PropRead { + ContextNode ctx; - ResponseSource() { this.asExpr().(PropAccess).accesses(ctx, "response") } + ResponseSource() { super.accesses(ctx, "response") } /** * Gets the route handler that provides this response. @@ -252,13 +275,26 @@ module Koa { override RouteHandler getRouteHandler() { result = ctx.getRouteHandler() } } + /** + * DEPRECATED: Use `ContextNode` instead. + * An expression that may hold a Koa context object. + */ + deprecated class ContextExpr extends Expr { + ContextNode node; + + ContextExpr() { node.asExpr() = this } + + /** Gets the route handler that provides this response. */ + deprecated RouteHandler getRouteHandler() { result = node.getRouteHandler() } + } + /** * An expression that may hold a Koa context object. */ - class ContextExpr extends Expr { + class ContextNode extends DataFlow::Node { ContextSource src; - ContextExpr() { src.ref().flowsTo(DataFlow::valueNode(this)) } + ContextNode() { src.ref().flowsTo(this) } /** * Gets the route handler that provides this response. @@ -310,11 +346,11 @@ module Koa { kind = "parameter" and this = rh.getARequestParameterAccess() or - exists(Expr e | rh.getARequestOrContextExpr() = e | + exists(DataFlow::Node e | rh.getARequestOrContextNode() = e | // `ctx.request.url`, `ctx.request.originalUrl`, or `ctx.request.href` exists(string propName | kind = "url" and - this.asExpr().(PropAccess).accesses(e, propName) + this.(DataFlow::PropRead).accesses(e, propName) | propName = "url" or @@ -325,19 +361,19 @@ module Koa { or // params, when handler is registered by `koa-router` or similar. kind = "parameter" and - this.asExpr().(PropAccess).accesses(e, "params") + this.(DataFlow::PropRead).accesses(e, "params") or // `ctx.request.body` - e.flow() instanceof RequestNode and + e instanceof RequestNode and kind = "body" and - this.asExpr().(PropAccess).accesses(e, "body") + this.(DataFlow::PropRead).accesses(e, "body") or // `ctx.cookies.get()` - exists(PropAccess cookies | - e instanceof ContextExpr and + exists(DataFlow::PropRead cookies | + e instanceof ContextNode and kind = "cookie" and cookies.accesses(e, "cookies") and - this = cookies.flow().(DataFlow::SourceNode).getAMethodCall("get") + this = cookies.getAMethodCall("get") ) or exists(RequestHeaderAccess access | access = this | @@ -356,9 +392,9 @@ module Koa { private DataFlow::Node getAQueryParameterAccess(RouteHandler rh) { // `ctx.query.name` or `ctx.request.query.name` - exists(PropAccess q | - q.accesses(rh.getARequestOrContextExpr(), "query") and - result = q.flow().(DataFlow::SourceNode).getAPropertyRead() + exists(DataFlow::PropRead q | + q.accesses(rh.getARequestOrContextNode(), "query") and + result = q.getAPropertyRead() ) } @@ -369,18 +405,18 @@ module Koa { RouteHandler rh; RequestHeaderAccess() { - exists(Expr e | e = rh.getARequestOrContextExpr() | - exists(string propName, PropAccess headers | + exists(DataFlow::Node e | e = rh.getARequestOrContextNode() | + exists(string propName, DataFlow::PropRead headers | // `ctx.request.header.`, `ctx.request.headers.` headers.accesses(e, propName) and - this = headers.flow().(DataFlow::SourceNode).getAPropertyRead() + this = headers.getAPropertyRead() | propName = "header" or propName = "headers" ) or // `ctx.request.get()` - this.asExpr().(MethodCallExpr).calls(e, "get") + this.(DataFlow::MethodCallNode).calls(e, "get") ) } @@ -427,9 +463,7 @@ module Koa { RouteHandler rh; ResponseSendArgument() { - exists(DataFlow::PropWrite pwn | - pwn.writes(DataFlow::valueNode(rh.getAResponseOrContextExpr()), "body", this) - ) + exists(DataFlow::PropWrite pwn | pwn.writes(rh.getAResponseOrContextNode(), "body", this)) } override RouteHandler getRouteHandler() { result = rh } @@ -438,12 +472,10 @@ module Koa { /** * An invocation of the `redirect` method of an HTTP response object. */ - private class RedirectInvocation extends HTTP::RedirectInvocation, DataFlow::MethodCallNode { + private class RedirectInvocation extends HTTP::RedirectInvocation instanceof DataFlow::MethodCallNode { RouteHandler rh; - RedirectInvocation() { - this.asExpr().(MethodCallExpr).calls(rh.getAResponseOrContextExpr(), "redirect") - } // TODO: Improve this. + RedirectInvocation() { super.calls(rh.getAResponseOrContextNode(), "redirect") } override DataFlow::Node getUrlArgument() { result = this.getArgument(0) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll index 0abc70760187..f9cfe8552458 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll @@ -49,8 +49,7 @@ module NodeJSLib { /** * Holds if `call` is an invocation of `http.createServer` or `https.createServer`. */ - predicate isCreateServer(CallExpr call) { - // TODO: DataFlow::Node + predicate isCreateServer(DataFlow::CallNode call) { exists(string pkg, string fn | pkg = "http" and fn = "createServer" or @@ -61,7 +60,7 @@ module NodeJSLib { or pkg = "http2" and fn = "createSecureServer" | - call = DataFlow::moduleMember(pkg, fn).getAnInvocation().asExpr() + call = DataFlow::moduleMember(pkg, fn).getAnInvocation() ) } @@ -423,7 +422,7 @@ module NodeJSLib { * An expression that creates a new Node.js server. */ class ServerDefinition extends HTTP::Servers::StandardServerDefinition { - ServerDefinition() { isCreateServer(this.asExpr()) } + ServerDefinition() { isCreateServer(this) } } /** An expression that is passed as `http.request({ auth: }, ...)`. */ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll index 95114e8c4b73..1e5c5d712c48 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll @@ -61,9 +61,7 @@ module CleartextStorage { /** * An expression set as a value of localStorage or sessionStorage. */ - class WebStorageSink extends Sink { - WebStorageSink() { this.asExpr() instanceof WebStorageWrite } - } + class WebStorageSink extends Sink instanceof WebStorageWrite { } /** * An expression stored by AngularJS. diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll index 6549f40ebdd2..a20d50c10d5a 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll @@ -104,7 +104,9 @@ module ClientSideUrlRedirect { xss = true or // An assignment to `location` - exists(Assignment assgn | isLocation(assgn.getTarget()) and astNode = assgn.getRhs()) and + exists(Assignment assgn | + isLocationNode(assgn.getTarget().flow()) and astNode = assgn.getRhs() + ) and xss = true or // An assignment to `location.href`, `location.protocol` or `location.hostname` diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll index 58728d5f9e60..5eaf8b427207 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll @@ -143,18 +143,17 @@ class DomPropWriteNode extends Assignment { /** * A value written to web storage, like `localStorage` or `sessionStorage`. */ -class WebStorageWrite extends Expr { - // TODO: DataFlow::Node +class WebStorageWrite extends DataFlow::Node { WebStorageWrite() { exists(DataFlow::SourceNode webStorage | webStorage = DataFlow::globalVarRef("localStorage") or webStorage = DataFlow::globalVarRef("sessionStorage") | // an assignment to `window.localStorage[someProp]` - this = webStorage.getAPropertyWrite().getRhs().asExpr() + this = webStorage.getAPropertyWrite().getRhs() or // an invocation of `window.localStorage.setItem` - this = webStorage.getAMethodCall("setItem").getArgument(1).asExpr() + this = webStorage.getAMethodCall("setItem").getArgument(1) ) } } diff --git a/javascript/ql/test/library-tests/frameworks/NodeJSLib/isCreateServer.qll b/javascript/ql/test/library-tests/frameworks/NodeJSLib/isCreateServer.qll index 86bcb37b728c..aacfe28ae28b 100644 --- a/javascript/ql/test/library-tests/frameworks/NodeJSLib/isCreateServer.qll +++ b/javascript/ql/test/library-tests/frameworks/NodeJSLib/isCreateServer.qll @@ -1,3 +1,3 @@ import javascript -query predicate test_isCreateServer(CallExpr e) { NodeJSLib::isCreateServer(e) } +query predicate test_isCreateServer(DataFlow::CallNode e) { NodeJSLib::isCreateServer(e) } diff --git a/javascript/ql/test/library-tests/frameworks/koa/ContextExpr.qll b/javascript/ql/test/library-tests/frameworks/koa/ContextExpr.qll index d33c4e12229c..c1218e2aabe7 100644 --- a/javascript/ql/test/library-tests/frameworks/koa/ContextExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/koa/ContextExpr.qll @@ -1,5 +1,5 @@ import javascript -query predicate test_ContextExpr(Koa::ContextExpr e, Koa::RouteHandler res) { +query predicate test_ContextExpr(Koa::ContextNode e, Koa::RouteHandler res) { res = e.getRouteHandler() } diff --git a/javascript/ql/test/library-tests/frameworks/koa/RouteHandler_getAContextExpr.qll b/javascript/ql/test/library-tests/frameworks/koa/RouteHandler_getAContextExpr.qll index cbbe41ebb857..c5049096d5ae 100644 --- a/javascript/ql/test/library-tests/frameworks/koa/RouteHandler_getAContextExpr.qll +++ b/javascript/ql/test/library-tests/frameworks/koa/RouteHandler_getAContextExpr.qll @@ -1,5 +1,5 @@ import semmle.javascript.frameworks.Express -query predicate test_RouteHandler_getAContextExpr(Koa::RouteHandler rh, Expr res) { - res = rh.getAContextExpr() +query predicate test_RouteHandler_getAContextExpr(Koa::RouteHandler rh, DataFlow::Node res) { + res = rh.getAContextNode() } diff --git a/javascript/ql/test/library-tests/frameworks/koa/tests.expected b/javascript/ql/test/library-tests/frameworks/koa/tests.expected index 9e983ccca926..042fc7227c29 100644 --- a/javascript/ql/test/library-tests/frameworks/koa/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/koa/tests.expected @@ -47,6 +47,9 @@ test_ResponseExpr | src/koa.js:18:3:18:14 | ctx.response | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:44:2:44:13 | ctx.response | src/koa.js:30:10:45:1 | async c ... url);\\n} | test_RouteHandler_getAContextExpr +| src/koa.js:7:1:7:22 | functio ... r1() {} | src/koa.js:7:1:7:0 | this | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:10:10:10:9 | this | +| src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:10:28:10:30 | ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:10:28:10:30 | ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:11:3:11:6 | this | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:12:3:12:6 | this | @@ -64,6 +67,7 @@ test_RouteHandler_getAContextExpr | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:26:3:26:5 | ctx | | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:27:3:27:5 | ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:30:16:30:18 | ctx | +| src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:30:16:30:18 | ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:31:2:31:4 | ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:32:2:32:4 | ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:33:2:33:4 | ctx | @@ -78,9 +82,11 @@ test_RouteHandler_getAContextExpr | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:43:2:43:4 | ctx | | src/koa.js:30:10:45:1 | async c ... url);\\n} | src/koa.js:44:2:44:4 | ctx | | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:47:16:47:18 | ctx | +| src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:47:16:47:18 | ctx | | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:48:16:48:18 | ctx | | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:51:14:51:16 | ctx | | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | src/koa.js:54:16:54:18 | ctx | +| src/koa.js:59:10:61:1 | functio ... .url;\\n} | src/koa.js:59:10:59:9 | this | | src/koa.js:59:10:61:1 | functio ... .url;\\n} | src/koa.js:60:2:60:5 | this | test_HeaderDefinition | src/koa.js:11:3:11:25 | this.se ... 1', '') | src/koa.js:10:10:28:1 | functio ... az');\\n} | @@ -157,6 +163,9 @@ test_RouteHandler_getARequestExpr | src/koa.js:10:10:28:1 | functio ... az');\\n} | src/koa.js:26:3:26:13 | ctx.request | | src/koa.js:59:10:61:1 | functio ... .url;\\n} | src/koa.js:60:2:60:13 | this.request | test_ContextExpr +| src/koa.js:7:1:7:0 | this | src/koa.js:7:1:7:22 | functio ... r1() {} | +| src/koa.js:10:10:10:9 | this | src/koa.js:10:10:28:1 | functio ... az');\\n} | +| src/koa.js:10:28:10:30 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:10:28:10:30 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:11:3:11:6 | this | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:12:3:12:6 | this | src/koa.js:10:10:28:1 | functio ... az');\\n} | @@ -174,6 +183,7 @@ test_ContextExpr | src/koa.js:26:3:26:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:27:3:27:5 | ctx | src/koa.js:10:10:28:1 | functio ... az');\\n} | | src/koa.js:30:16:30:18 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | +| src/koa.js:30:16:30:18 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:31:2:31:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:32:2:32:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:33:2:33:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | @@ -188,9 +198,11 @@ test_ContextExpr | src/koa.js:43:2:43:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:44:2:44:4 | ctx | src/koa.js:30:10:45:1 | async c ... url);\\n} | | src/koa.js:47:16:47:18 | ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | +| src/koa.js:47:16:47:18 | ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | | src/koa.js:48:16:48:18 | ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | | src/koa.js:51:14:51:16 | ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | | src/koa.js:54:16:54:18 | ctx | src/koa.js:47:10:56:1 | async c ... .foo;\\n} | +| src/koa.js:59:10:59:9 | this | src/koa.js:59:10:61:1 | functio ... .url;\\n} | | src/koa.js:60:2:60:5 | this | src/koa.js:59:10:61:1 | functio ... .url;\\n} | test_RedirectInvocation | src/koa.js:43:2:43:18 | ctx.redirect(url) | src/koa.js:43:15:43:17 | url | src/koa.js:30:10:45:1 | async c ... url);\\n} | From 2f429e7d294543cd9df8db65aaf8818502d7c112 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 20:19:42 +0200 Subject: [PATCH 19/39] convert some leftovers to use dataflow nodes --- .../semmle/javascript/frameworks/Express.qll | 8 +++----- .../lib/semmle/javascript/frameworks/Hapi.qll | 17 ++++++----------- .../ql/lib/semmle/javascript/frameworks/Koa.qll | 10 ++++------ .../frameworks/Express/RouteExpr.qll | 5 ----- .../library-tests/frameworks/Express/tests.ql | 1 - 5 files changed, 13 insertions(+), 28 deletions(-) delete mode 100644 javascript/ql/test/library-tests/frameworks/Express/RouteExpr.qll diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 26e4bc20002b..754d528159e5 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -56,13 +56,11 @@ module Express { } /** + * DEPRECATED: Use `isRouter()` instead. * An expression that refers to a route. */ - class RouteExpr extends DataFlow::MethodCallNode { - RouteExpr() { isRouter(this) } - - /** Gets the router from which this route was created, if it is known. */ - RouterDefinition getRouter() { isRouter(this, result) } + deprecated class RouteExpr extends MethodCallExpr { + RouteExpr() { isRouter(this.flow()) } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll index 860538735492..b66ab8d484fa 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll @@ -19,29 +19,24 @@ module Hapi { /** * A Hapi route handler. */ - class RouteHandler extends HTTP::Servers::StandardRouteHandler, DataFlow::ValueNode { - Function function; - - RouteHandler() { - function = astNode and - exists(RouteSetup setup | this = setup.getARouteHandler()) - } + class RouteHandler extends HTTP::Servers::StandardRouteHandler, DataFlow::FunctionNode { + RouteHandler() { exists(RouteSetup setup | this = setup.getARouteHandler()) } /** * Gets the parameter of the route handler that contains the request object. */ - Parameter getRequestParameter() { result = function.getParameter(0) } + DataFlow::ParameterNode getRequestParameter() { result = getParameter(0) } /** * Gets the parameter of the route handler that contains the "request toolkit", * usually named `h`. */ - Parameter getRequestToolkitParameter() { result = function.getParameter(1) } + DataFlow::ParameterNode getRequestToolkitParameter() { result = getParameter(1) } /** * Gets a source node referring to the request toolkit parameter, usually named `h`. */ - DataFlow::SourceNode getRequestToolkit() { result = getRequestToolkitParameter().flow() } + DataFlow::SourceNode getRequestToolkit() { result = getRequestToolkitParameter() } } /** @@ -66,7 +61,7 @@ module Hapi { private class RequestSource extends HTTP::Servers::RequestSource { RouteHandler rh; - RequestSource() { this = DataFlow::parameterNode(rh.getRequestParameter()) } + RequestSource() { this = rh.getRequestParameter() } /** * Gets the route handler that handles this request. diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll index 801ed7fc9e80..49104de92633 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Koa.qll @@ -49,7 +49,7 @@ module Koa { * Gets an expression that contains the "context" object of * a route handler invocation. */ - deprecated Expr getAContextExpr() { result.(ContextExpr).getRouteHandler() = this } + deprecated Expr getAContextExpr() { result = this.getAContextNode().asExpr() } /** * Gets an expression that contains the "context" object of @@ -67,7 +67,7 @@ module Koa { * object of a route handler invocation. */ deprecated Expr getAResponseOrContextExpr() { - result = this.getAResponseNode().asExpr() or result = this.getAContextExpr() + result = this.getAResponseOrContextNode().asExpr() } /** @@ -83,9 +83,7 @@ module Koa { * Gets an expression that contains the context or request * object of a route handler invocation. */ - deprecated Expr getARequestOrContextExpr() { - result = this.getARequestNode().asExpr() or result = this.getAContextExpr() - } + deprecated Expr getARequestOrContextExpr() { result = this.getARequestOrContextNode().asExpr() } /** * Gets an expression that contains the context or request @@ -447,7 +445,7 @@ module Koa { override DataFlow::SourceNode getARouteHandler() { // `StandardRouteHandler` uses this predicate in it's charpred, so making this predicate return a `RouteHandler` would give an empty recursion. - result.flowsToExpr(this.getArgument(0).asExpr()) + result.flowsTo(this.getArgument(0)) or // For the route-handlers that does not depend on this predicate in their charpred. result.(RouteHandler).getARouteHandlerRegistrationObject().flowsTo(this.getArgument(0)) diff --git a/javascript/ql/test/library-tests/frameworks/Express/RouteExpr.qll b/javascript/ql/test/library-tests/frameworks/Express/RouteExpr.qll deleted file mode 100644 index bc8010494fd3..000000000000 --- a/javascript/ql/test/library-tests/frameworks/Express/RouteExpr.qll +++ /dev/null @@ -1,5 +0,0 @@ -import javascript - -query predicate test_RouteExpr(Express::RouteExpr e, Express::RouterDefinition res) { - res = e.getRouter() -} diff --git a/javascript/ql/test/library-tests/frameworks/Express/tests.ql b/javascript/ql/test/library-tests/frameworks/Express/tests.ql index ec76c73df27b..d708732267af 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/tests.ql +++ b/javascript/ql/test/library-tests/frameworks/Express/tests.ql @@ -27,7 +27,6 @@ import RouterDefinition_getASubRouter import HeaderDefinition_getNameExpr import appCreation import RouteSetup_getRequestMethod -import RouteExpr import RouteHandler_getAResponseExpr import isResponse import ResponseBody From 9bea110d24386bfcfb33007a50398e94512642aa Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 20:33:12 +0200 Subject: [PATCH 20/39] convert the DOM model to use DataFlow nodes --- .../ClientSideUrlRedirectCustomizations.qll | 6 +- .../javascript/security/dataflow/DOM.qll | 115 ++++++++++++++---- .../dataflow/DomBasedXssCustomizations.qll | 8 +- 3 files changed, 100 insertions(+), 29 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll index a20d50c10d5a..513b6cc18f91 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll @@ -179,7 +179,7 @@ module ClientSideUrlRedirect { ) or // e.g. node.setAttribute("href", sink) - any(DomMethodCallExpr call).interpretsArgumentsAsUrl(this.asExpr()) + any(DomMethodCallNode call).interpretsArgumentsAsUrl(this) } override predicate isXssSink() { any() } @@ -191,9 +191,9 @@ module ClientSideUrlRedirect { */ class AttributeWriteUrlSink extends ScriptUrlSink, DataFlow::ValueNode { AttributeWriteUrlSink() { - exists(DomPropWriteNode pw | + exists(DomPropertyWrite pw | pw.interpretsValueAsJavaScriptUrl() and - this = DataFlow::valueNode(pw.getRhs()) + this = pw.getRhs() ) } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll index 5eaf8b427207..1d89668fa7a6 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll @@ -21,14 +21,28 @@ class DomGlobalVariable extends GlobalVariable { /** DEPRECATED: Alias for DomGlobalVariable */ deprecated class DOMGlobalVariable = DomGlobalVariable; -/** Holds if `e` could hold a value that comes from the DOM. */ -predicate isDomValue(Expr e) { DOM::domValueRef().flowsToExpr(e) } +/** + * DEPRECATED: Use `isDomNode` instead. + * Holds if `e` could hold a value that comes from the DOM. + */ +deprecated predicate isDomValue(Expr e) { isDomNode(e.flow()) } + +/** + * Holds if `e` could hold a value that comes from the DOM. + */ +predicate isDomNode(DataFlow::Node e) { DOM::domValueRef().flowsTo(e) } + +/** + * DEPRECATED: Use `isLocationNode` instead. + * Holds if `e` could refer to the `location` property of a DOM node. + */ +deprecated predicate isLocation(Expr e) { isLocationNode(e.flow()) } /** Holds if `e` could refer to the `location` property of a DOM node. */ -predicate isLocation(Expr e) { - e = DOM::domValueRef().getAPropertyReference("location").asExpr() +predicate isLocationNode(DataFlow::Node e) { + e = DOM::domValueRef().getAPropertyReference("location") or - e.accessesGlobal("location") + e = DataFlow::globalVarRef("location") } /** @@ -53,15 +67,52 @@ deprecated predicate isDocumentUrl(Expr e) { e.flow() = DOM::locationSource() } deprecated predicate isDocumentURL = isDocumentUrl/1; /** + * DEPRECATED. In most cases, a sanitizer based on this predicate can be removed, as + * taint tracking no longer step through the properties of the location object by default. + * + * Holds if `pacc` accesses a part of `document.location` that is + * not considered user-controlled, that is, anything except + * `href`, `hash` and `search`. + */ +deprecated predicate isSafeLocationProperty(PropAccess pacc) { + exists(string prop | pacc = DOM::locationRef().getAPropertyRead(prop).asExpr() | + prop != "href" and prop != "hash" and prop != "search" + ) +} + +/** + * DEPRECATED: Use `DomMethodCallNode` instead. * A call to a DOM method. */ -class DomMethodCallExpr extends MethodCallExpr { - DomMethodCallExpr() { isDomValue(this.getReceiver()) } +deprecated class DomMethodCallExpr extends MethodCallExpr { + DomMethodCallNode node; + + DomMethodCallExpr() { this.flow() = node } + + /** Holds if `arg` is an argument that is interpreted as HTML. */ + deprecated predicate interpretsArgumentsAsHtml(Expr arg) { + node.interpretsArgumentsAsHtml(arg.flow()) + } + + /** Holds if `arg` is an argument that is used as an URL. */ + deprecated predicate interpretsArgumentsAsURL(Expr arg) { + node.interpretsArgumentsAsURL(arg.flow()) + } + + /** DEPRECATED: Alias for interpretsArgumentsAsHtml */ + deprecated predicate interpretsArgumentsAsHTML(Expr arg) { this.interpretsArgumentsAsHtml(arg) } +} + +/** + * A call to a DOM method. + */ +class DomMethodCallNode extends DataFlow::MethodCallNode { + DomMethodCallNode() { isDomNode(this.getReceiver()) } /** * Holds if `arg` is an argument that is interpreted as HTML. */ - predicate interpretsArgumentsAsHtml(Expr arg) { + predicate interpretsArgumentsAsHtml(DataFlow::Node arg) { exists(int argPos, string name | arg = this.getArgument(argPos) and name = this.getMethodName() @@ -86,7 +137,7 @@ class DomMethodCallExpr extends MethodCallExpr { /** * Holds if `arg` is an argument that is used as an URL. */ - predicate interpretsArgumentsAsUrl(Expr arg) { + predicate interpretsArgumentsAsUrl(DataFlow::Node arg) { exists(int argPos, string name | arg = this.getArgument(argPos) and name = this.getMethodName() @@ -104,40 +155,60 @@ class DomMethodCallExpr extends MethodCallExpr { } /** DEPRECATED: Alias for interpretsArgumentsAsUrl */ - deprecated predicate interpretsArgumentsAsURL(Expr arg) { this.interpretsArgumentsAsUrl(arg) } + deprecated predicate interpretsArgumentsAsURL(DataFlow::Node arg) { this.interpretsArgumentsAsUrl(arg) } /** DEPRECATED: Alias for interpretsArgumentsAsHtml */ - deprecated predicate interpretsArgumentsAsHTML(Expr arg) { this.interpretsArgumentsAsHtml(arg) } + deprecated predicate interpretsArgumentsAsHTML(DataFlow::Node arg) { this.interpretsArgumentsAsHtml(arg) } } /** + * DEPRECATED: Use `DomPropertyWrite` instead. * An assignment to a property of a DOM object. */ -class DomPropWriteNode extends Assignment { - PropAccess lhs; +deprecated class DomPropWriteNode extends Assignment { + DomPropertyWrite node; - DomPropWriteNode() { - lhs = this.getLhs() and - isDomValue(lhs.getBase()) - } + DomPropWriteNode() { this.flow() = node } /** * Holds if the assigned value is interpreted as HTML. */ - predicate interpretsValueAsHtml() { - lhs.getPropertyName() = "innerHTML" or - lhs.getPropertyName() = "outerHTML" - } + predicate interpretsValueAsHtml() { node.interpretsValueAsHtml() } /** DEPRECATED: Alias for interpretsValueAsHtml */ deprecated predicate interpretsValueAsHTML() { this.interpretsValueAsHtml() } + /** + * Holds if the assigned value is interpreted as JavaScript via javascript: protocol. + */ + predicate interpretsValueAsJavaScriptUrl() { node.interpretsValueAsJavaScriptUrl() } +} + +/** + * An assignment to a property of a DOM object. + */ +class DomPropertyWrite extends DataFlow::Node instanceof DataFlow::PropWrite { + DomPropertyWrite() { isDomNode(super.getBase()) } + + /** + * Holds if the assigned value is interpreted as HTML. + */ + predicate interpretsValueAsHtml() { + super.getPropertyName() = "innerHTML" or + super.getPropertyName() = "outerHTML" + } + /** * Holds if the assigned value is interpreted as JavaScript via javascript: protocol. */ predicate interpretsValueAsJavaScriptUrl() { - lhs.getPropertyName() = DOM::getAPropertyNameInterpretedAsJavaScriptUrl() + super.getPropertyName() = DOM::getAPropertyNameInterpretedAsJavaScriptUrl() } + + /** + * Gets the data flow node corresponding to the value being written, + */ + DataFlow::Node getRhs() { result = super.getRhs() } } /** diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll index b23f52d7c228..9b5179a29059 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll @@ -130,12 +130,12 @@ module DomBasedXss { class DomSink extends Sink { DomSink() { // Call to a DOM function that inserts its argument into the DOM - any(DomMethodCallExpr call).interpretsArgumentsAsHtml(this.asExpr()) + any(DomMethodCallNode call).interpretsArgumentsAsHtml(this) or // Assignment to a dangerous DOM property - exists(DomPropWriteNode pw | + exists(DomPropertyWrite pw | pw.interpretsValueAsHtml() and - this = DataFlow::valueNode(pw.getRhs()) + this = pw.getRhs() ) or // `html` or `source.html` properties of React Native `WebView` @@ -159,7 +159,7 @@ module DomBasedXss { ) or exists(DataFlow::MethodCallNode ccf | - isDomValue(ccf.getReceiver().asExpr()) and + isDomNode(ccf.getReceiver()) and ccf.getMethodName() = "createContextualFragment" and this = ccf.getArgument(0) ) From aa9261f1b1cb7ccd93297c05696c39053bd91fec Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 21:34:34 +0200 Subject: [PATCH 21/39] convert the AngularJS model to use DataFlow nodes --- javascript/ql/lib/semmle/javascript/Expr.qll | 2 +- .../semmle/javascript/dataflow/DataFlow.qll | 5 +- .../lib/semmle/javascript/dataflow/Nodes.qll | 6 + .../frameworks/AngularJS/AngularJSCore.qll | 180 +++++++++--------- .../AngularJS/DependencyInjections.qll | 98 +++++----- .../AngularJS/ServiceDefinitions.qll | 55 ++++-- .../CleartextStorageCustomizations.qll | 4 +- .../ClientSideUrlRedirectCustomizations.qll | 2 +- .../dataflow/CodeInjectionCustomizations.qll | 2 +- .../dataflow/DomBasedXssCustomizations.qll | 2 +- .../dataflow/XmlBombCustomizations.qll | 4 +- .../security/dataflow/XxeCustomizations.qll | 4 +- .../AngularJS/DeadAngularJSEventListener.ql | 16 +- .../ql/src/AngularJS/DependencyMismatch.ql | 2 +- javascript/ql/src/AngularJS/DisablingSce.ql | 2 +- .../ql/src/AngularJS/DoubleCompilation.ql | 4 +- .../ql/src/AngularJS/DuplicateDependency.ql | 9 +- .../ql/src/AngularJS/InsecureUrlWhitelist.ql | 2 +- .../ql/src/AngularJS/RepeatedInjection.ql | 6 +- .../src/AngularJS/UnusedAngularDependency.ql | 4 +- .../dependency-dataflow/ScopeMethodCalls.ql | 2 +- .../DependencyResolution_full.ql | 2 +- .../AngularJS/scopes/ScopeAccess.expected | 45 +++++ 23 files changed, 260 insertions(+), 198 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/Expr.qll b/javascript/ql/lib/semmle/javascript/Expr.qll index 7db74458bdf6..3676077e0241 100644 --- a/javascript/ql/lib/semmle/javascript/Expr.qll +++ b/javascript/ql/lib/semmle/javascript/Expr.qll @@ -167,7 +167,7 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode { /** * Holds if this expression may refer to the initial value of parameter `p`. */ - predicate mayReferToParameter(Parameter p) { this.flow().mayReferToParameter(p) } + predicate mayReferToParameter(Parameter p) { DataFlow::parameterNode(p).flowsToExpr(this) } /** * Gets the static type of this expression, as determined by the TypeScript type system. diff --git a/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll index 7a2640b6f60a..20366a8f2b5c 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll @@ -139,9 +139,12 @@ module DataFlow { } /** + * DEPRECATED: Use `DataFlow::ParameterNode::flowsTo()` instead. * Holds if this expression may refer to the initial value of parameter `p`. */ - predicate mayReferToParameter(Parameter p) { parameterNode(p).(SourceNode).flowsTo(this) } + deprecated predicate mayReferToParameter(Parameter p) { + parameterNode(p).(SourceNode).flowsTo(this) + } /** * Holds if this element is at the specified location. diff --git a/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll index 826e5280ace6..29509e36f885 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll @@ -472,6 +472,12 @@ class FunctionNode extends DataFlow::ValueNode, DataFlow::SourceNode { /** Gets a parameter of this function. */ ParameterNode getAParameter() { result = this.getParameter(_) } + /** Gets the parameter named `name` of this function, if any. */ + DataFlow::ParameterNode getParameterByName(string name) { + result = getAParameter() and + result.getName() = name + } + /** Gets the number of parameters declared on this function. */ int getNumParameter() { result = count(astNode.getAParameter()) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll b/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll index f7975a8c1985..e00d7adad9f8 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll @@ -105,8 +105,8 @@ class AngularModule extends TAngularModule { /** * Get the array of dependencies from this module's definition. */ - ArrayExpr getDependencyArray() { - this.getADefinition().getArgument(1).getALocalSource().asExpr() = result + DataFlow::ArrayCreationNode getDependencyArray() { + this.getADefinition().getArgument(1).getALocalSource() = result } /** @@ -160,14 +160,10 @@ class ModuleApiCall extends DataFlow::CallNode { string getMethodName() { result = methodName } } -class ModuleApiCallDependencyInjection extends DependencyInjection { - ModuleApiCall call; +class ModuleApiCallDependencyInjection extends DependencyInjection instanceof ModuleApiCall { string methodName; - ModuleApiCallDependencyInjection() { - this = call and - methodName = call.getMethodName() - } + ModuleApiCallDependencyInjection() { methodName = super.getMethodName() } /** * Gets the argument position for this method call that expects an injectable function. @@ -183,7 +179,7 @@ class ModuleApiCallDependencyInjection extends DependencyInjection { } override DataFlow::Node getAnInjectableFunction() { - result = call.getArgument(this.injectableArgPos()) + result = super.getArgument(this.injectableArgPos()) } } @@ -266,10 +262,10 @@ abstract class CustomDirective extends DirectiveInstance { DataFlow::SourceNode getMember(string name) { result.flowsTo(this.getMemberInit(name)) } /** Gets the method `name` of this directive. */ - Function getMethod(string name) { DataFlow::valueNode(result) = this.getMember(name) } + DataFlow::FunctionNode getMethod(string name) { result = this.getMember(name) } /** Gets a link function of this directive. */ - abstract Function getALinkFunction(); + abstract DataFlow::FunctionNode getALinkFunction(); /** Holds if this directive's properties are bound to the controller. */ abstract predicate bindsToController(); @@ -332,10 +328,10 @@ class GeneralDirective extends CustomDirective, MkCustomDirective { /** Gets a node that contributes to the return value of the factory function. */ override DataFlow::SourceNode getAnInstantiation() { - exists(Function factory, InjectableFunction f | + exists(DataFlow::FunctionNode factory, InjectableFunction f | f = definition.getAFactoryFunction() and factory = f.asFunction() and - result.flowsToExpr(factory.getAReturnedExpr()) + result.flowsTo(factory.getAReturn()) ) } @@ -344,7 +340,7 @@ class GeneralDirective extends CustomDirective, MkCustomDirective { } /** Gets the compile function of this directive, if any. */ - Function getCompileFunction() { result = this.getMethod("compile") } + DataFlow::FunctionNode getCompileFunction() { result = this.getMethod("compile") } /** * Gets a pre/post link function of this directive defined on its definition object. @@ -365,9 +361,8 @@ class GeneralDirective extends CustomDirective, MkCustomDirective { result = this.getMember("link").getAPropertySource(kind) or // { compile: function() { ... return link; } } - exists(Expr compileReturn, DataFlow::SourceNode compileReturnSrc | - compileReturn = this.getCompileFunction().getAReturnedExpr() and - compileReturnSrc.flowsToExpr(compileReturn) + exists(DataFlow::SourceNode compileReturnSrc | + compileReturnSrc.flowsTo(this.getCompileFunction().getAReturn()) | // link = function postLink() { ... } kind = "post" and @@ -380,12 +375,12 @@ class GeneralDirective extends CustomDirective, MkCustomDirective { } /** Gets the pre-link function of this directive. */ - Function getPreLinkFunction() { result = this.getLinkFunction("pre").getAstNode() } + DataFlow::FunctionNode getPreLinkFunction() { result = this.getLinkFunction("pre") } /** Gets the post-link function of this directive. */ - Function getPostLinkFunction() { result = this.getLinkFunction("post").getAstNode() } + DataFlow::FunctionNode getPostLinkFunction() { result = this.getLinkFunction("post") } - override Function getALinkFunction() { result = this.getLinkFunction(_).getAstNode() } + override DataFlow::FunctionNode getALinkFunction() { result = this.getLinkFunction(_) } override predicate bindsToController() { this.getMemberInit("bindToController").asExpr().mayHaveBooleanValue(true) @@ -412,7 +407,7 @@ class ComponentDirective extends CustomDirective, MkCustomComponent { comp.getConfig().hasPropertyWrite(name, result) } - override Function getALinkFunction() { none() } + override DataFlow::FunctionNode getALinkFunction() { none() } override predicate bindsToController() { none() } @@ -561,13 +556,12 @@ class DirectiveTargetName extends string { * * See https://docs.angularjs.org/api/ng/service/$location for details. */ -private class LocationFlowSource extends RemoteFlowSource { +private class LocationFlowSource extends RemoteFlowSource instanceof DataFlow::MethodCallNode { LocationFlowSource() { - exists(ServiceReference service, MethodCallExpr mce, string m, int n | + exists(ServiceReference service, string m, int n | service.getName() = "$location" and - this.asExpr() = mce and - mce = service.getAMethodCall(m) and - n = mce.getNumArgument() + this = service.getAMethodCall(m) and + n = super.getNumArgument() | m = "search" and n < 2 or @@ -605,7 +599,7 @@ private class JQLiteObject extends JQuery::ObjectSource::Range { JQLiteObject() { this = angular().getAMemberCall("element") or - exists(Parameter param | this = DataFlow::parameterNode(param) | + exists(DataFlow::ParameterNode param | this = param | // element parameters to user-functions invoked by AngularJS param = any(LinkFunction link).getElementParameter() or @@ -613,13 +607,13 @@ private class JQLiteObject extends JQuery::ObjectSource::Range { param = d.getCompileFunction().getParameter(0) or exists(DataFlow::FunctionNode f, int i | - f.flowsToExpr(d.getCompileFunction().getAReturnedExpr()) and i = 1 + f.flowsTo(d.getCompileFunction().getAReturn()) and i = 1 or f = d.getMember("template") and i = 0 or f = d.getMember("templateUrl") and i = 0 | - param = f.getAstNode().(Function).getParameter(i) + param = f.getParameter(i) ) ) ) @@ -630,100 +624,112 @@ private class JQLiteObject extends JQuery::ObjectSource::Range { } } +/** + * DEPRECATED: Use `AngularJSCallNode` instead. + * A call to an AngularJS function. + * + * Used for exposing behavior that is similar to the behavior of other libraries. + */ +deprecated class AngularJSCall extends CallExpr { + AngularJSCallNode node; + + AngularJSCall() { this.flow() = node } + + /** Holds if `e` is an argument that this call interprets as HTML. */ + deprecated predicate interpretsArgumentAsHtml(Expr e) { node.interpretsArgumentAsHtml(e.flow()) } + + /** Holds if `e` is an argument that this call stores globally, e.g. in a cookie. */ + deprecated predicate storesArgumentGlobally(Expr e) { node.storesArgumentGlobally(e.flow()) } + + /** Holds if `e` is an argument that this call interprets as code. */ + deprecated predicate interpretsArgumentAsCode(Expr e) { node.interpretsArgumentAsCode(e.flow()) } +} + /** * A call to an AngularJS function. * * Used for exposing behavior that is similar to the behavior of other libraries. */ -abstract class AngularJSCall extends CallExpr { +abstract class AngularJSCallNode extends DataFlow::CallNode { /** * Holds if `e` is an argument that this call interprets as HTML. */ - abstract predicate interpretsArgumentAsHtml(Expr e); + abstract predicate interpretsArgumentAsHtml(DataFlow::Node e); /** * Holds if `e` is an argument that this call stores globally, e.g. in a cookie. */ - abstract predicate storesArgumentGlobally(Expr e); + abstract predicate storesArgumentGlobally(DataFlow::Node e); /** * Holds if `e` is an argument that this call interprets as code. */ - abstract predicate interpretsArgumentAsCode(Expr e); + abstract predicate interpretsArgumentAsCode(DataFlow::Node e); } /** * A call to a method on the AngularJS object itself. */ -private class AngularMethodCall extends AngularJSCall { - MethodCallExpr mce; - - AngularMethodCall() { - mce = angular().getAMemberCall(_).asExpr() and - mce = this - } +private class AngularMethodCall extends AngularJSCallNode { + AngularMethodCall() { this = angular().getAMemberCall(_) } - override predicate interpretsArgumentAsHtml(Expr e) { - mce.getMethodName() = "element" and - e = mce.getArgument(0) + override predicate interpretsArgumentAsHtml(DataFlow::Node e) { + super.getCalleeName() = "element" and + e = super.getArgument(0) } - override predicate storesArgumentGlobally(Expr e) { none() } + override predicate storesArgumentGlobally(DataFlow::Node e) { none() } - override predicate interpretsArgumentAsCode(Expr e) { none() } + override predicate interpretsArgumentAsCode(DataFlow::Node e) { none() } } /** * A call to a builtin service or one of its methods. */ -private class BuiltinServiceCall extends AngularJSCall { - CallExpr call; - +private class BuiltinServiceCall extends AngularJSCallNode { BuiltinServiceCall() { exists(BuiltinServiceReference service | service.getAMethodCall(_) = this or service.getACall() = this - | - call = this ) } - override predicate interpretsArgumentAsHtml(Expr e) { + override predicate interpretsArgumentAsHtml(DataFlow::Node e) { exists(ServiceReference service, string methodName | service.getName() = "$sce" and - call = service.getAMethodCall(methodName) + this = service.getAMethodCall(methodName) | // specialized call (methodName = "trustAsHtml" or methodName = "trustAsCss") and - e = call.getArgument(0) + e = this.getArgument(0) or // generic call with enum argument methodName = "trustAs" and exists(DataFlow::PropRead prn | - prn.asExpr() = call.getArgument(0) and + prn = this.getArgument(0) and (prn = service.getAPropertyAccess("HTML") or prn = service.getAPropertyAccess("CSS")) and - e = call.getArgument(1) + e = this.getArgument(1) ) ) } - override predicate storesArgumentGlobally(Expr e) { + override predicate storesArgumentGlobally(DataFlow::Node e) { exists(ServiceReference service, string serviceName, string methodName | service.getName() = serviceName and - call = service.getAMethodCall(methodName) + this = service.getAMethodCall(methodName) | // AngularJS caches (only available during runtime, so similar to sessionStorage) (serviceName = "$cacheFactory" or serviceName = "$templateCache") and methodName = "put" and - e = call.getArgument(1) + e = this.getArgument(1) or serviceName = "$cookies" and (methodName = "put" or methodName = "putObject") and - e = call.getArgument(1) + e = this.getArgument(1) ) } - override predicate interpretsArgumentAsCode(Expr e) { + override predicate interpretsArgumentAsCode(DataFlow::Node e) { exists(ScopeServiceReference scope, string methodName | methodName = [ @@ -731,22 +737,21 @@ private class BuiltinServiceCall extends AngularJSCall { "$watchGroup" ] | - call = scope.getAMethodCall(methodName) and - e = call.getArgument(0) + this = scope.getAMethodCall(methodName) and + e = this.getArgument(0) ) or exists(ServiceReference service | service.getName() = ["$compile", "$parse", "$interpolate"] | - call = service.getACall() and - e = call.getArgument(0) + this = service.getACall() and + e = this.getArgument(0) ) or - exists(ServiceReference service, CallExpr filterInvocation | + exists(ServiceReference service | // `$filter('orderBy')(collection, expression)` service.getName() = "$filter" and - call = service.getACall() and - call.getArgument(0).mayHaveStringValue("orderBy") and - filterInvocation.getCallee() = call and - e = filterInvocation.getArgument(1) + this = service.getACall() and + this.getArgument(0).mayHaveStringValue("orderBy") and + e = this.getACall().getArgument(1) ) } } @@ -754,33 +759,33 @@ private class BuiltinServiceCall extends AngularJSCall { /** * A link-function used in a custom AngularJS directive. */ -class LinkFunction extends Function { +class LinkFunction extends DataFlow::FunctionNode { LinkFunction() { this = any(GeneralDirective d).getALinkFunction() } /** * Gets the scope parameter of this function. */ - Parameter getScopeParameter() { result = this.getParameter(0) } + DataFlow::ParameterNode getScopeParameter() { result = this.getParameter(0) } /** * Gets the element parameter of this function (contains a jqLite-wrapped DOM element). */ - Parameter getElementParameter() { result = this.getParameter(1) } + DataFlow::ParameterNode getElementParameter() { result = this.getParameter(1) } /** * Gets the attributes parameter of this function. */ - Parameter getAttributesParameter() { result = this.getParameter(2) } + DataFlow::ParameterNode getAttributesParameter() { result = this.getParameter(2) } /** * Gets the controller parameter of this function. */ - Parameter getControllerParameter() { result = this.getParameter(3) } + DataFlow::ParameterNode getControllerParameter() { result = this.getParameter(3) } /** * Gets the transclude-function parameter of this function. */ - Parameter getTranscludeFnParameter() { result = this.getParameter(4) } + DataFlow::ParameterNode getTranscludeFnParameter() { result = this.getParameter(4) } } /** @@ -807,29 +812,29 @@ class AngularScope extends TAngularScope { /** * Gets an access to this scope object. */ - Expr getAnAccess() { + DataFlow::Node getAnAccess() { exists(CustomDirective d | this = d.getAScope() | - exists(Parameter p | + exists(DataFlow::ParameterNode p | p = d.getController().getDependencyParameter("$scope") or p = d.getALinkFunction().getParameter(0) | - result.mayReferToParameter(p) + p.flowsTo(result) ) or exists(DataFlow::ThisNode dis | - dis.flowsToExpr(result) and - dis.getBinder().getAstNode() = d.getController().asFunction() and + dis.flowsTo(result) and + dis.getBinder() = d.getController().asFunction() and d.bindsToController() ) or - d.hasIsolateScope() and result = d.getMember("scope").asExpr() + d.hasIsolateScope() and result = d.getMember("scope") ) or - exists(DirectiveController c, DOM::ElementDefinition elem, Parameter p | + exists(DirectiveController c, DOM::ElementDefinition elem, DataFlow::ParameterNode p | c.boundTo(elem) and this.mayApplyTo(elem) and p = c.getFactoryFunction().getDependencyParameter("$scope") and - result.mayReferToParameter(p) + p.flowsTo(result) ) } @@ -1022,15 +1027,12 @@ private class RouteInstantiatedController extends Controller { /** * Dataflow for the arguments of AngularJS dependency-injected functions. */ -private class DependencyInjectedArgumentInitializer extends DataFlow::AnalyzedNode { +private class DependencyInjectedArgumentInitializer extends DataFlow::AnalyzedNode instanceof DataFlow::ParameterNode { DataFlow::AnalyzedNode service; DependencyInjectedArgumentInitializer() { - exists( - AngularJS::InjectableFunction f, Parameter param, AngularJS::CustomServiceDefinition def - | - this = DataFlow::parameterNode(param) and - def.getServiceReference() = f.getAResolvedDependency(param) and + exists(AngularJS::InjectableFunction f, AngularJS::CustomServiceDefinition def | + def.getServiceReference() = f.getAResolvedDependency(this) and service = def.getAService() ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/DependencyInjections.qll b/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/DependencyInjections.qll index 6f5aaf7d38ff..0db43d3d97a9 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/DependencyInjections.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/DependencyInjections.qll @@ -41,33 +41,35 @@ abstract class DependencyInjection extends DataFlow::ValueNode { */ abstract class InjectableFunction extends DataFlow::ValueNode { /** Gets the parameter corresponding to dependency `name`. */ - abstract Parameter getDependencyParameter(string name); + abstract DataFlow::ParameterNode getDependencyParameter(string name); /** * Gets the `i`th dependency declaration, which is also named `name`. */ - abstract AstNode getDependencyDeclaration(int i, string name); + abstract DataFlow::Node getDependencyDeclaration(int i, string name); /** - * Gets an ASTNode for the `name` dependency declaration. + * Gets a node for the `name` dependency declaration. */ - AstNode getADependencyDeclaration(string name) { result = getDependencyDeclaration(_, name) } + DataFlow::Node getADependencyDeclaration(string name) { + result = getDependencyDeclaration(_, name) + } /** - * Gets the ASTNode for the `i`th dependency declaration. + * Gets the dataflow node for the `i`th dependency declaration. */ - AstNode getDependencyDeclaration(int i) { result = getDependencyDeclaration(i, _) } + DataFlow::Node getDependencyDeclaration(int i) { result = getDependencyDeclaration(i, _) } /** Gets the function underlying this injectable function. */ - abstract Function asFunction(); + abstract DataFlow::FunctionNode asFunction(); - /** Gets a location where this function is explicitly dependency injected. */ - abstract AstNode getAnExplicitDependencyInjection(); + /** Gets a node where this function is explicitly dependency injected. */ + abstract DataFlow::Node getAnExplicitDependencyInjection(); /** * Gets a service corresponding to the dependency-injected `parameter`. */ - ServiceReference getAResolvedDependency(Parameter parameter) { + ServiceReference getAResolvedDependency(DataFlow::ParameterNode parameter) { exists(string name, InjectableFunctionServiceRequest request | this = request.getAnInjectedFunction() and parameter = getDependencyParameter(name) and @@ -79,7 +81,7 @@ abstract class InjectableFunction extends DataFlow::ValueNode { * Gets a Custom service corresponding to the dependency-injected `parameter`. * (this is a convenience variant of `getAResolvedDependency`) */ - DataFlow::Node getCustomServiceDependency(Parameter parameter) { + DataFlow::Node getCustomServiceDependency(DataFlow::ParameterNode parameter) { exists(CustomServiceDefinition custom | custom.getServiceReference() = getAResolvedDependency(parameter) and result = custom.getAService() @@ -91,100 +93,88 @@ abstract class InjectableFunction extends DataFlow::ValueNode { * An injectable function that does not explicitly list its dependencies, * instead relying on implicit matching by parameter names. */ -private class FunctionWithImplicitDependencyAnnotation extends InjectableFunction { - override Function astNode; - +private class FunctionWithImplicitDependencyAnnotation extends InjectableFunction instanceof DataFlow::FunctionNode { FunctionWithImplicitDependencyAnnotation() { this.(DataFlow::FunctionNode).flowsTo(any(DependencyInjection d).getAnInjectableFunction()) and - not exists(getAPropertyDependencyInjection(astNode)) + not exists(getAPropertyDependencyInjection(this)) } - override Parameter getDependencyParameter(string name) { - result = astNode.getParameterByName(name) + override DataFlow::ParameterNode getDependencyParameter(string name) { + result = super.getParameterByName(name) } - override Parameter getDependencyDeclaration(int i, string name) { + override DataFlow::ParameterNode getDependencyDeclaration(int i, string name) { result.getName() = name and - result = astNode.getParameter(i) + result = super.getParameter(i) } - override Function asFunction() { result = astNode } + override DataFlow::FunctionNode asFunction() { result = this } - override AstNode getAnExplicitDependencyInjection() { none() } + override DataFlow::Node getAnExplicitDependencyInjection() { none() } } -private DataFlow::PropWrite getAPropertyDependencyInjection(Function function) { - exists(DataFlow::FunctionNode ltf | - ltf.getAstNode() = function and - result = ltf.getAPropertyWrite("$inject") - ) +private DataFlow::PropWrite getAPropertyDependencyInjection(DataFlow::FunctionNode function) { + result = function.getAPropertyWrite("$inject") } /** * An injectable function with an `$inject` property that lists its * dependencies. */ -private class FunctionWithInjectProperty extends InjectableFunction { - override Function astNode; +private class FunctionWithInjectProperty extends InjectableFunction instanceof DataFlow::FunctionNode { DataFlow::ArrayCreationNode dependencies; FunctionWithInjectProperty() { ( this.(DataFlow::FunctionNode).flowsTo(any(DependencyInjection d).getAnInjectableFunction()) or - exists(FunctionWithExplicitDependencyAnnotation f | f.asFunction() = astNode) + exists(FunctionWithExplicitDependencyAnnotation f | f.asFunction() = this) ) and exists(DataFlow::PropWrite pwn | - pwn = getAPropertyDependencyInjection(astNode) and + pwn = getAPropertyDependencyInjection(this) and pwn.getRhs().getALocalSource() = dependencies ) } - override Parameter getDependencyParameter(string name) { - exists(int i | exists(getDependencyDeclaration(i, name)) | result = astNode.getParameter(i)) + override DataFlow::ParameterNode getDependencyParameter(string name) { + exists(int i | exists(getDependencyDeclaration(i, name)) | result = super.getParameter(i)) } - override AstNode getDependencyDeclaration(int i, string name) { - exists(DataFlow::ValueNode decl | - decl = dependencies.getElement(i) and - decl.mayHaveStringValue(name) and - result = decl.getAstNode() - ) + override DataFlow::Node getDependencyDeclaration(int i, string name) { + result = dependencies.getElement(i) and + result.mayHaveStringValue(name) } - override Function asFunction() { result = astNode } + override DataFlow::FunctionNode asFunction() { result = this } - override AstNode getAnExplicitDependencyInjection() { - result = getAPropertyDependencyInjection(astNode).getAstNode() + override DataFlow::Node getAnExplicitDependencyInjection() { + result = getAPropertyDependencyInjection(this) } } /** * An injectable function embedded in an array of dependencies. */ -private class FunctionWithExplicitDependencyAnnotation extends InjectableFunction { +private class FunctionWithExplicitDependencyAnnotation extends InjectableFunction instanceof DataFlow::ArrayCreationNode { DataFlow::FunctionNode function; - override ArrayExpr astNode; FunctionWithExplicitDependencyAnnotation() { this.(DataFlow::SourceNode).flowsTo(any(DependencyInjection d).getAnInjectableFunction()) and - function.flowsToExpr(astNode.getElement(astNode.getSize() - 1)) + function.flowsTo(super.getElement(super.getSize() - 1)) } - override Parameter getDependencyParameter(string name) { - exists(int i | astNode.getElement(i).mayHaveStringValue(name) | - result = asFunction().getParameter(i) - ) + override DataFlow::ParameterNode getDependencyParameter(string name) { + exists(int i | super.getElement(i).mayHaveStringValue(name) | result = function.getParameter(i)) } - override AstNode getDependencyDeclaration(int i, string name) { - result = astNode.getElement(i) and - result.(Expr).mayHaveStringValue(name) + override DataFlow::Node getDependencyDeclaration(int i, string name) { + result = super.getElement(i) and + result.mayHaveStringValue(name) } - override Function asFunction() { result = function.getAstNode() } + override DataFlow::FunctionNode asFunction() { result = function } - override AstNode getAnExplicitDependencyInjection() { - result = astNode or + override DataFlow::Node getAnExplicitDependencyInjection() { + result = this or result = function.(InjectableFunction).getAnExplicitDependencyInjection() } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll b/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll index 6d421de851ce..e13142fdc89d 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll @@ -38,25 +38,25 @@ abstract class ServiceReference extends TServiceReference { * Gets a data flow node that may refer to this service. */ DataFlow::SourceNode getAReference() { - result = DataFlow::parameterNode(any(ServiceRequest request).getDependencyParameter(this)) + result = any(ServiceRequestNode request).getDependencyParameter(this) } /** * Gets an access to the referenced service. */ - Expr getAnAccess() { - result.mayReferToParameter(any(ServiceRequest request).getDependencyParameter(this)) + DataFlow::Node getAnAccess() { + any(ServiceRequestNode request).getDependencyParameter(this).flowsTo(result) } /** * Gets a call that invokes the referenced service. */ - CallExpr getACall() { result.getCallee() = getAnAccess() } + DataFlow::CallNode getACall() { result.getCalleeNode() = getAnAccess() } /** * Gets a method call that invokes method `methodName` on the referenced service. */ - MethodCallExpr getAMethodCall(string methodName) { + DataFlow::MethodCallNode getAMethodCall(string methodName) { result.getReceiver() = getAnAccess() and result.getMethodName() = methodName } @@ -65,7 +65,7 @@ abstract class ServiceReference extends TServiceReference { * Gets an access to property `propertyName` on the referenced service. */ DataFlow::PropRef getAPropertyAccess(string propertyName) { - result.getBase().asExpr() = getAnAccess() and + result.getBase() = getAnAccess() and result.getPropertyName() = propertyName } @@ -93,7 +93,7 @@ class BuiltinServiceReference extends ServiceReference, MkBuiltinServiceReferenc DataFlow::ParameterNode builtinServiceRef(string serviceName) { exists(InjectableFunction f, BuiltinServiceReference service | service.getName() = serviceName and - result = DataFlow::parameterNode(f.getDependencyParameter(serviceName)) + result = f.getDependencyParameter(serviceName) ) } @@ -338,7 +338,7 @@ class FilterDefinition extends CustomSpecialServiceDefinition { override DataFlow::SourceNode getAService() { exists(InjectableFunction f | f = factoryFunction.getALocalSource() and - result.flowsToExpr(f.asFunction().getAReturnedExpr()) + result.flowsTo(f.asFunction().getAReturn()) ) } @@ -428,7 +428,7 @@ class AnimationDefinition extends CustomSpecialServiceDefinition { override DataFlow::SourceNode getAService() { exists(InjectableFunction f | f = factoryFunction.getALocalSource() and - result.flowsToExpr(f.asFunction().getAReturnedExpr()) + result.flowsTo(f.asFunction().getAReturn()) ) } @@ -446,22 +446,37 @@ BuiltinServiceReference getBuiltinServiceOfKind(string kind) { } /** + * DEPRECATED: Use `ServiceRequestNode` instead. * A request for one or more AngularJS services. */ -abstract class ServiceRequest extends Expr { +deprecated class ServiceRequest extends Expr { + ServiceRequestNode node; + + ServiceRequest() { this.flow() = node } + + /** Gets the parameter of this request into which `service` is injected. */ + deprecated Parameter getDependencyParameter(ServiceReference service) { + result.flow() = node.getDependencyParameter(service) + } +} + +/** + * A request for one or more AngularJS services. + */ +abstract class ServiceRequestNode extends DataFlow::Node { /** * Gets the parameter of this request into which `service` is injected. */ - abstract Parameter getDependencyParameter(ServiceReference service); + abstract DataFlow::ParameterNode getDependencyParameter(ServiceReference service); } /** * The request for a scope service in the form of the link-function of a directive. */ -private class LinkFunctionWithScopeInjection extends ServiceRequest { +private class LinkFunctionWithScopeInjection extends ServiceRequestNode { LinkFunctionWithScopeInjection() { this instanceof LinkFunction } - override Parameter getDependencyParameter(ServiceReference service) { + override DataFlow::ParameterNode getDependencyParameter(ServiceReference service) { service instanceof ScopeServiceReference and result = this.(LinkFunction).getScopeParameter() } @@ -470,10 +485,10 @@ private class LinkFunctionWithScopeInjection extends ServiceRequest { /** * A request for a service, in the form of a dependency-injected function. */ -class InjectableFunctionServiceRequest extends ServiceRequest { +class InjectableFunctionServiceRequest extends ServiceRequestNode { InjectableFunction injectedFunction; - InjectableFunctionServiceRequest() { injectedFunction.getAstNode() = this } + InjectableFunctionServiceRequest() { injectedFunction = this } /** * Gets the function of this request. @@ -494,16 +509,16 @@ class InjectableFunctionServiceRequest extends ServiceRequest { result.isInjectable() } - override Parameter getDependencyParameter(ServiceReference service) { + override DataFlow::ParameterNode getDependencyParameter(ServiceReference service) { service = injectedFunction.getAResolvedDependency(result) } } private DataFlow::SourceNode getFactoryFunctionResult(RecipeDefinition def) { - exists(Function factoryFunction, InjectableFunction f | + exists(DataFlow::FunctionNode factoryFunction, InjectableFunction f | f = def.getAFactoryFunction() and factoryFunction = f.asFunction() and - result.flowsToExpr(factoryFunction.getAReturnedExpr()) + result.flowsTo(factoryFunction.getAReturn()) ) } @@ -562,7 +577,7 @@ class ServiceRecipeDefinition extends RecipeDefinition { exists(InjectableFunction f | f = getAFactoryFunction() and - result.getAstNode() = f.asFunction() + result = f.asFunction() ) } } @@ -608,7 +623,7 @@ class ProviderRecipeDefinition extends RecipeDefinition { exists(DataFlow::ThisNode thiz, InjectableFunction f | f = getAFactoryFunction() and - thiz.getBinder().getFunction() = f.asFunction() and + thiz.getBinder() = f.asFunction() and result = thiz.getAPropertySource("$get") ) } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll index 1e5c5d712c48..60c7aad426ec 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll @@ -67,8 +67,6 @@ module CleartextStorage { * An expression stored by AngularJS. */ class AngularJSStorageSink extends Sink { - AngularJSStorageSink() { - any(AngularJS::AngularJSCall call).storesArgumentGlobally(this.asExpr()) - } + AngularJSStorageSink() { any(AngularJS::AngularJSCallNode call).storesArgumentGlobally(this) } } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll index 513b6cc18f91..d6f8466b086e 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll @@ -121,7 +121,7 @@ module ClientSideUrlRedirect { // A redirection using the AngularJS `$location` service exists(AngularJS::ServiceReference service | service.getName() = "$location" and - this.asExpr() = service.getAMethodCall("url").getArgument(0) + this = service.getAMethodCall("url").getArgument(0) ) and xss = false } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll index 9e72cc9ee820..fd76028a6f32 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll @@ -37,7 +37,7 @@ module CodeInjection { */ class AngularJSExpressionSink extends Sink, DataFlow::ValueNode { AngularJSExpressionSink() { - any(AngularJS::AngularJSCall call).interpretsArgumentAsCode(this.asExpr()) + any(AngularJS::AngularJSCallNode call).interpretsArgumentAsCode(this) } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll index 9b5179a29059..18230c920377 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll @@ -31,7 +31,7 @@ module DomBasedXss { ) or // call to an Angular method that interprets its argument as HTML - any(AngularJS::AngularJSCall call).interpretsArgumentAsHtml(this.asExpr()) + any(AngularJS::AngularJSCallNode call).interpretsArgumentAsHtml(this) or // call to a WinJS function that interprets its argument as HTML exists(DataFlow::MethodCallNode mcn, string m | diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/XmlBombCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/XmlBombCustomizations.qll index 1d159b057ad0..7d9755ca7a51 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/XmlBombCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/XmlBombCustomizations.qll @@ -31,8 +31,8 @@ module XmlBomb { /** * An access to `document.location`, considered as a flow source for XML bomb vulnerabilities. */ - class LocationAsSource extends Source, DataFlow::ValueNode { - LocationAsSource() { isLocation(astNode) } + class LocationAsSource extends Source { + LocationAsSource() { isLocationNode(this) } } /** diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/XxeCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/XxeCustomizations.qll index 4e7bb5e730c9..0b54c3bf301f 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/XxeCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/XxeCustomizations.qll @@ -31,8 +31,8 @@ module Xxe { /** * An access to `document.location`, considered as a flow source for XXE vulnerabilities. */ - class LocationAsSource extends Source, DataFlow::ValueNode { - LocationAsSource() { isLocation(astNode) } + class LocationAsSource extends Source { + LocationAsSource() { isLocationNode(this) } } /** diff --git a/javascript/ql/src/AngularJS/DeadAngularJSEventListener.ql b/javascript/ql/src/AngularJS/DeadAngularJSEventListener.ql index 36a907842752..d1d411ad4470 100644 --- a/javascript/ql/src/AngularJS/DeadAngularJSEventListener.ql +++ b/javascript/ql/src/AngularJS/DeadAngularJSEventListener.ql @@ -42,17 +42,19 @@ predicate isABuiltinEventName(string name) { * Holds if user code emits or broadcasts an event named `name`. */ predicate isAUserDefinedEventName(string name) { - exists(string methodName, MethodCallExpr mce | methodName = "$emit" or methodName = "$broadcast" | - mce.getArgument(0).mayHaveStringValue(name) and + exists(string methodName, DataFlow::MethodCallNode mcn | + methodName = "$emit" or methodName = "$broadcast" + | + mcn.getArgument(0).mayHaveStringValue(name) and ( // dataflow based scope resolution - mce = any(AngularJS::ScopeServiceReference scope).getAMethodCall(methodName) + mcn = any(AngularJS::ScopeServiceReference scope).getAMethodCall(methodName) or // heuristic scope resolution: assume parameters like `$scope` or `$rootScope` are AngularJS scope objects - exists(SimpleParameter param | + exists(DataFlow::ParameterNode param | param.getName() = any(AngularJS::ScopeServiceReference scope).getName() and - mce.getReceiver().mayReferToParameter(param) and - mce.getMethodName() = methodName + param.getAMethodCall() = mcn and + mcn.getMethodName() = methodName ) or // a call in an AngularJS expression @@ -64,7 +66,7 @@ predicate isAUserDefinedEventName(string name) { ) } -from AngularJS::ScopeServiceReference scope, MethodCallExpr mce, string eventName +from AngularJS::ScopeServiceReference scope, DataFlow::MethodCallNode mce, string eventName where mce = scope.getAMethodCall("$on") and mce.getArgument(0).mayHaveStringValue(eventName) and diff --git a/javascript/ql/src/AngularJS/DependencyMismatch.ql b/javascript/ql/src/AngularJS/DependencyMismatch.ql index bbdb042bf19d..83f9b1cb73ac 100644 --- a/javascript/ql/src/AngularJS/DependencyMismatch.ql +++ b/javascript/ql/src/AngularJS/DependencyMismatch.ql @@ -14,7 +14,7 @@ import javascript -from AngularJS::InjectableFunction f, SimpleParameter p, string msg +from AngularJS::InjectableFunction f, DataFlow::ParameterNode p, string msg where p = f.asFunction().getAParameter() and ( diff --git a/javascript/ql/src/AngularJS/DisablingSce.ql b/javascript/ql/src/AngularJS/DisablingSce.ql index 7ec1b5405b21..4f164d9c55b1 100644 --- a/javascript/ql/src/AngularJS/DisablingSce.ql +++ b/javascript/ql/src/AngularJS/DisablingSce.ql @@ -14,7 +14,7 @@ import javascript -from MethodCallExpr mce, AngularJS::BuiltinServiceReference service +from DataFlow::MethodCallNode mce, AngularJS::BuiltinServiceReference service where service.getName() = "$sceProvider" and mce = service.getAMethodCall("enabled") and diff --git a/javascript/ql/src/AngularJS/DoubleCompilation.ql b/javascript/ql/src/AngularJS/DoubleCompilation.ql index 95f088d20ce2..968e493c45da 100644 --- a/javascript/ql/src/AngularJS/DoubleCompilation.ql +++ b/javascript/ql/src/AngularJS/DoubleCompilation.ql @@ -15,7 +15,7 @@ import javascript -from AngularJS::ServiceReference compile, SimpleParameter elem, CallExpr c +from AngularJS::ServiceReference compile, DataFlow::ParameterNode elem, DataFlow::CallNode c where compile.getName() = "$compile" and elem = @@ -24,7 +24,7 @@ where .(AngularJS::LinkFunction) .getElementParameter() and c = compile.getACall() and - c.getArgument(0).mayReferToParameter(elem) and + elem.flowsTo(c.getArgument(0)) and // don't flag $compile calls that specify a `maxPriority` c.getNumArgument() < 3 select c, "This call to $compile may cause double compilation of '" + elem + "'." diff --git a/javascript/ql/src/AngularJS/DuplicateDependency.ql b/javascript/ql/src/AngularJS/DuplicateDependency.ql index e0f0c4954cb8..53ed240aa542 100644 --- a/javascript/ql/src/AngularJS/DuplicateDependency.ql +++ b/javascript/ql/src/AngularJS/DuplicateDependency.ql @@ -12,16 +12,17 @@ import javascript import semmle.javascript.RestrictedLocations -predicate isRepeatedDependency(AngularJS::InjectableFunction f, string name, AstNode location) { +predicate isRepeatedDependency(AngularJS::InjectableFunction f, string name, DataFlow::Node node) { exists(int i, int j | i < j and exists(f.getDependencyDeclaration(i, name)) and - location = f.getDependencyDeclaration(j, name) + node = f.getDependencyDeclaration(j, name) ) } -from AngularJS::InjectableFunction f, AstNode node, string name +from AngularJS::InjectableFunction f, DataFlow::Node node, string name where isRepeatedDependency(f, name, node) and not count(f.asFunction().getParameterByName(name)) > 1 // avoid duplicating reports from js/duplicate-parameter-name -select f.asFunction().(FirstLineOf), "This function has a duplicate dependency '$@'.", node, name +select f.asFunction().getFunction().(FirstLineOf), "This function has a duplicate dependency '$@'.", + node, name diff --git a/javascript/ql/src/AngularJS/InsecureUrlWhitelist.ql b/javascript/ql/src/AngularJS/InsecureUrlWhitelist.ql index ac4c4772f11d..54f900a1b36b 100644 --- a/javascript/ql/src/AngularJS/InsecureUrlWhitelist.ql +++ b/javascript/ql/src/AngularJS/InsecureUrlWhitelist.ql @@ -23,7 +23,7 @@ predicate isResourceUrlWhitelist( ) { exists(AngularJS::ServiceReference service | service.getName() = "$sceDelegateProvider" and - setupCall.asExpr() = service.getAMethodCall("resourceUrlWhitelist") and + setupCall = service.getAMethodCall("resourceUrlWhitelist") and list.flowsTo(setupCall.getArgument(0)) ) } diff --git a/javascript/ql/src/AngularJS/RepeatedInjection.ql b/javascript/ql/src/AngularJS/RepeatedInjection.ql index 3f2e535fdd0d..27fb0dc2f621 100644 --- a/javascript/ql/src/AngularJS/RepeatedInjection.ql +++ b/javascript/ql/src/AngularJS/RepeatedInjection.ql @@ -12,9 +12,9 @@ import javascript import semmle.javascript.RestrictedLocations -from AngularJS::InjectableFunction f, AstNode explicitInjection +from AngularJS::InjectableFunction f, DataFlow::Node explicitInjection where count(f.getAnExplicitDependencyInjection()) > 1 and explicitInjection = f.getAnExplicitDependencyInjection() -select f.asFunction().(FirstLineOf), "This function has $@ defined in multiple places.", - explicitInjection, "dependency injections" +select f.asFunction().getFunction().(FirstLineOf), + "This function has $@ defined in multiple places.", explicitInjection, "dependency injections" diff --git a/javascript/ql/src/AngularJS/UnusedAngularDependency.ql b/javascript/ql/src/AngularJS/UnusedAngularDependency.ql index 4eb22c336953..4c5530d1a68a 100644 --- a/javascript/ql/src/AngularJS/UnusedAngularDependency.ql +++ b/javascript/ql/src/AngularJS/UnusedAngularDependency.ql @@ -13,9 +13,9 @@ import javascript import Declarations.UnusedParameter import semmle.javascript.RestrictedLocations -predicate isUnusedParameter(Function f, string msg, Parameter parameter) { +predicate isUnusedParameter(DataFlow::FunctionNode f, string msg, Parameter parameter) { exists(Variable pv | - isUnused(f, parameter, pv, _) and + isUnused(f.getFunction(), parameter, pv, _) and not isAnAccidentallyUnusedParameter(parameter) and // avoid double alerts msg = "Unused dependency " + pv.getName() + "." ) diff --git a/javascript/ql/test/library-tests/frameworks/AngularJS/dependency-dataflow/ScopeMethodCalls.ql b/javascript/ql/test/library-tests/frameworks/AngularJS/dependency-dataflow/ScopeMethodCalls.ql index 612439f0be04..53a27ecdf829 100644 --- a/javascript/ql/test/library-tests/frameworks/AngularJS/dependency-dataflow/ScopeMethodCalls.ql +++ b/javascript/ql/test/library-tests/frameworks/AngularJS/dependency-dataflow/ScopeMethodCalls.ql @@ -1,5 +1,5 @@ import javascript -from AngularJS::ScopeServiceReference s, MethodCallExpr mce +from AngularJS::ScopeServiceReference s, DataFlow::MethodCallNode mce where mce = s.getAMethodCall(_) select mce diff --git a/javascript/ql/test/library-tests/frameworks/AngularJS/dependency-resolution/DependencyResolution_full.ql b/javascript/ql/test/library-tests/frameworks/AngularJS/dependency-resolution/DependencyResolution_full.ql index eb12430a4563..be1f2c1aceff 100644 --- a/javascript/ql/test/library-tests/frameworks/AngularJS/dependency-resolution/DependencyResolution_full.ql +++ b/javascript/ql/test/library-tests/frameworks/AngularJS/dependency-resolution/DependencyResolution_full.ql @@ -1,6 +1,6 @@ import javascript private import AngularJS -from InjectableFunction f, SimpleParameter p, DataFlow::Node nd +from InjectableFunction f, DataFlow::ParameterNode p, DataFlow::Node nd where nd = f.getCustomServiceDependency(p) select p.getName(), nd diff --git a/javascript/ql/test/library-tests/frameworks/AngularJS/scopes/ScopeAccess.expected b/javascript/ql/test/library-tests/frameworks/AngularJS/scopes/ScopeAccess.expected index d7a6e49b6cd4..1560c2076bc1 100644 --- a/javascript/ql/test/library-tests/frameworks/AngularJS/scopes/ScopeAccess.expected +++ b/javascript/ql/test/library-tests/frameworks/AngularJS/scopes/ScopeAccess.expected @@ -1,92 +1,137 @@ | isolate scope for directive1 | scope-access.js:4:41:4:45 | scope | +| isolate scope for directive1 | scope-access.js:4:41:4:45 | scope | | isolate scope for directive1 | scope-access.js:5:17:5:21 | scope | | isolate scope for directive1 | scope-access.js:7:20:7:21 | {} | | isolate scope for directive2 | scope-access.js:12:34:12:39 | $scope | +| isolate scope for directive2 | scope-access.js:12:34:12:39 | $scope | | isolate scope for directive2 | scope-access.js:13:17:13:22 | $scope | | isolate scope for directive2 | scope-access.js:15:20:15:21 | {} | | isolate scope for directive3 | scope-access.js:20:39:20:44 | $scope | +| isolate scope for directive3 | scope-access.js:20:39:20:44 | $scope | | isolate scope for directive3 | scope-access.js:21:17:21:22 | $scope | | isolate scope for directive3 | scope-access.js:23:20:23:21 | {} | | isolate scope for directive4 | scope-access.js:28:45:28:45 | a | +| isolate scope for directive4 | scope-access.js:28:45:28:45 | a | | isolate scope for directive4 | scope-access.js:29:17:29:17 | a | | isolate scope for directive4 | scope-access.js:31:20:31:21 | {} | +| isolate scope for directive5 | scope-access.js:36:25:36:24 | this | | isolate scope for directive5 | scope-access.js:37:17:37:20 | this | | isolate scope for directive5 | scope-access.js:39:20:39:21 | {} | +| isolate scope for directive6 | scope-access.js:45:25:45:24 | this | +| isolate scope for directive6 | scope-access.js:46:18:46:26 | return of anonymous function | | isolate scope for directive6 | scope-access.js:46:23:46:26 | this | | isolate scope for directive6 | scope-access.js:48:20:48:21 | {} | | isolate scope for myCustomer | dev-guide-5.js:11:12:13:5 | { // Sc ... y\\n } | | isolate scope for myCustomer | dev-guide-6.js:11:12:13:5 | { // Sc ... y\\n } | | scope for ... | scope-access.js:54:34:54:39 | $scope | +| scope for ... | scope-access.js:54:34:54:39 | $scope | | scope for ... | scope-access.js:55:17:55:22 | $scope | | scope for
... | dev-guide-1.js:4:49:4:54 | $scope | +| scope for
... | dev-guide-1.js:4:49:4:54 | $scope | +| scope for
... | dev-guide-1.js:4:49:4:54 | $scope | | scope for
... | dev-guide-1.js:5:3:5:8 | $scope | | scope for
... | dev-guide-1.js:7:3:7:8 | $scope | +| scope for
... | dev-guide-1.js:7:21:7:20 | $scope | | scope for
... | dev-guide-1.js:8:5:8:10 | $scope | | scope for
... | dev-guide-1.js:8:34:8:39 | $scope | | scope for
... | dev-guide-2.js:4:66:4:71 | $scope | +| scope for
... | dev-guide-2.js:4:66:4:71 | $scope | | scope for
... | dev-guide-2.js:5:3:5:8 | $scope | | scope for
... | dev-guide-2.js:8:51:8:56 | $scope | +| scope for
... | dev-guide-2.js:8:51:8:56 | $scope | | scope for
... | dev-guide-2.js:9:3:9:8 | $scope | | scope for
... | dev-guide-3.js:4:52:4:57 | $scope | +| scope for
... | dev-guide-3.js:4:52:4:57 | $scope | +| scope for
... | dev-guide-3.js:4:52:4:57 | $scope | | scope for
... | dev-guide-3.js:5:3:5:8 | $scope | | scope for
... | dev-guide-3.js:6:3:6:8 | $scope | +| scope for
... | dev-guide-3.js:6:25:6:24 | $scope | | scope for
... | dev-guide-3.js:7:5:7:10 | $scope | | scope for
... | dev-guide-4.js:4:52:4:57 | $scope | +| scope for
... | dev-guide-4.js:4:52:4:57 | $scope | | scope for
... | dev-guide-4.js:5:3:5:8 | $scope | | scope for
... | dev-guide-4.js:10:51:10:56 | $scope | +| scope for
... | dev-guide-4.js:10:51:10:56 | $scope | | scope for
... | dev-guide-4.js:11:3:11:8 | $scope | | scope for
... | dev-guide-5.js:4:47:4:52 | $scope | | scope for
... | dev-guide-5.js:4:47:4:52 | $scope | +| scope for
... | dev-guide-5.js:4:47:4:52 | $scope | +| scope for
... | dev-guide-5.js:4:47:4:52 | $scope | | scope for
... | dev-guide-5.js:5:3:5:8 | $scope | | scope for
... | dev-guide-5.js:5:3:5:8 | $scope | | scope for
... | dev-guide-5.js:6:3:6:8 | $scope | | scope for
... | dev-guide-5.js:6:3:6:8 | $scope | | scope for
... | dev-guide-6.js:4:47:4:52 | $scope | | scope for
... | dev-guide-6.js:4:47:4:52 | $scope | +| scope for
... | dev-guide-6.js:4:47:4:52 | $scope | +| scope for
... | dev-guide-6.js:4:47:4:52 | $scope | | scope for
... | dev-guide-6.js:5:3:5:8 | $scope | | scope for
... | dev-guide-6.js:5:3:5:8 | $scope | | scope for
... | dev-guide-6.js:6:3:6:8 | $scope | | scope for
... | dev-guide-6.js:6:3:6:8 | $scope | | scope for ... | scope-access.js:59:52:59:57 | $scope | +| scope for ... | scope-access.js:59:52:59:57 | $scope | | scope for ... | scope-access.js:60:9:60:14 | $scope | | scope for
  • ... | dev-guide-3.js:4:52:4:57 | $scope | | scope for
  • ... | dev-guide-3.js:4:52:4:57 | $scope | +| scope for
  • ... | dev-guide-3.js:4:52:4:57 | $scope | +| scope for
  • ... | dev-guide-3.js:4:52:4:57 | $scope | +| scope for
  • ... | dev-guide-3.js:4:52:4:57 | $scope | +| scope for
  • ... | dev-guide-3.js:4:52:4:57 | $scope | | scope for
  • ... | dev-guide-3.js:5:3:5:8 | $scope | | scope for
  • ... | dev-guide-3.js:5:3:5:8 | $scope | | scope for
  • ... | dev-guide-3.js:6:3:6:8 | $scope | | scope for
  • ... | dev-guide-3.js:6:3:6:8 | $scope | +| scope for
  • ... | dev-guide-3.js:6:25:6:24 | $scope | +| scope for
  • ... | dev-guide-3.js:6:25:6:24 | $scope | | scope for
  • ... | dev-guide-3.js:7:5:7:10 | $scope | | scope for
  • ... | dev-guide-3.js:7:5:7:10 | $scope | | scope in dev-guide-1.html | dev-guide-1.js:4:49:4:54 | $scope | +| scope in dev-guide-1.html | dev-guide-1.js:4:49:4:54 | $scope | +| scope in dev-guide-1.html | dev-guide-1.js:4:49:4:54 | $scope | | scope in dev-guide-1.html | dev-guide-1.js:5:3:5:8 | $scope | | scope in dev-guide-1.html | dev-guide-1.js:7:3:7:8 | $scope | +| scope in dev-guide-1.html | dev-guide-1.js:7:21:7:20 | $scope | | scope in dev-guide-1.html | dev-guide-1.js:8:5:8:10 | $scope | | scope in dev-guide-1.html | dev-guide-1.js:8:34:8:39 | $scope | | scope in dev-guide-2.html | dev-guide-2.js:4:66:4:71 | $scope | +| scope in dev-guide-2.html | dev-guide-2.js:4:66:4:71 | $scope | | scope in dev-guide-2.html | dev-guide-2.js:5:3:5:8 | $scope | | scope in dev-guide-2.html | dev-guide-2.js:8:51:8:56 | $scope | +| scope in dev-guide-2.html | dev-guide-2.js:8:51:8:56 | $scope | | scope in dev-guide-2.html | dev-guide-2.js:9:3:9:8 | $scope | | scope in dev-guide-3.html | dev-guide-3.js:4:52:4:57 | $scope | +| scope in dev-guide-3.html | dev-guide-3.js:4:52:4:57 | $scope | +| scope in dev-guide-3.html | dev-guide-3.js:4:52:4:57 | $scope | | scope in dev-guide-3.html | dev-guide-3.js:5:3:5:8 | $scope | | scope in dev-guide-3.html | dev-guide-3.js:6:3:6:8 | $scope | +| scope in dev-guide-3.html | dev-guide-3.js:6:25:6:24 | $scope | | scope in dev-guide-3.html | dev-guide-3.js:7:5:7:10 | $scope | | scope in dev-guide-4.html | dev-guide-4.js:4:52:4:57 | $scope | +| scope in dev-guide-4.html | dev-guide-4.js:4:52:4:57 | $scope | | scope in dev-guide-4.html | dev-guide-4.js:5:3:5:8 | $scope | | scope in dev-guide-4.html | dev-guide-4.js:10:51:10:56 | $scope | +| scope in dev-guide-4.html | dev-guide-4.js:10:51:10:56 | $scope | | scope in dev-guide-4.html | dev-guide-4.js:11:3:11:8 | $scope | | scope in dev-guide-5.html | dev-guide-5.js:4:47:4:52 | $scope | +| scope in dev-guide-5.html | dev-guide-5.js:4:47:4:52 | $scope | | scope in dev-guide-5.html | dev-guide-5.js:5:3:5:8 | $scope | | scope in dev-guide-5.html | dev-guide-5.js:6:3:6:8 | $scope | | scope in dev-guide-5.html | dev-guide-6.js:4:47:4:52 | $scope | +| scope in dev-guide-5.html | dev-guide-6.js:4:47:4:52 | $scope | | scope in dev-guide-5.html | dev-guide-6.js:5:3:5:8 | $scope | | scope in dev-guide-5.html | dev-guide-6.js:6:3:6:8 | $scope | | scope in dev-guide-6.html | dev-guide-5.js:4:47:4:52 | $scope | +| scope in dev-guide-6.html | dev-guide-5.js:4:47:4:52 | $scope | | scope in dev-guide-6.html | dev-guide-5.js:5:3:5:8 | $scope | | scope in dev-guide-6.html | dev-guide-5.js:6:3:6:8 | $scope | | scope in dev-guide-6.html | dev-guide-6.js:4:47:4:52 | $scope | +| scope in dev-guide-6.html | dev-guide-6.js:4:47:4:52 | $scope | | scope in dev-guide-6.html | dev-guide-6.js:5:3:5:8 | $scope | | scope in dev-guide-6.html | dev-guide-6.js:6:3:6:8 | $scope | | scope in scope-access.html | scope-access.js:54:34:54:39 | $scope | +| scope in scope-access.html | scope-access.js:54:34:54:39 | $scope | | scope in scope-access.html | scope-access.js:55:17:55:22 | $scope | | scope in scope-access.html | scope-access.js:59:52:59:57 | $scope | +| scope in scope-access.html | scope-access.js:59:52:59:57 | $scope | | scope in scope-access.html | scope-access.js:60:9:60:14 | $scope | From 5ebea8c75a501813688d824c4dd0c4aaf2155fa0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 30 Mar 2022 23:58:20 +0200 Subject: [PATCH 22/39] fix express in the POI test --- javascript/ql/test/experimental/PoI/TestCustomPoIs.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/test/experimental/PoI/TestCustomPoIs.ql b/javascript/ql/test/experimental/PoI/TestCustomPoIs.ql index dd526143a65e..1a4f9b686f01 100644 --- a/javascript/ql/test/experimental/PoI/TestCustomPoIs.ql +++ b/javascript/ql/test/experimental/PoI/TestCustomPoIs.ql @@ -24,7 +24,7 @@ class RouteSetupAndRouterAndRouteHandlerPoI extends ActivePoI { RouteSetupAndRouterAndRouteHandlerPoI() { this = "RouteSetupAndRouterAndRouteHandlerPoI" } override predicate is(Node l0, Node l1, string t1, Node l2, string t2) { - l0.(Express::RouteSetup).getRouter().flow() = l1 and + l0.(Express::RouteSetup).getRouter() = l1 and t1 = "router" and l0.(Express::RouteSetup).getARouteHandler() = l2 and t2 = "routehandler" From e0e8085b95fa52a5500c1ea01dd7408f0c827139 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 31 Mar 2022 10:59:46 +0200 Subject: [PATCH 23/39] update the cryptoLibraries to use dataflow nodes --- .../javascript/frameworks/CryptoLibraries.qll | 126 +++++++++--------- .../BrokenCryptoAlgorithmCustomizations.qll | 2 +- ...InsufficientPasswordHashCustomizations.qll | 2 +- 3 files changed, 64 insertions(+), 66 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll b/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll index 9dcd4d9fbb94..6a583811bc30 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll @@ -8,11 +8,11 @@ import semmle.javascript.security.CryptoAlgorithms /** * An application of a cryptographic algorithm. */ -abstract class CryptographicOperation extends Expr { +abstract class CryptographicOperation extends DataFlow::Node { /** * Gets the input the algorithm is used on, e.g. the plain text input to be encrypted. */ - abstract Expr getInput(); + abstract DataFlow::Node getInput(); /** * Gets the applied algorithm. @@ -58,8 +58,8 @@ class CryptographicKeyCredentialsExpr extends CredentialsExpr { * A model of the asmCrypto library. */ private module AsmCrypto { - private class Apply extends CryptographicOperation { - Expr input; + private class Apply extends CryptographicOperation instanceof DataFlow::CallNode { + DataFlow::Node input; CryptographicAlgorithm algorithm; // non-functional Apply() { @@ -73,17 +73,15 @@ private module AsmCrypto { * ``` */ - exists(DataFlow::CallNode mce | this = mce.asExpr() | - exists(DataFlow::SourceNode asmCrypto, string algorithmName | - asmCrypto = DataFlow::globalVarRef("asmCrypto") and - algorithm.matchesName(algorithmName) and - mce = asmCrypto.getAPropertyRead(algorithmName).getAMemberCall(_) and - input = mce.getAnArgument().asExpr() - ) + exists(DataFlow::SourceNode asmCrypto, string algorithmName | + asmCrypto = DataFlow::globalVarRef("asmCrypto") and + algorithm.matchesName(algorithmName) and + this = asmCrypto.getAPropertyRead(algorithmName).getAMemberCall(_) and + input = this.getAnArgument() ) } - override Expr getInput() { result = input } + override DataFlow::Node getInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } } @@ -97,9 +95,8 @@ private module BrowserIdCrypto { Key() { this = any(Apply apply).getKey() } } - private class Apply extends CryptographicOperation { + private class Apply extends CryptographicOperation instanceof DataFlow::MethodCallNode { CryptographicAlgorithm algorithm; // non-functional - MethodCallExpr mce; Apply() { /* @@ -118,7 +115,6 @@ private module BrowserIdCrypto { * ``` */ - this = mce and exists( DataFlow::SourceNode mod, DataFlow::Node algorithmNameNode, DataFlow::CallNode keygen, DataFlow::FunctionNode callback @@ -128,15 +124,15 @@ private module BrowserIdCrypto { algorithmNameNode = keygen.getOptionArgument(0, "algorithm") and algorithm.matchesName(algorithmNameNode.getStringValue()) and callback = keygen.getCallback(1) and - this = mod.getAMemberCall("sign").asExpr() + this = mod.getAMemberCall("sign") ) } - override Expr getInput() { result = mce.getArgument(0) } + override DataFlow::Node getInput() { result = super.getArgument(0) } override CryptographicAlgorithm getAlgorithm() { result = algorithm } - DataFlow::Node getKey() { result.asExpr() = mce.getArgument(1) } + DataFlow::Node getKey() { result = super.getArgument(1) } } } @@ -217,14 +213,12 @@ private module NodeJSCrypto { override predicate isSymmetricKey() { none() } } - private class Apply extends CryptographicOperation, MethodCallExpr { + private class Apply extends CryptographicOperation instanceof DataFlow::MethodCallNode { InstantiatedAlgorithm instantiation; - Apply() { - this = instantiation.getAMethodCall(any(string m | m = "update" or m = "write")).asExpr() - } + Apply() { this = instantiation.getAMethodCall(any(string m | m = "update" or m = "write")) } - override Expr getInput() { result = this.getArgument(0) } + override DataFlow::Node getInput() { result = super.getArgument(0) } override CryptographicAlgorithm getAlgorithm() { result = instantiation.getAlgorithm() } } @@ -260,7 +254,7 @@ private module CryptoJS { /** * Matches `CryptoJS.` and `require("crypto-js/")` */ - private DataFlow::SourceNode getAlgorithmExpr(CryptographicAlgorithm algorithm) { + private DataFlow::SourceNode getAlgorithmNode(CryptographicAlgorithm algorithm) { exists(string algorithmName | algorithm.matchesName(algorithmName) | exists(DataFlow::SourceNode mod | mod = DataFlow::moduleImport("crypto-js") | result = mod.getAPropertyRead(algorithmName) or @@ -274,7 +268,9 @@ private module CryptoJS { ) } - private DataFlow::CallNode getEncryptionApplication(Expr input, CryptographicAlgorithm algorithm) { + private DataFlow::CallNode getEncryptionApplication( + DataFlow::Node input, CryptographicAlgorithm algorithm + ) { /* * ``` * var CryptoJS = require("crypto-js"); @@ -288,11 +284,13 @@ private module CryptoJS { * Also matches where `CryptoJS.` has been replaced by `require("crypto-js/")` */ - result = getAlgorithmExpr(algorithm).getAMemberCall("encrypt") and - input = result.getArgument(0).asExpr() + result = getAlgorithmNode(algorithm).getAMemberCall("encrypt") and + input = result.getArgument(0) } - private DataFlow::CallNode getDirectApplication(Expr input, CryptographicAlgorithm algorithm) { + private DataFlow::CallNode getDirectApplication( + DataFlow::Node input, CryptographicAlgorithm algorithm + ) { /* * ``` * var CryptoJS = require("crypto-js"); @@ -307,20 +305,20 @@ private module CryptoJS { * Also matches where `CryptoJS.` has been replaced by `require("crypto-js/")` */ - result = getAlgorithmExpr(algorithm).getACall() and - input = result.getArgument(0).asExpr() + result = getAlgorithmNode(algorithm).getACall() and + input = result.getArgument(0) } private class Apply extends CryptographicOperation { - Expr input; + DataFlow::Node input; CryptographicAlgorithm algorithm; // non-functional Apply() { - this = getEncryptionApplication(input, algorithm).asExpr() or - this = getDirectApplication(input, algorithm).asExpr() + this = getEncryptionApplication(input, algorithm) or + this = getDirectApplication(input, algorithm) } - override Expr getInput() { result = input } + override DataFlow::Node getInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } } @@ -328,7 +326,7 @@ private module CryptoJS { private class Key extends CryptographicKey { Key() { exists(DataFlow::SourceNode e, CryptographicAlgorithm algorithm | - e = getAlgorithmExpr(algorithm) + e = getAlgorithmNode(algorithm) | exists(string name | name = "encrypt" or @@ -351,7 +349,7 @@ private module CryptoJS { CreateKey() { // var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 }); this = - getAlgorithmExpr(any(CryptographicAlgorithm algo | algo.getName() = algorithm)).getACall() and + getAlgorithmNode(any(CryptographicAlgorithm algo | algo.getName() = algorithm)).getACall() and optionArg = 2 or // var key = CryptoJS.algo.PBKDF2.create({ keySize: 8 }); @@ -378,8 +376,8 @@ private module CryptoJS { * A model of the TweetNaCl library. */ private module TweetNaCl { - private class Apply extends CryptographicOperation instanceof MethodCallExpr { - Expr input; + private class Apply extends CryptographicOperation instanceof DataFlow::CallNode { + DataFlow::Node input; CryptographicAlgorithm algorithm; Apply() { @@ -400,12 +398,12 @@ private module TweetNaCl { name = "sign" and algorithm.matchesName("ed25519") | (mod = DataFlow::moduleImport("nacl") or mod = DataFlow::moduleImport("nacl-fast")) and - this = mod.getAMemberCall(name).asExpr() and + this = mod.getAMemberCall(name) and super.getArgument(0) = input ) } - override Expr getInput() { result = input } + override DataFlow::Node getInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } } @@ -421,7 +419,7 @@ private module HashJs { * - `require("hash.js/lib/hash/")`() * - `require("hash.js/lib/hash/sha/")`() */ - private DataFlow::CallNode getAlgorithmExpr(CryptographicAlgorithm algorithm) { + private DataFlow::CallNode getAlgorithmNode(CryptographicAlgorithm algorithm) { exists(string algorithmName | algorithm.matchesName(algorithmName) | result = DataFlow::moduleMember("hash.js", algorithmName).getACall() or @@ -438,8 +436,8 @@ private module HashJs { ) } - private class Apply extends CryptographicOperation instanceof MethodCallExpr { - Expr input; + private class Apply extends CryptographicOperation instanceof DataFlow::CallNode { + DataFlow::Node input; CryptographicAlgorithm algorithm; // non-functional Apply() { @@ -456,11 +454,11 @@ private module HashJs { * Also matches where `hash.()` has been replaced by a more specific require a la `require("hash.js/lib/hash/sha/512")` */ - this = getAlgorithmExpr(algorithm).getAMemberCall("update").asExpr() and + this = getAlgorithmNode(algorithm).getAMemberCall("update") and input = super.getArgument(0) } - override Expr getInput() { result = input } + override DataFlow::Node getInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } } @@ -492,7 +490,7 @@ private module Forge { // `require('forge').cipher.createCipher("3DES-CBC").update("secret", "key");` (createName = "createCipher" or createName = "createDecipher") and this = mod.getAPropertyRead("cipher").getAMemberCall(createName) and - this.getArgument(0).asExpr().mayHaveStringValue(cipherName) and + this.getArgument(0).mayHaveStringValue(cipherName) and cipherName = cipherPrefix + "-" + cipherSuffix and cipherSuffix = ["CBC", "CFB", "CTR", "ECB", "GCM", "OFB"] and algorithmName = cipherPrefix and @@ -531,19 +529,19 @@ private module Forge { override CryptographicAlgorithm getAlgorithm() { result = algorithm } } - private class Apply extends CryptographicOperation instanceof MethodCallExpr { - Expr input; + private class Apply extends CryptographicOperation instanceof DataFlow::CallNode { + DataFlow::Node input; CryptographicAlgorithm algorithm; // non-functional Apply() { exists(Cipher cipher | - this = cipher.getAMemberCall("update").asExpr() and + this = cipher.getAMemberCall("update") and super.getArgument(0) = input and algorithm = cipher.getAlgorithm() ) } - override Expr getInput() { result = input } + override DataFlow::Node getInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } } @@ -590,8 +588,8 @@ private module Forge { * A model of the md5 library. */ private module Md5 { - private class Apply extends CryptographicOperation instanceof CallExpr { - Expr input; + private class Apply extends CryptographicOperation instanceof DataFlow::CallNode { + DataFlow::Node input; CryptographicAlgorithm algorithm; Apply() { @@ -599,12 +597,12 @@ private module Md5 { exists(DataFlow::SourceNode mod | mod = DataFlow::moduleImport("md5") and algorithm.matchesName("MD5") and - this = mod.getACall().asExpr() and + this = mod.getACall() and super.getArgument(0) = input ) } - override Expr getInput() { result = input } + override DataFlow::Node getInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } } @@ -614,8 +612,8 @@ private module Md5 { * A model of the bcrypt, bcryptjs, bcrypt-nodejs libraries. */ private module Bcrypt { - private class Apply extends CryptographicOperation instanceof MethodCallExpr { - Expr input; + private class Apply extends CryptographicOperation instanceof DataFlow::CallNode { + DataFlow::Node input; CryptographicAlgorithm algorithm; Apply() { @@ -632,12 +630,12 @@ private module Bcrypt { methodName = "hashSync" ) and mod = DataFlow::moduleImport(moduleName) and - this = mod.getAMemberCall(methodName).asExpr() and + this = mod.getAMemberCall(methodName) and super.getArgument(0) = input ) } - override Expr getInput() { result = input } + override DataFlow::Node getInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } } @@ -647,23 +645,23 @@ private module Bcrypt { * A model of the hasha library. */ private module Hasha { - private class Apply extends CryptographicOperation instanceof CallExpr { - Expr input; + private class Apply extends CryptographicOperation instanceof DataFlow::CallNode { + DataFlow::Node input; CryptographicAlgorithm algorithm; Apply() { // `require('hasha')('unicorn', { algorithm: "md5" });` - exists(DataFlow::SourceNode mod, string algorithmName, Expr algorithmNameNode | + exists(DataFlow::SourceNode mod, string algorithmName, DataFlow::Node algorithmNameNode | mod = DataFlow::moduleImport("hasha") and - this = mod.getACall().asExpr() and + this = mod.getACall() and super.getArgument(0) = input and algorithm.matchesName(algorithmName) and - super.hasOptionArgument(1, "algorithm", algorithmNameNode) and + super.getOptionArgument(1, "algorithm") = algorithmNameNode and algorithmNameNode.mayHaveStringValue(algorithmName) ) } - override Expr getInput() { result = input } + override DataFlow::Node getInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithmCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithmCustomizations.qll index 58858d798865..4149dd84c283 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithmCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithmCustomizations.qll @@ -43,7 +43,7 @@ module BrokenCryptoAlgorithm { WeakCryptographicOperationSink() { exists(CryptographicOperation application | application.getAlgorithm().isWeak() and - this.asExpr() = application.getInput() + this = application.getInput() ) } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHashCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHashCustomizations.qll index 6ffcb7fa527a..83e07c177cfc 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHashCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHashCustomizations.qll @@ -49,7 +49,7 @@ module InsufficientPasswordHash { application.getAlgorithm().isWeak() or not application.getAlgorithm() instanceof PasswordHashingAlgorithm | - this.asExpr() = application.getInput() + this = application.getInput() ) } } From 4d0534352eb749d73b7198390b63377b0f98d0c7 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 31 Mar 2022 11:07:37 +0200 Subject: [PATCH 24/39] refactor a use of MethodCallExpr in `ClientSideUrlRedirectCustomizations.qll` --- .../ClientSideUrlRedirectCustomizations.qll | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll index d6f8466b086e..e0eb92981c0c 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll @@ -57,23 +57,23 @@ module ClientSideUrlRedirect { * when `base` is the current URL. */ predicate untrustedUrlSubstring(DataFlow::Node base, DataFlow::Node substring) { - exists(MethodCallExpr mce, string methodName | - mce = substring.asExpr() and mce.calls(base.asExpr(), methodName) + exists(DataFlow::MethodCallNode mcn, string methodName | + mcn = substring and mcn.calls(base, methodName) | methodName = "split" and // exclude all splits where only the prefix is accessed, which is safe for url-redirects. - not exists(PropAccess pacc | mce = pacc.getBase() | pacc.getPropertyName() = "0") + not exists(DataFlow::PropRead pacc | mcn = pacc.getBase() | pacc.getPropertyName() = "0") or methodName = StringOps::substringMethodName() and // exclude `location.href.substring(0, ...)` and similar, which can // never refer to the query string - not mce.getArgument(0).(NumberLiteral).getIntValue() = 0 + not mcn.getArgument(0).asExpr().(NumberLiteral).getIntValue() = 0 ) or - exists(MethodCallExpr mce | - substring.asExpr() = mce and - mce = any(DataFlow::RegExpCreationNode re).getAMethodCall("exec").asExpr() and - base.asExpr() = mce.getArgument(0) + exists(DataFlow::MethodCallNode mcn | + substring = mcn and + mcn = any(DataFlow::RegExpCreationNode re).getAMethodCall("exec") and + base = mcn.getArgument(0) ) } From c5b158809648641d6cec40f26f10cc681a4f8c0f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 31 Mar 2022 11:14:38 +0200 Subject: [PATCH 25/39] update the SQL/NoSQL models to use dataflow nodes --- .../NosqlInjectionATM.qll | 2 +- .../lib/semmle/javascript/frameworks/Knex.qll | 2 +- .../semmle/javascript/frameworks/NoSQL.qll | 14 ++++---- .../lib/semmle/javascript/frameworks/SQL.qll | 36 +++++++++---------- .../dataflow/NosqlInjectionCustomizations.qll | 4 +-- .../security/dataflow/NosqlInjectionQuery.qll | 2 +- .../dataflow/SqlInjectionCustomizations.qll | 8 ++--- .../query20.qll | 2 +- 8 files changed, 33 insertions(+), 37 deletions(-) diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/NosqlInjectionATM.qll b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/NosqlInjectionATM.qll index 7debdba1f02a..3acb5c315f7d 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/NosqlInjectionATM.qll +++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/NosqlInjectionATM.qll @@ -115,7 +115,7 @@ predicate isBaseAdditionalFlowStep( inlbl = TaintedObject::label() and outlbl = TaintedObject::label() and exists(NoSql::Query query, DataFlow::SourceNode queryObj | - queryObj.flowsToExpr(query) and + queryObj.flowsTo(query) and queryObj.flowsTo(trg) and src = queryObj.getAPropertyWrite().getRhs() ) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Knex.qll b/javascript/ql/lib/semmle/javascript/frameworks/Knex.qll index e768a9feaff6..923df27bd501 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Knex.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Knex.qll @@ -43,7 +43,7 @@ module Knex { /** A SQL string passed to a raw Knex method. */ private class RawKnexSqlString extends SQL::SqlString { - RawKnexSqlString() { this = any(RawKnexCall call).getArgument(0).asExpr() } + RawKnexSqlString() { this = any(RawKnexCall call).getArgument(0) } } /** A call that triggers a SQL query submission by calling then/stream/asCallback. */ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll b/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll index 5985735a1067..69d12d4d10af 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll @@ -6,8 +6,8 @@ import javascript /** Provides classes for modeling NoSql query sinks. */ module NoSql { - /** An expression that is interpreted as a NoSql query. */ - abstract class Query extends Expr { + /** An expression that is interpreted as a NoSQL query. */ + abstract class Query extends DataFlow::Node { /** Gets an expression that is interpreted as a code operator in this query. */ DataFlow::Node getACodeOperator() { none() } } @@ -84,7 +84,7 @@ private module MongoDB { class Query extends NoSql::Query { QueryCall qc; - Query() { this = qc.getAQueryArgument().asExpr() } + Query() { this = qc.getAQueryArgument() } override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() } } @@ -518,7 +518,7 @@ private module Mongoose { class MongoDBQueryPart extends NoSql::Query { MongooseFunction f; - MongoDBQueryPart() { this = f.getQueryArgument().asSink().asExpr() } + MongoDBQueryPart() { this = f.getQueryArgument().asSink() } override DataFlow::Node getACodeOperator() { result = getADollarWhereProperty(f.getQueryArgument()) @@ -625,7 +625,7 @@ private module Minimongo { class Query extends NoSql::Query { QueryCall qc; - Query() { this = qc.getAQueryArgument().asExpr() } + Query() { this = qc.getAQueryArgument() } override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() } } @@ -685,7 +685,7 @@ private module MarsDB { class Query extends NoSql::Query { QueryCall qc; - Query() { this = qc.getAQueryArgument().asExpr() } + Query() { this = qc.getAQueryArgument() } override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() } } @@ -770,7 +770,7 @@ private module Redis { RedisKeyArgument() { exists(string method, int argIndex | QuerySignatures::argumentIsAmbiguousKey(method, argIndex) and - this = redis().getMember(method).getParameter(argIndex).asSink().asExpr() + this = redis().getMember(method).getParameter(argIndex).asSink() ) } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/SQL.qll b/javascript/ql/lib/semmle/javascript/frameworks/SQL.qll index edd92614a2c3..0cc70b13381f 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/SQL.qll @@ -5,26 +5,26 @@ import javascript module SQL { - /** A string-valued expression that is interpreted as a SQL command. */ - abstract class SqlString extends Expr { } + /** A string-valued dataflow node that is interpreted as a SQL command. */ + abstract class SqlString extends DataFlow::Node { } private class SqlStringFromModel extends SqlString { - SqlStringFromModel() { this = ModelOutput::getASinkNode("sql-injection").asSink().asExpr() } + SqlStringFromModel() { this = ModelOutput::getASinkNode("sql-injection").asSink() } } /** - * An expression that sanitizes a string to make it safe to embed into + * An dataflow node that sanitizes a string to make it safe to embed into * a SQL command. */ - abstract class SqlSanitizer extends Expr { - Expr input; - Expr output; + abstract class SqlSanitizer extends DataFlow::Node { + DataFlow::Node input; + DataFlow::Node output; /** Gets the input expression being sanitized. */ - Expr getInput() { result = input } + DataFlow::Node getInput() { result = input } /** Gets the output expression containing the sanitized value. */ - Expr getOutput() { result = output } + DataFlow::Node getOutput() { result = output } } } @@ -90,13 +90,13 @@ private module MySql { /** An expression that is passed to the `query` method and hence interpreted as SQL. */ class QueryString extends SQL::SqlString { - QueryString() { this = any(QueryCall qc).getAQueryArgument().asExpr() } + QueryString() { this = any(QueryCall qc).getAQueryArgument() } } /** A call to the `escape` or `escapeId` method that performs SQL sanitization. */ - class EscapingSanitizer extends SQL::SqlSanitizer, MethodCallExpr { + class EscapingSanitizer extends SQL::SqlSanitizer instanceof API::CallNode { EscapingSanitizer() { - this = [mysql(), pool(), connection()].getMember(["escape", "escapeId"]).getACall().asExpr() and + this = [mysql(), pool(), connection()].getMember(["escape", "escapeId"]).getACall() and input = this.getArgument(0) and output = this } @@ -198,9 +198,9 @@ private module Postgres { /** An expression that is passed to the `query` method and hence interpreted as SQL. */ class QueryString extends SQL::SqlString { QueryString() { - this = any(QueryCall qc).getAQueryArgument().asExpr() + this = any(QueryCall qc).getAQueryArgument() or - this = API::moduleImport("pg-cursor").getParameter(0).asSink().asExpr() + this = API::moduleImport("pg-cursor").getParameter(0).asSink() } } @@ -349,7 +349,7 @@ private module Postgres { /** An expression that is interpreted as SQL by `pg-promise`. */ class PgPromiseQueryString extends SQL::SqlString { - PgPromiseQueryString() { this = any(PgPromiseQueryCall qc).getAQueryArgument().asExpr() } + PgPromiseQueryString() { this = any(PgPromiseQueryCall qc).getAQueryArgument() } } } @@ -398,7 +398,7 @@ private module Sqlite { /** An expression that is passed to the `query` method and hence interpreted as SQL. */ class QueryString extends SQL::SqlString { - QueryString() { this = any(QueryCall qc).getAQueryArgument().asExpr() } + QueryString() { this = any(QueryCall qc).getAQueryArgument() } } } @@ -470,7 +470,7 @@ private module MsSql { class QueryString extends SQL::SqlString { QueryString() { exists(DatabaseAccess dba | dba instanceof QueryTemplateExpr or dba instanceof QueryCall | - this = dba.getAQueryArgument().asExpr() + this = dba.getAQueryArgument() ) } } @@ -478,7 +478,7 @@ private module MsSql { /** An element of a query template, which is automatically sanitized. */ class QueryTemplateSanitizer extends SQL::SqlSanitizer { QueryTemplateSanitizer() { - this = any(QueryTemplateExpr qte).getAQueryArgument().asExpr() and + this = any(QueryTemplateExpr qte).getAQueryArgument() and input = this and output = this } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjectionCustomizations.qll index 7d4c59394403..50dd7fc00536 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjectionCustomizations.qll @@ -36,7 +36,5 @@ module NosqlInjection { } /** An expression interpreted as a NoSql query, viewed as a sink. */ - class NosqlQuerySink extends Sink, DataFlow::ValueNode { - override NoSql::Query astNode; - } + class NosqlQuerySink extends Sink instanceof NoSql::Query { } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjectionQuery.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjectionQuery.qll index ada9c57ad64c..be9b3bdee0a0 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjectionQuery.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjectionQuery.qll @@ -45,7 +45,7 @@ class Configuration extends TaintTracking::Configuration { inlbl = TaintedObject::label() and outlbl = TaintedObject::label() and exists(NoSql::Query query, DataFlow::SourceNode queryObj | - queryObj.flowsToExpr(query) and + queryObj.flowsTo(query) and queryObj.flowsTo(trg) and src = queryObj.getAPropertyWrite().getRhs() ) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjectionCustomizations.qll index 42ffe2ea3c3b..dd6f5d79ac8a 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjectionCustomizations.qll @@ -28,13 +28,11 @@ module SqlInjection { } /** An SQL expression passed to an API call that executes SQL. */ - class SqlInjectionExprSink extends Sink, DataFlow::ValueNode { - override SQL::SqlString astNode; - } + class SqlInjectionExprSink extends Sink instanceof SQL::SqlString { } /** An expression that sanitizes a value for the purposes of string based query injection. */ - class SanitizerExpr extends Sanitizer, DataFlow::ValueNode { - SanitizerExpr() { astNode = any(SQL::SqlSanitizer ss).getOutput() } + class SanitizerExpr extends Sanitizer { + SanitizerExpr() { this = any(SQL::SqlSanitizer ss).getOutput() } } /** An GraphQL expression passed to an API call that executes GraphQL. */ diff --git a/javascript/ql/test/tutorials/Introducing the JavaScript libraries/query20.qll b/javascript/ql/test/tutorials/Introducing the JavaScript libraries/query20.qll index 86c7ab712c5a..7b8b7843fc8b 100644 --- a/javascript/ql/test/tutorials/Introducing the JavaScript libraries/query20.qll +++ b/javascript/ql/test/tutorials/Introducing the JavaScript libraries/query20.qll @@ -1,5 +1,5 @@ import javascript query predicate test_query20(SQL::SqlString ss, string res) { - ss instanceof AddExpr and res = "Use templating instead of string concatenation." + ss.asExpr() instanceof AddExpr and res = "Use templating instead of string concatenation." } From 0c4f08c841782b371be0aba5f348319aa632223b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 4 Apr 2022 11:06:28 +0200 Subject: [PATCH 26/39] refactor the CredentialsExpr to be a dataflow node --- .../lib/semmle/javascript/frameworks/AWS.qll | 14 +++++------ .../semmle/javascript/frameworks/Azure.qll | 9 ++++--- .../javascript/frameworks/ClientRequests.qll | 6 ++--- .../semmle/javascript/frameworks/Connect.qll | 6 ++--- .../javascript/frameworks/Credentials.qll | 25 +++++++++++++++---- .../javascript/frameworks/CryptoLibraries.qll | 6 ++--- .../javascript/frameworks/DigitalOcean.qll | 6 ++--- .../semmle/javascript/frameworks/Express.qll | 6 ++--- .../lib/semmle/javascript/frameworks/JWT.qll | 8 +++--- .../semmle/javascript/frameworks/NoSQL.qll | 6 ++--- .../javascript/frameworks/NodeJSLib.qll | 17 +++++-------- .../semmle/javascript/frameworks/PkgCloud.qll | 4 +-- .../semmle/javascript/frameworks/Request.qll | 8 +++--- .../lib/semmle/javascript/frameworks/SQL.qll | 14 +++++------ .../HardcodedCredentialsCustomizations.qll | 8 +++--- .../frameworks/SQL/Credentials.ql | 2 +- 16 files changed, 74 insertions(+), 71 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/AWS.qll b/javascript/ql/lib/semmle/javascript/frameworks/AWS.qll index 120f47bb9527..1eac5888b955 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/AWS.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/AWS.qll @@ -8,19 +8,19 @@ module AWS { /** * Holds if the `i`th argument of `invk` is an object hash for `AWS.Config`. */ - private predicate takesConfigurationObject(InvokeExpr invk, int i) { + private predicate takesConfigurationObject(DataFlow::InvokeNode invk, int i) { exists(DataFlow::ModuleImportNode mod | mod.getPath() = "aws-sdk" | // `AWS.config.update(nd)` - invk = mod.getAPropertyRead("config").getAMemberCall("update").asExpr() and + invk = mod.getAPropertyRead("config").getAMemberCall("update") and i = 0 or exists(DataFlow::SourceNode cfg | cfg = mod.getAConstructorInvocation("Config") | // `new AWS.Config(nd)` - invk = cfg.asExpr() and + invk = cfg and i = 0 or // `var config = new AWS.Config(...); config.update(nd);` - invk = cfg.getAMemberCall("update").asExpr() and + invk = cfg.getAMemberCall("update") and i = 0 ) ) @@ -29,13 +29,13 @@ module AWS { /** * An expression that is used as an AWS config value: `{ accessKeyId: , secretAccessKey: }`. */ - class Credentials extends CredentialsExpr { + class Credentials extends CredentialsNode { string kind; Credentials() { - exists(string prop, InvokeExpr invk, int i | + exists(string prop, DataFlow::InvokeNode invk, int i | takesConfigurationObject(invk, i) and - invk.hasOptionArgument(i, prop, this) + this = invk.getOptionArgument(i, prop) | prop = "accessKeyId" and kind = "user name" or diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Azure.qll b/javascript/ql/lib/semmle/javascript/frameworks/Azure.qll index 5cfd2c8326dd..1527b655eddf 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Azure.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Azure.qll @@ -8,13 +8,14 @@ module Azure { /** * An expression that is used for authentication at Azure`. */ - class Credentials extends CredentialsExpr { + class Credentials extends CredentialsNode { string kind; Credentials() { - exists(CallExpr mce, string methodName | - (methodName = "loginWithUsernamePassword" or methodName = "loginWithServicePrincipalSecret") and - mce = DataFlow::moduleMember("ms-rest-azure", methodName).getACall().asExpr() + exists(DataFlow::CallNode mce | + mce = + DataFlow::moduleMember("ms-rest-azure", + ["loginWithUsernamePassword", "loginWithServicePrincipalSecret"]).getACall() | this = mce.getArgument(0) and kind = "user name" or diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll index 8e56a36b9bf8..e721508ff061 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll @@ -270,16 +270,16 @@ module ClientRequest { } /** An expression that is used as a credential in a request. */ - private class AuthorizationHeader extends CredentialsExpr { + private class AuthorizationHeader extends CredentialsNode { AuthorizationHeader() { exists(DataFlow::PropWrite write | write.getPropertyName().regexpMatch("(?i)authorization") | - this = write.getRhs().asExpr() + this = write.getRhs() ) or exists(DataFlow::MethodCallNode call | call.getMethodName() = ["append", "set"] | call.getNumArgument() = 2 and call.getArgument(0).getStringValue().regexpMatch("(?i)authorization") and - this = call.getArgument(1).asExpr() + this = call.getArgument(1) ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll b/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll index f662faf9a5b7..fe130648cd5f 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Connect.qll @@ -101,12 +101,12 @@ module Connect { } /** An expression that is passed as `basicAuthConnect(, )`. */ - class Credentials extends CredentialsExpr { + class Credentials extends CredentialsNode { string kind; Credentials() { - exists(CallExpr call | - call = DataFlow::moduleImport("basic-auth-connect").getAnInvocation().asExpr() and + exists(DataFlow::CallNode call | + call = DataFlow::moduleImport("basic-auth-connect").getAnInvocation() and call.getNumArgument() = 2 | this = call.getArgument(0) and kind = "user name" diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Credentials.qll b/javascript/ql/lib/semmle/javascript/frameworks/Credentials.qll index 164bc6e8f88a..ad27a0fe8289 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Credentials.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Credentials.qll @@ -6,10 +6,27 @@ import javascript /** + * DEPRECATED: Use `CredentialsNode` instead. * An expression whose value is used to supply credentials such * as a user name, a password, or a key. */ -abstract class CredentialsExpr extends Expr { +deprecated class CredentialsExpr extends Expr { + CredentialsNode node; + + CredentialsExpr() { node.asExpr() = this } + + /** + * Gets a description of the kind of credential this expression is used as, + * such as `"user name"`, `"password"`, `"key"`. + */ + deprecated string getCredentialsKind() { result = node.getCredentialsKind() } +} + +/** + * An expression whose value is used to supply credentials such + * as a user name, a password, or a key. + */ +abstract class CredentialsNode extends DataFlow::Node { /** * Gets a description of the kind of credential this expression is used as, * such as `"user name"`, `"password"`, `"key"`. @@ -17,12 +34,10 @@ abstract class CredentialsExpr extends Expr { abstract string getCredentialsKind(); } -private class CredentialsFromModel extends CredentialsExpr { +private class CredentialsFromModel extends CredentialsNode { string kind; - CredentialsFromModel() { - this = ModelOutput::getASinkNode("credentials[" + kind + "]").asSink().asExpr() - } + CredentialsFromModel() { this = ModelOutput::getASinkNode("credentials[" + kind + "]").asSink() } override string getCredentialsKind() { result = kind } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll b/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll index 6a583811bc30..9cf4dcfaacea 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll @@ -46,11 +46,9 @@ abstract class CryptographicKeyCreation extends DataFlow::Node { } /** - * A key used in a cryptographic algorithm, viewed as a `CredentialsExpr`. + * A key used in a cryptographic algorithm, viewed as a `CredentialsNode`. */ -class CryptographicKeyCredentialsExpr extends CredentialsExpr { - CryptographicKeyCredentialsExpr() { this = any(CryptographicKey k).asExpr() } - +class CryptographicKeyCredentialsExpr extends CredentialsNode instanceof CryptographicKey { override string getCredentialsKind() { result = "key" } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/DigitalOcean.qll b/javascript/ql/lib/semmle/javascript/frameworks/DigitalOcean.qll index 76077c930236..60d96a937c9c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/DigitalOcean.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/DigitalOcean.qll @@ -8,12 +8,12 @@ module DigitalOcean { /** * An expression that is used for authentication at DigitalOcean: `digitalocean.client()`. */ - class Credentials extends CredentialsExpr { + class Credentials extends CredentialsNode { string kind; Credentials() { - exists(CallExpr mce | - mce = DataFlow::moduleMember("digitalocean", "client").getACall().asExpr() + exists(DataFlow::CallNode mce | + mce = DataFlow::moduleMember("digitalocean", "client").getACall() | this = mce.getArgument(0) and kind = "token" ) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 754d528159e5..51c0b11e285b 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -995,7 +995,7 @@ module Express { } /** An expression that is passed as `expressBasicAuth({ users: { : }})`. */ - class Credentials extends CredentialsExpr { + class Credentials extends CredentialsNode { string kind; Credentials() { @@ -1006,9 +1006,9 @@ module Express { usersSrc.flowsTo(call.getOptionArgument(0, "users")) and usersSrc.flowsTo(pwn.getBase()) | - this = pwn.getPropertyNameExpr() and kind = "user name" + this = pwn.getPropertyNameExpr().flow() and kind = "user name" or - this = pwn.getRhs().asExpr() and kind = "password" + this = pwn.getRhs() and kind = "password" ) ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/JWT.qll b/javascript/ql/lib/semmle/javascript/frameworks/JWT.qll index 485684507707..aa0b157844cd 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/JWT.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/JWT.qll @@ -40,12 +40,10 @@ private module JsonWebToken { } /** - * The private key for a JWT as a `CredentialsExpr`. + * The private key for a JWT as a `CredentialsNode`. */ - private class JwtKey extends CredentialsExpr { - JwtKey() { - this = DataFlow::moduleMember("jsonwebtoken", "sign").getACall().getArgument(1).asExpr() - } + private class JwtKey extends CredentialsNode { + JwtKey() { this = DataFlow::moduleMember("jsonwebtoken", "sign").getACall().getArgument(1) } override string getCredentialsKind() { result = "key" } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll b/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll index 69d12d4d10af..7f49e0cd2293 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll @@ -496,13 +496,11 @@ private module Mongoose { /** * An expression passed to `mongoose.createConnection` to supply credentials. */ - class Credentials extends CredentialsExpr { + class Credentials extends CredentialsNode { string kind; Credentials() { - exists(string prop | - this = createConnection().getParameter(3).getMember(prop).asSink().asExpr() - | + exists(string prop | this = createConnection().getParameter(3).getMember(prop).asSink() | prop = "user" and kind = "user name" or prop = "pass" and kind = "password" diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll index f9cfe8552458..0c5fdbd6a15c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll @@ -426,11 +426,10 @@ module NodeJSLib { } /** An expression that is passed as `http.request({ auth: }, ...)`. */ - class Credentials extends CredentialsExpr { + class Credentials extends CredentialsNode { Credentials() { exists(string http | http = "http" or http = "https" | - this = - DataFlow::moduleMember(http, "request").getACall().getOptionArgument(0, "auth").asExpr() + this = DataFlow::moduleMember(http, "request").getACall().getOptionArgument(0, "auth") ) } @@ -1038,11 +1037,9 @@ module NodeJSLib { /** * A data flow node that is the username passed to the login callback provided by an HTTP or HTTPS request made by a Node.js process, for example `username` in `http.request(url).on('login', (res, cb) => {cb(username, password)})`. */ - private class ClientRequestLoginUsername extends CredentialsExpr { + private class ClientRequestLoginUsername extends CredentialsNode { ClientRequestLoginUsername() { - exists(ClientRequestLoginCallback callback | - this = callback.getACall().getArgument(0).asExpr() - ) + exists(ClientRequestLoginCallback callback | this = callback.getACall().getArgument(0)) } override string getCredentialsKind() { result = "Node.js http(s) client login username" } @@ -1051,11 +1048,9 @@ module NodeJSLib { /** * A data flow node that is the password passed to the login callback provided by an HTTP or HTTPS request made by a Node.js process, for example `password` in `http.request(url).on('login', (res, cb) => {cb(username, password)})`. */ - private class ClientRequestLoginPassword extends CredentialsExpr { + private class ClientRequestLoginPassword extends CredentialsNode { ClientRequestLoginPassword() { - exists(ClientRequestLoginCallback callback | - this = callback.getACall().getArgument(1).asExpr() - ) + exists(ClientRequestLoginCallback callback | this = callback.getACall().getArgument(1)) } override string getCredentialsKind() { result = "Node.js http(s) client login password" } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/PkgCloud.qll b/javascript/ql/lib/semmle/javascript/frameworks/PkgCloud.qll index ef1e5b9bdbb4..9255b31fb659 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/PkgCloud.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/PkgCloud.qll @@ -31,13 +31,13 @@ module PkgCloud { /** * An expression that is used for authentication through pkgcloud. */ - class Credentials extends CredentialsExpr { + class Credentials extends CredentialsNode { string kind; Credentials() { exists(string propertyName, DataFlow::InvokeNode invk, int i | takesConfigurationObject(invk, i) and - this = invk.getOptionArgument(0, propertyName).asExpr() + this = invk.getOptionArgument(0, propertyName) | /* * Catch-all support for the following providers: diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Request.qll b/javascript/ql/lib/semmle/javascript/frameworks/Request.qll index bd9fa71864fe..392a84c51a43 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Request.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Request.qll @@ -6,7 +6,7 @@ import javascript module Request { /** A credentials expression that is used for authentication. */ - class Credentials extends CredentialsExpr { + class Credentials extends CredentialsNode { string kind; Credentials() { @@ -20,9 +20,9 @@ module Request { action = mod.getAMemberCall(any(HTTP::RequestMethodName n).toLowerCase()) ) | - exists(MethodCallExpr auth, int argIndex | + exists(DataFlow::MethodCallNode auth, int argIndex | // request.get(url).auth('username', 'password', _, 'token'); - auth = action.getAMemberCall("auth").asExpr() and + auth = action.getAMemberCall("auth") and this = auth.getArgument(argIndex) | argIndex = 0 and kind = "user name" @@ -35,7 +35,7 @@ module Request { exists(DataFlow::ObjectLiteralNode auth, string propertyName | // request.get(url, { auth: {user: 'username', pass: 'password', bearer: 'token'}}) auth.flowsTo(action.getOptionArgument(1, "auth")) and - auth.hasPropertyWrite(propertyName, DataFlow::valueNode(this)) + auth.hasPropertyWrite(propertyName, this) | (propertyName = "user" or propertyName = "username") and kind = "user name" diff --git a/javascript/ql/lib/semmle/javascript/frameworks/SQL.qll b/javascript/ql/lib/semmle/javascript/frameworks/SQL.qll index 0cc70b13381f..a1499d09ea2c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/SQL.qll @@ -103,13 +103,13 @@ private module MySql { } /** An expression that is passed as user name or password to `mysql.createConnection`. */ - class Credentials extends CredentialsExpr { + class Credentials extends CredentialsNode { string kind; Credentials() { exists(API::Node callee, string prop | callee in [createConnection(), createPool()] and - this = callee.getParameter(0).getMember(prop).asSink().asExpr() and + this = callee.getParameter(0).getMember(prop).asSink() and ( prop = "user" and kind = "user name" or @@ -205,14 +205,14 @@ private module Postgres { } /** An expression that is passed as user name or password when creating a client or a pool. */ - class Credentials extends CredentialsExpr { + class Credentials extends CredentialsNode { string kind; Credentials() { exists(string prop | - this = [newClient(), newPool()].getParameter(0).getMember(prop).asSink().asExpr() + this = [newClient(), newPool()].getParameter(0).getMember(prop).asSink() or - this = pgPromise().getParameter(0).getMember(prop).asSink().asExpr() + this = pgPromise().getParameter(0).getMember(prop).asSink() | prop = "user" and kind = "user name" or @@ -485,7 +485,7 @@ private module MsSql { } /** An expression that is passed as user name or password when creating a client or a pool. */ - class Credentials extends CredentialsExpr { + class Credentials extends CredentialsNode { string kind; Credentials() { @@ -495,7 +495,7 @@ private module MsSql { or callee = mssql().getMember("ConnectionPool") ) and - this = callee.getParameter(0).getMember(prop).asSink().asExpr() and + this = callee.getParameter(0).getMember(prop).asSink() and ( prop = "user" and kind = "user name" or diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/HardcodedCredentialsCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/HardcodedCredentialsCustomizations.qll index 6ad3b1a8853c..5e43e34aa8a0 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/HardcodedCredentialsCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/HardcodedCredentialsCustomizations.qll @@ -33,12 +33,10 @@ module HardcodedCredentials { } /** - * A subclass of `Sink` that includes every `CredentialsExpr` + * A subclass of `Sink` that includes every `CredentialsNode` * as a credentials sink. */ - class DefaultCredentialsSink extends Sink, DataFlow::ValueNode { - override CredentialsExpr astNode; - - override string getKind() { result = astNode.getCredentialsKind() } + class DefaultCredentialsSink extends Sink instanceof CredentialsNode { + override string getKind() { result = super.getCredentialsKind() } } } diff --git a/javascript/ql/test/library-tests/frameworks/SQL/Credentials.ql b/javascript/ql/test/library-tests/frameworks/SQL/Credentials.ql index 5e32f342c200..2451052eaf4c 100644 --- a/javascript/ql/test/library-tests/frameworks/SQL/Credentials.ql +++ b/javascript/ql/test/library-tests/frameworks/SQL/Credentials.ql @@ -1,4 +1,4 @@ import javascript -from CredentialsExpr ce +from CredentialsNode ce select ce, ce.getCredentialsKind() From b4968eb6458900c6b295ecab2193b3f16a673ffe Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 4 Apr 2022 11:14:48 +0200 Subject: [PATCH 27/39] refactor the SensitiveExpr to be a dataflow node --- .../javascript/frameworks/CookieLibraries.qll | 2 +- .../javascript/security/SensitiveActions.qll | 38 +++++++++++++------ .../BrokenCryptoAlgorithmCustomizations.qll | 6 +-- .../CleartextStorageCustomizations.qll | 8 ++-- ...InsufficientPasswordHashCustomizations.qll | 8 ++-- .../PostMessageStarCustomizations.qll | 4 +- .../Security/CWE-327/BrokenCryptoAlgorithm.ql | 2 +- .../src/Security/CWE-598/SensitiveGetQuery.ql | 4 +- .../library-tests/SensitiveActions/tests.ql | 2 +- 9 files changed, 40 insertions(+), 34 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/CookieLibraries.qll b/javascript/ql/lib/semmle/javascript/frameworks/CookieLibraries.qll index 71b7254fbbcd..1efc7da5dc49 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/CookieLibraries.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/CookieLibraries.qll @@ -76,7 +76,7 @@ private predicate canHaveSensitiveCookie(DataFlow::Node node) { HeuristicNames::nameIndicatesSensitiveData([s, getCookieName(s)], _) ) or - node.asExpr() instanceof SensitiveExpr + node instanceof SensitiveNode } /** diff --git a/javascript/ql/lib/semmle/javascript/security/SensitiveActions.qll b/javascript/ql/lib/semmle/javascript/security/SensitiveActions.qll index dfa1ef10a805..504ebad9e35f 100644 --- a/javascript/ql/lib/semmle/javascript/security/SensitiveActions.qll +++ b/javascript/ql/lib/semmle/javascript/security/SensitiveActions.qll @@ -13,9 +13,25 @@ import javascript import semmle.javascript.security.internal.SensitiveDataHeuristics private import HeuristicNames +/** + * DEPRECATED: Use `SensitiveNode` instead. + * An expression that might contain sensitive data. + */ +deprecated class SensitiveExpr extends Expr { + SensitiveNode node; + + SensitiveExpr() { node.asExpr() = this } + + /** Gets a human-readable description of this expression for use in alert messages. */ + deprecated string describe() { result = node.describe() } + + /** Gets a classification of the kind of sensitive data this expression might contain. */ + deprecated SensitiveDataClassification getClassification() { result = node.getClassification() } +} + /** An expression that might contain sensitive data. */ cached -abstract class SensitiveExpr extends Expr { +abstract class SensitiveNode extends DataFlow::Node { /** Gets a human-readable description of this expression for use in alert messages. */ cached abstract string describe(); @@ -26,33 +42,33 @@ abstract class SensitiveExpr extends Expr { } /** A function call that might produce sensitive data. */ -class SensitiveCall extends SensitiveExpr, InvokeExpr { +class SensitiveCall extends SensitiveNode instanceof DataFlow::InvokeNode { SensitiveDataClassification classification; SensitiveCall() { - classification = this.getCalleeName().(SensitiveDataFunctionName).getClassification() + classification = super.getCalleeName().(SensitiveDataFunctionName).getClassification() or // This is particularly to pick up methods with an argument like "password", which // may indicate a lookup. - exists(string s | this.getAnArgument().mayHaveStringValue(s) | + exists(string s | super.getAnArgument().mayHaveStringValue(s) | nameIndicatesSensitiveData(s, classification) ) } - override string describe() { result = "a call to " + this.getCalleeName() } + override string describe() { result = "a call to " + super.getCalleeName() } override SensitiveDataClassification getClassification() { result = classification } } /** An access to a variable or property that might contain sensitive data. */ -abstract class SensitiveVariableAccess extends SensitiveExpr { +abstract class SensitiveVariableAccess extends SensitiveNode { string name; SensitiveVariableAccess() { - this.(VarAccess).getName() = name + this.asExpr().(VarAccess).getName() = name or exists(DataFlow::PropRead pr | - this = pr.asExpr() and + this = pr and pr.getPropertyName() = name ) } @@ -173,10 +189,8 @@ class ProtectCall extends DataFlow::CallNode { } /** An expression that might contain a clear-text password. */ -class CleartextPasswordExpr extends SensitiveExpr { - CleartextPasswordExpr() { - this.(SensitiveExpr).getClassification() = SensitiveDataClassification::password() - } +class CleartextPasswordExpr extends SensitiveNode { + CleartextPasswordExpr() { this.getClassification() = SensitiveDataClassification::password() } override string describe() { none() } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithmCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithmCustomizations.qll index 4149dd84c283..832f811f67b9 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithmCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithmCustomizations.qll @@ -30,10 +30,8 @@ module BrokenCryptoAlgorithm { * A sensitive expression, viewed as a data flow source for sensitive information * in broken or weak cryptographic algorithms. */ - class SensitiveExprSource extends Source, DataFlow::ValueNode { - override SensitiveExpr astNode; - - override string describe() { result = astNode.describe() } + class SensitiveExprSource extends Source instanceof SensitiveNode { + override string describe() { result = SensitiveNode.super.describe() } } /** diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll index 60c7aad426ec..ef2090b3dead 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextStorageCustomizations.qll @@ -30,15 +30,13 @@ module CleartextStorage { * A sensitive expression, viewed as a data flow source for cleartext storage * of sensitive information. */ - class SensitiveExprSource extends Source, DataFlow::ValueNode { - override SensitiveExpr astNode; - + class SensitiveExprSource extends Source instanceof SensitiveNode { SensitiveExprSource() { // storing user names or account names in plaintext isn't usually a problem - astNode.getClassification() != SensitiveDataClassification::id() + super.getClassification() != SensitiveDataClassification::id() } - override string describe() { result = astNode.describe() } + override string describe() { result = SensitiveNode.super.describe() } } /** A call to any function whose name suggests that it encodes or encrypts its arguments. */ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHashCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHashCustomizations.qll index 83e07c177cfc..1697d55fe0b1 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHashCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHashCustomizations.qll @@ -30,14 +30,12 @@ module InsufficientPasswordHash { * A potential clear-text password, considered as a source for password hashing * with insufficient computational effort. */ - class CleartextPasswordSource extends Source, DataFlow::ValueNode { - override SensitiveExpr astNode; - + class CleartextPasswordSource extends Source instanceof SensitiveNode { CleartextPasswordSource() { - astNode.getClassification() = SensitiveDataClassification::password() + super.getClassification() = SensitiveDataClassification::password() } - override string describe() { result = astNode.describe() } + override string describe() { result = SensitiveNode.super.describe() } } /** diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/PostMessageStarCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/PostMessageStarCustomizations.qll index 3f8b7c7f846e..b35d564bcaf2 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/PostMessageStarCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/PostMessageStarCustomizations.qll @@ -41,9 +41,7 @@ module PostMessageStar { * A sensitive expression, viewed as a data flow source for cross-window communication * with unrestricted origin. */ - class SensitiveExprSource extends Source, DataFlow::ValueNode { - override SensitiveExpr astNode; - } + class SensitiveExprSource extends Source instanceof SensitiveNode { } /** A call to any function whose name suggests that it encodes or encrypts its arguments. */ class ProtectSanitizer extends Sanitizer { diff --git a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql index 99e5f937f5bb..3cdd8bb3f31c 100644 --- a/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql +++ b/javascript/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql @@ -19,7 +19,7 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) and - not source.getNode().asExpr() instanceof CleartextPasswordExpr // flagged by js/insufficient-password-hash + not source.getNode() instanceof CleartextPasswordExpr // flagged by js/insufficient-password-hash select sink.getNode(), source, sink, "Sensitive data from $@ is used in a broken or weak cryptographic algorithm.", source.getNode(), source.getNode().(Source).describe() diff --git a/javascript/ql/src/Security/CWE-598/SensitiveGetQuery.ql b/javascript/ql/src/Security/CWE-598/SensitiveGetQuery.ql index ace28997ccc2..89aeb49b6f41 100644 --- a/javascript/ql/src/Security/CWE-598/SensitiveGetQuery.ql +++ b/javascript/ql/src/Security/CWE-598/SensitiveGetQuery.ql @@ -15,13 +15,13 @@ import javascript from Routing::RouteSetup setup, Routing::RouteHandler handler, HTTP::RequestInputAccess input, - SensitiveExpr sensitive + SensitiveNode sensitive where setup.getOwnHttpMethod() = "GET" and setup.getAChild+() = handler and input.getRouteHandler() = handler.getFunction() and input.getKind() = "parameter" and - input.(DataFlow::SourceNode).flowsToExpr(sensitive) and + input.(DataFlow::SourceNode).flowsTo(sensitive) and not sensitive.getClassification() = SensitiveDataClassification::id() select input, "$@ for GET requests uses query parameter as sensitive data.", handler, "Route handler" diff --git a/javascript/ql/test/library-tests/SensitiveActions/tests.ql b/javascript/ql/test/library-tests/SensitiveActions/tests.ql index 7adfe2121d3e..e1cd2cbd095b 100644 --- a/javascript/ql/test/library-tests/SensitiveActions/tests.ql +++ b/javascript/ql/test/library-tests/SensitiveActions/tests.ql @@ -20,4 +20,4 @@ query predicate processTermination(NodeJSLib::ProcessTermination term) { any() } query predicate sensitiveAction(SensitiveAction ac) { any() } -query predicate sensitiveExpr(SensitiveExpr e) { any() } +query predicate sensitiveExpr(SensitiveNode e) { any() } From 6697dd1396456d627e8791109ab5add35b611681 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 31 Mar 2022 14:18:59 +0200 Subject: [PATCH 28/39] rewrite some expression based predicates in `TaintTracking.qll` --- .../javascript/dataflow/TaintTracking.qll | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll index ec38e760916a..5be11df1b8fb 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll @@ -546,16 +546,16 @@ module TaintTracking { */ private class ComputedPropWriteTaintStep extends SharedTaintStep { override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(AssignExpr assgn, IndexExpr idx, DataFlow::SourceNode obj | - assgn.getTarget() = idx and - obj.flowsToExpr(idx.getBase()) and - not exists(idx.getPropertyName()) and - pred = DataFlow::valueNode(assgn.getRhs()) and + exists(DataFlow::PropWrite assgn, DataFlow::SourceNode obj | + not exists(assgn.getPropertyName()) and + not assgn.getWriteNode() instanceof Property and // not a write inside an object literal + pred = assgn.getRhs() and + assgn = obj.getAPropertyWrite() and succ = obj | obj instanceof DataFlow::ObjectLiteralNode or - obj.getAPropertyRead("length").flowsToExpr(idx.getPropertyNameExpr()) + obj.getAPropertyRead("length").flowsToExpr(assgn.getPropertyNameExpr()) ) } } @@ -580,8 +580,8 @@ module TaintTracking { override predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node target) { exists(DataFlow::ValueNode succ | target = succ | // string operations that propagate taint - exists(string name | name = succ.getAstNode().(MethodCallExpr).getMethodName() | - pred.asExpr() = succ.getAstNode().(MethodCallExpr).getReceiver() and + exists(string name | name = succ.(DataFlow::MethodCallNode).getMethodName() | + pred = succ.(DataFlow::MethodCallNode).getReceiver() and ( // sorted, interesting, properties of String.prototype name = @@ -600,7 +600,7 @@ module TaintTracking { name = "join" ) or - exists(int i | pred.asExpr() = succ.getAstNode().(MethodCallExpr).getArgument(i) | + exists(int i | pred = succ.(DataFlow::MethodCallNode).getArgument(i) | name = "concat" or name = ["replace", "replaceAll"] and i = 1 @@ -615,10 +615,10 @@ module TaintTracking { ) or // String.fromCharCode and String.fromCodePoint - exists(int i, MethodCallExpr mce | - mce = succ.getAstNode() and - pred.asExpr() = mce.getArgument(i) and - (mce.getMethodName() = "fromCharCode" or mce.getMethodName() = "fromCodePoint") + exists(int i, DataFlow::MethodCallNode mcn | + mcn = succ and + pred = mcn.getArgument(i) and + mcn.getMethodName() = ["fromCharCode", "fromCodePoint"] ) or // `(encode|decode)URI(Component)?` propagate taint @@ -744,11 +744,11 @@ module TaintTracking { * the parameters in `input`. */ predicate isUrlSearchParams(DataFlow::SourceNode params, DataFlow::Node input) { - exists(DataFlow::GlobalVarRefNode urlSearchParams, NewExpr newUrlSearchParams | + exists(DataFlow::GlobalVarRefNode urlSearchParams, DataFlow::NewNode newUrlSearchParams | urlSearchParams.getName() = "URLSearchParams" and - newUrlSearchParams = urlSearchParams.getAnInstantiation().asExpr() and - params.asExpr() = newUrlSearchParams and - input.asExpr() = newUrlSearchParams.getArgument(0) + newUrlSearchParams = urlSearchParams.getAnInstantiation() and + params = newUrlSearchParams and + input = newUrlSearchParams.getArgument(0) ) } From 5b61db9fd3d4083a714b2ecd5ed322e302e1db1e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 31 Mar 2022 15:15:04 +0200 Subject: [PATCH 29/39] refactor miscellaneous expression uses to dataflow nodes --- .../adaptivethreatmodeling/CoreKnowledge.qll | 2 +- .../EndpointFeatures.qll | 2 +- .../lib/semmle/javascript/dataflow/Nodes.qll | 8 +++++++ .../javascript/dataflow/TaintTracking.qll | 18 ++++++--------- .../frameworks/AngularJS/AngularJSCore.qll | 22 +++++++++---------- .../AngularJS/ServiceDefinitions.qll | 6 ++--- .../semmle/javascript/frameworks/Express.qll | 2 +- .../lib/semmle/javascript/frameworks/Next.qll | 7 +++--- ...APIUsedWithUntrustedDataCustomizations.qll | 2 +- 9 files changed, 35 insertions(+), 34 deletions(-) diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/CoreKnowledge.qll b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/CoreKnowledge.qll index cba8fc8fab77..e569fb3dc960 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/CoreKnowledge.qll +++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/CoreKnowledge.qll @@ -175,7 +175,7 @@ predicate isOtherModeledArgument(DataFlow::Node n, FilteringReason reason) { or n instanceof CryptographicKey and reason instanceof CryptographicKeyReason or - any(CryptographicOperation op).getInput().flow() = n and + any(CryptographicOperation op).getInput() = n and reason instanceof CryptographicOperationFlowReason or exists(DataFlow::CallNode call | n = call.getAnArgument() | diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll index f146f569684d..f0ec79df0cf5 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll +++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll @@ -144,7 +144,7 @@ private module AccessPaths { not param = base.getReceiver() | result = param and - name = param.asSource().asExpr().(Parameter).getName() + name = param.asSource().(DataFlow::ParameterNode).getName() or param.asSource().asExpr() instanceof DestructuringPattern and result = param.getMember(name) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll index 29509e36f885..eee2e7a26ac7 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll @@ -562,6 +562,14 @@ class ObjectLiteralNode extends DataFlow::ValueNode, DataFlow::SourceNode { DataFlow::FunctionNode getPropertySetter(string name) { result = astNode.getPropertyByName(name).(PropertySetter).getInit().flow() } + + /** Gets the value of a computed property name of this object literal, such as `x` in `{[x]: 1}` */ + DataFlow::Node getAComputedPropertyName() { + exists(Property prop | prop = astNode.getAProperty() | + prop.isComputed() and + result = prop.getNameExpr().flow() + ) + } } /** diff --git a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll index 5be11df1b8fb..d7f620f64315 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll @@ -482,17 +482,13 @@ module TaintTracking { */ private class HeapTaintStep extends SharedTaintStep { override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(Expr e, Expr f | e = succ.asExpr() and f = pred.asExpr() | - exists(Property prop | e.(ObjectExpr).getAProperty() = prop | - prop.isComputed() and f = prop.getNameExpr() - ) - or - // spreading a tainted object into an object literal gives a tainted object - e.(ObjectExpr).getAProperty().(SpreadProperty).getInit().(SpreadElement).getOperand() = f - or - // spreading a tainted value into an array literal gives a tainted array - e.(ArrayExpr).getAnElement().(SpreadElement).getOperand() = f - ) + succ.(DataFlow::ObjectLiteralNode).getAComputedPropertyName() = pred + or + // spreading a tainted object into an object literal gives a tainted object + succ.(DataFlow::ObjectLiteralNode).getASpreadProperty() = pred + or + // spreading a tainted value into an array literal gives a tainted array + succ.(DataFlow::ArrayCreationNode).getASpreadArgument() = pred or // arrays with tainted elements and objects with tainted property names are tainted succ.(DataFlow::ArrayCreationNode).getAnElement() = pred and diff --git a/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll b/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll index e00d7adad9f8..e26a71bcdd48 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll @@ -68,7 +68,7 @@ private class TrackStringsInAngularCode extends DataFlow::SourceNode::Range, Dat */ private DataFlow::CallNode angularModuleCall(string name) { result = angular().getAMemberCall("module") and - result.getArgument(0).asExpr().mayHaveStringValue(name) + result.getArgument(0).mayHaveStringValue(name) } /** @@ -280,7 +280,7 @@ abstract class CustomDirective extends DirectiveInstance { InjectableFunction getController() { result = this.getMember("controller") } /** Gets the template URL of this directive, if any. */ - string getTemplateUrl() { this.getMember("templateUrl").asExpr().mayHaveStringValue(result) } + string getTemplateUrl() { this.getMember("templateUrl").mayHaveStringValue(result) } /** * Gets a template file for this directive, if any. @@ -298,9 +298,7 @@ abstract class CustomDirective extends DirectiveInstance { else result = DirectiveInstance.super.getAScope() } - private string getRestrictionString() { - this.getMember("restrict").asExpr().mayHaveStringValue(result) - } + private string getRestrictionString() { this.getMember("restrict").mayHaveStringValue(result) } private predicate hasTargetType(DirectiveTargetType type) { not exists(this.getRestrictionString()) or @@ -383,10 +381,12 @@ class GeneralDirective extends CustomDirective, MkCustomDirective { override DataFlow::FunctionNode getALinkFunction() { result = this.getLinkFunction(_) } override predicate bindsToController() { - this.getMemberInit("bindToController").asExpr().mayHaveBooleanValue(true) + this.getMemberInit("bindToController").mayHaveBooleanValue(true) } - override predicate hasIsolateScope() { this.getMember("scope").asExpr() instanceof ObjectExpr } + override predicate hasIsolateScope() { + this.getMember("scope") instanceof DataFlow::ObjectLiteralNode + } } /** @@ -930,9 +930,7 @@ class RouteSetup extends DataFlow::CallNode, DependencyInjection { | result = controllerProperty or - exists(ControllerDefinition def | - controllerProperty.asExpr().mayHaveStringValue(def.getName()) - | + exists(ControllerDefinition def | controllerProperty.mayHaveStringValue(def.getName()) | result = def.getAService() ) ) @@ -1012,7 +1010,7 @@ private class RouteInstantiatedController extends Controller { override predicate boundTo(DOM::ElementDefinition elem) { exists(string url, HTML::HtmlFile template | - setup.getRouteParam("templateUrl").asExpr().mayHaveStringValue(url) and + setup.getRouteParam("templateUrl").mayHaveStringValue(url) and template.getAbsolutePath().regexpMatch(".*\\Q" + url + "\\E") and elem.getFile() = template ) @@ -1020,7 +1018,7 @@ private class RouteInstantiatedController extends Controller { override predicate boundToAs(DOM::ElementDefinition elem, string name) { this.boundTo(elem) and - setup.getRouteParam("controllerAs").asExpr().mayHaveStringValue(name) + setup.getRouteParam("controllerAs").mayHaveStringValue(name) } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll b/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll index e13142fdc89d..2194de9e667d 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll @@ -244,7 +244,7 @@ abstract class RecipeDefinition extends DataFlow::CallNode, CustomServiceDefinit this = moduleRef(_).getAMethodCall(methodName) or this = builtinServiceRef("$provide").getAMethodCall(methodName) ) and - getArgument(0).asExpr().mayHaveStringValue(name) + getArgument(0).mayHaveStringValue(name) } override string getName() { result = name } @@ -281,7 +281,7 @@ private predicate isCustomServiceDefinitionOnModule( DataFlow::Node factoryFunction ) { mce = moduleRef(_).getAMethodCall(moduleMethodName) and - mce.getArgument(0).asExpr().mayHaveStringValue(serviceName) and + mce.getArgument(0).mayHaveStringValue(serviceName) and factoryFunction = mce.getArgument(1) } @@ -296,7 +296,7 @@ private predicate isCustomServiceDefinitionOnProvider( factoryArgument = mce.getOptionArgument(0, serviceName) or mce.getNumArgument() = 2 and - mce.getArgument(0).asExpr().mayHaveStringValue(serviceName) and + mce.getArgument(0).mayHaveStringValue(serviceName) and factoryArgument = mce.getArgument(1) ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 51c0b11e285b..84f7a2eee346 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -959,7 +959,7 @@ module Express { * Example: `fun` for `router1.use(fun)` or `router.use("/route", fun)` */ HTTP::RouteHandler getARouteHandler() { - result.(DataFlow::SourceNode).flowsToExpr(this.getARouteSetup().getAnArgument().asExpr()) + result.(DataFlow::SourceNode).flowsTo(this.getARouteSetup().getAnArgument()) } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Next.qll b/javascript/ql/lib/semmle/javascript/frameworks/Next.qll index 604577c6a706..495543eb1b36 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Next.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Next.qll @@ -35,11 +35,10 @@ module NextJS { */ Module getAModuleWithFallbackPaths() { result = getAPagesModule() and - exists(DataFlow::FunctionNode staticPaths, Expr fallback | + exists(DataFlow::FunctionNode staticPaths, DataFlow::Node fallback | staticPaths = result.getAnExportedValue("getStaticPaths").getAFunctionValue() and - fallback = - staticPaths.getAReturn().getALocalSource().getAPropertyWrite("fallback").getRhs().asExpr() and - not fallback.(BooleanLiteral).getValue() = "false" + fallback = staticPaths.getAReturn().getALocalSource().getAPropertyWrite("fallback").getRhs() and + not fallback.mayHaveBooleanValue(false) ) } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll index fb663a755ed4..785677488e4e 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll @@ -165,7 +165,7 @@ module ExternalApiUsedWithUntrustedData { not param = base.getReceiver() | result = param and - name = param.asSource().asExpr().(Parameter).getName() + name = param.asSource().(DataFlow::ParameterNode).getName() or param.asSource().asExpr() instanceof DestructuringPattern and result = param.getMember(name) From 833480d5c58319978fc064d651cbafbaa24058e6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 4 Apr 2022 10:54:36 +0200 Subject: [PATCH 30/39] add change note --- javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md diff --git a/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md b/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md new file mode 100644 index 000000000000..3f69da548aa8 --- /dev/null +++ b/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* Many library models have been rewritten to use dataflow nodes instead of the AST. + These changes include some renamings where the old name is still available as a deprecated feature. \ No newline at end of file From 73a936104a52d61b8a43d454fcc1cf25c7534d41 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 Apr 2022 14:28:05 +0200 Subject: [PATCH 31/39] fix typo in qldoc Co-authored-by: Asger F --- javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll index 1d89668fa7a6..63d6929a0da2 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll @@ -206,7 +206,7 @@ class DomPropertyWrite extends DataFlow::Node instanceof DataFlow::PropWrite { } /** - * Gets the data flow node corresponding to the value being written, + * Gets the data flow node corresponding to the value being written. */ DataFlow::Node getRhs() { result = super.getRhs() } } From 74a79f862291cc1d1e1fb293b193b79af24d69b3 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 Apr 2022 14:28:36 +0200 Subject: [PATCH 32/39] simplify int check Co-authored-by: Asger F --- .../security/dataflow/ClientSideUrlRedirectCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll index e0eb92981c0c..4c6ad8b0ee9e 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll @@ -67,7 +67,7 @@ module ClientSideUrlRedirect { methodName = StringOps::substringMethodName() and // exclude `location.href.substring(0, ...)` and similar, which can // never refer to the query string - not mcn.getArgument(0).asExpr().(NumberLiteral).getIntValue() = 0 + not mcn.getArgument(0).getIntValue() = 0 ) or exists(DataFlow::MethodCallNode mcn | From e387ebaedd2ec330760a829bc019c89063769dd1 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 Apr 2022 14:23:10 +0200 Subject: [PATCH 33/39] add `domNode.innerHTML += sink` as a DOM sink --- .../ql/lib/semmle/javascript/security/dataflow/DOM.qll | 6 +++++- .../Security/CWE-079/DomBasedXss/Xss.expected | 10 ++++++++++ .../DomBasedXss/XssWithAdditionalSources.expected | 9 +++++++++ .../Security/CWE-079/DomBasedXss/classnames.js | 2 ++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll index 63d6929a0da2..45a840645174 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll @@ -208,7 +208,11 @@ class DomPropertyWrite extends DataFlow::Node instanceof DataFlow::PropWrite { /** * Gets the data flow node corresponding to the value being written. */ - DataFlow::Node getRhs() { result = super.getRhs() } + DataFlow::Node getRhs() { + result = super.getRhs() + or + result = super.getWriteNode().(AssignAddExpr).getRhs().flow() + } } /** diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected index 3af55bfd598c..3effc99fcb3f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected @@ -116,6 +116,11 @@ nodes | classnames.js:15:47:15:63 | clsx(window.name) | | classnames.js:15:52:15:62 | window.name | | classnames.js:15:52:15:62 | window.name | +| classnames.js:17:32:17:79 | `` | +| classnames.js:17:32:17:79 | `` | +| classnames.js:17:48:17:64 | clsx(window.name) | +| classnames.js:17:53:17:63 | window.name | +| classnames.js:17:53:17:63 | window.name | | clipboard.ts:8:11:8:51 | html | | clipboard.ts:8:11:8:51 | html | | clipboard.ts:8:18:8:51 | clipboa ... /html') | @@ -1187,6 +1192,10 @@ edges | classnames.js:15:47:15:63 | clsx(window.name) | classnames.js:15:31:15:78 | `` | | classnames.js:15:52:15:62 | window.name | classnames.js:15:47:15:63 | clsx(window.name) | | classnames.js:15:52:15:62 | window.name | classnames.js:15:47:15:63 | clsx(window.name) | +| classnames.js:17:48:17:64 | clsx(window.name) | classnames.js:17:32:17:79 | `` | +| classnames.js:17:48:17:64 | clsx(window.name) | classnames.js:17:32:17:79 | `` | +| classnames.js:17:53:17:63 | window.name | classnames.js:17:48:17:64 | clsx(window.name) | +| classnames.js:17:53:17:63 | window.name | classnames.js:17:48:17:64 | clsx(window.name) | | clipboard.ts:8:11:8:51 | html | clipboard.ts:15:25:15:28 | html | | clipboard.ts:8:11:8:51 | html | clipboard.ts:15:25:15:28 | html | | clipboard.ts:8:11:8:51 | html | clipboard.ts:15:25:15:28 | html | @@ -2182,6 +2191,7 @@ edges | classnames.js:11:31:11:79 | `` | classnames.js:10:45:10:55 | window.name | classnames.js:11:31:11:79 | `` | Cross-site scripting vulnerability due to $@. | classnames.js:10:45:10:55 | window.name | user-provided value | | classnames.js:13:31:13:83 | `` | classnames.js:13:57:13:67 | window.name | classnames.js:13:31:13:83 | `` | Cross-site scripting vulnerability due to $@. | classnames.js:13:57:13:67 | window.name | user-provided value | | classnames.js:15:31:15:78 | `` | classnames.js:15:52:15:62 | window.name | classnames.js:15:31:15:78 | `` | Cross-site scripting vulnerability due to $@. | classnames.js:15:52:15:62 | window.name | user-provided value | +| classnames.js:17:32:17:79 | `` | classnames.js:17:53:17:63 | window.name | classnames.js:17:32:17:79 | `` | Cross-site scripting vulnerability due to $@. | classnames.js:17:53:17:63 | window.name | user-provided value | | clipboard.ts:15:25:15:28 | html | clipboard.ts:8:18:8:51 | clipboa ... /html') | clipboard.ts:15:25:15:28 | html | Cross-site scripting vulnerability due to $@. | clipboard.ts:8:18:8:51 | clipboa ... /html') | user-provided value | | clipboard.ts:24:23:24:58 | e.clipb ... /html') | clipboard.ts:24:23:24:58 | e.clipb ... /html') | clipboard.ts:24:23:24:58 | e.clipb ... /html') | Cross-site scripting vulnerability due to $@. | clipboard.ts:24:23:24:58 | e.clipb ... /html') | user-provided value | | clipboard.ts:29:19:29:54 | e.clipb ... /html') | clipboard.ts:29:19:29:54 | e.clipb ... /html') | clipboard.ts:29:19:29:54 | e.clipb ... /html') | Cross-site scripting vulnerability due to $@. | clipboard.ts:29:19:29:54 | e.clipb ... /html') | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected index f8f72db0b4a9..fa65ccbe3dff 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected @@ -116,6 +116,11 @@ nodes | classnames.js:15:47:15:63 | clsx(window.name) | | classnames.js:15:52:15:62 | window.name | | classnames.js:15:52:15:62 | window.name | +| classnames.js:17:32:17:79 | `` | +| classnames.js:17:32:17:79 | `` | +| classnames.js:17:48:17:64 | clsx(window.name) | +| classnames.js:17:53:17:63 | window.name | +| classnames.js:17:53:17:63 | window.name | | clipboard.ts:8:11:8:51 | html | | clipboard.ts:8:11:8:51 | html | | clipboard.ts:8:18:8:51 | clipboa ... /html') | @@ -1237,6 +1242,10 @@ edges | classnames.js:15:47:15:63 | clsx(window.name) | classnames.js:15:31:15:78 | `` | | classnames.js:15:52:15:62 | window.name | classnames.js:15:47:15:63 | clsx(window.name) | | classnames.js:15:52:15:62 | window.name | classnames.js:15:47:15:63 | clsx(window.name) | +| classnames.js:17:48:17:64 | clsx(window.name) | classnames.js:17:32:17:79 | `` | +| classnames.js:17:48:17:64 | clsx(window.name) | classnames.js:17:32:17:79 | `` | +| classnames.js:17:53:17:63 | window.name | classnames.js:17:48:17:64 | clsx(window.name) | +| classnames.js:17:53:17:63 | window.name | classnames.js:17:48:17:64 | clsx(window.name) | | clipboard.ts:8:11:8:51 | html | clipboard.ts:15:25:15:28 | html | | clipboard.ts:8:11:8:51 | html | clipboard.ts:15:25:15:28 | html | | clipboard.ts:8:11:8:51 | html | clipboard.ts:15:25:15:28 | html | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/classnames.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/classnames.js index e18f7844f68e..a0e75045a2eb 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/classnames.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/classnames.js @@ -13,4 +13,6 @@ function main() { document.body.innerHTML = `Hello`; // NOT OK document.body.innerHTML = `Hello`; // OK document.body.innerHTML = `Hello`; // NOT OK + + document.body.innerHTML += `Hello`; // NOT OK } From 26f5643f3ee49e672f8d6bf8201c266f6627d145 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 Apr 2022 14:27:18 +0200 Subject: [PATCH 34/39] update the deprecation notice of `RouteExpr` such that it points to public APIs --- javascript/ql/lib/semmle/javascript/frameworks/Express.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 84f7a2eee346..1094a9fa4f98 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -56,7 +56,7 @@ module Express { } /** - * DEPRECATED: Use `isRouter()` instead. + * DEPRECATED: Use `RouterDefinition.ref()` or `RouteSetup` instead. * An expression that refers to a route. */ deprecated class RouteExpr extends MethodCallExpr { From e64f96c1ceb3fadf36ca040ae8731b517334341a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 5 Apr 2022 14:40:58 +0200 Subject: [PATCH 35/39] rewrite the change-note to emphasise that the change is potentially breaking --- javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md b/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md index 3f69da548aa8..373dc1fda00f 100644 --- a/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md +++ b/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md @@ -1,5 +1,6 @@ --- -category: minorAnalysis +category: breaking --- * Many library models have been rewritten to use dataflow nodes instead of the AST. - These changes include some renamings where the old name is still available as a deprecated feature. \ No newline at end of file + The types of some classes have been changed, and these changes may break existing code. + Other classes and predicates have been renamed, in these cases the old name is still available as a deprecated feature. \ No newline at end of file From b398f968e2431e3590838971fa76d89c46af8f95 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 25 Apr 2022 16:22:09 +0200 Subject: [PATCH 36/39] expand change-note to mention classes that have a changed basetype --- .../2022-04-04-dataflow-models.md | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md b/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md index 373dc1fda00f..a7c325bb6bdc 100644 --- a/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md +++ b/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md @@ -3,4 +3,55 @@ category: breaking --- * Many library models have been rewritten to use dataflow nodes instead of the AST. The types of some classes have been changed, and these changes may break existing code. - Other classes and predicates have been renamed, in these cases the old name is still available as a deprecated feature. \ No newline at end of file + Other classes and predicates have been renamed, in these cases the old name is still available as a deprecated feature. + +* The basetype of the following list of classes has changed from an expression to a dataflow node, and and thus code using these classes might break. + The fix to these breakages is usually to use `asExpr()` to get an expression from a dataflow node, or to use `.flow()` to get a dataflow node from an expression. + - DOM.qll#WebStorageWrite + - CryptoLibraries.qll#CryptographicOperation + - Express.qll#Express::RequestBodyAccess + - HTTP.qll#HTTP::ResponseBody + - HTTP.qll#HTTP::CookieDefinition + - HTTP.qll#HTTP::ServerDefinition + - HTTP.qll#HTTP::RouteSetup + - NoSQL.qll#NoSql::Query + - SQL.qll#SQL::SqlString + - SQL.qll#SQL::SqlSanitizer + - HTTP.qll#ResponseBody + - HTTP.qll#CookieDefinition + - HTTP.qll#ServerDefinition + - HTTP.qll#RouteSetup + - HTTP.qll#HTTP::RedirectInvocation + - HTTP.qll#RedirectInvocation + - Express.qll#Express::RouterDefinition + - AngularJSCore.qll#LinkFunction + - Connect.qll#Connect::StandardRouteHandler + - CryptoLibraries.qll#CryptographicKeyCredentialsExpr + - AWS.qll#AWS::Credentials + - Azure.qll#Azure::Credentials + - Connect.qll#Connect::Credentials + - DigitalOcean.qll#DigitalOcean::Credentials + - Express.qll#Express::Credentials + - NodeJSLib.qll#NodeJSLib::Credentials + - PkgCloud.qll#PkgCloud::Credentials + - Request.qll#Request::Credentials + - ServiceDefinitions.qll#InjectableFunctionServiceRequest + - SensitiveActions.qll#SensitiveVariableAccess + - SensitiveActions.qll#CleartextPasswordExpr + - Connect.qll#Connect::ServerDefinition + - Restify.qll#Restify::ServerDefinition + - Connect.qll#Connect::RouteSetup + - Express.qll#Express::RouteSetup + - Fastify.qll#Fastify::RouteSetup + - Hapi.qll#Hapi::RouteSetup + - Koa.qll#Koa::RouteSetup + - Restify.qll#Restify::RouteSetup + - NodeJSLib.qll#NodeJSLib::RouteSetup + - Express.qll#Express::StandardRouteHandler + - Express.qll#Express::SetCookie + - Hapi.qll#Hapi::RouteHandler + - HTTP.qll#HTTP::Servers::StandardHeaderDefinition + - HTTP.qll#Servers::StandardHeaderDefinition + - Hapi.qll#Hapi::ServerDefinition + - Koa.qll#Koa::AppDefinition + - SensitiveActions.qll#SensitiveCall \ No newline at end of file From 90bc8a5038dd0f56c2d70055566c7f16ee57c484 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 28 Apr 2022 10:27:16 +0200 Subject: [PATCH 37/39] run the explicit-this patch on javascript/ --- .../lib/semmle/javascript/dataflow/Nodes.qll | 2 +- .../AngularJS/ServiceDefinitions.qll | 36 ++++++++++--------- .../semmle/javascript/frameworks/Express.qll | 4 ++- .../semmle/javascript/frameworks/Firebase.qll | 14 ++++---- .../lib/semmle/javascript/frameworks/Hapi.qll | 24 ++++++------- .../lib/semmle/javascript/frameworks/Nest.qll | 30 ++++++++-------- .../semmle/javascript/frameworks/Restify.qll | 2 +- 7 files changed, 59 insertions(+), 53 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll index eee2e7a26ac7..1c9a9f661007 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll @@ -474,7 +474,7 @@ class FunctionNode extends DataFlow::ValueNode, DataFlow::SourceNode { /** Gets the parameter named `name` of this function, if any. */ DataFlow::ParameterNode getParameterByName(string name) { - result = getAParameter() and + result = this.getAParameter() and result.getName() = name } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll b/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll index 2194de9e667d..a9941c6492dc 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll @@ -27,7 +27,7 @@ private newtype TServiceReference = */ abstract class ServiceReference extends TServiceReference { /** Gets a textual representation of this element. */ - string toString() { result = getName() } + string toString() { result = this.getName() } /** * Gets the name of this reference. @@ -51,13 +51,13 @@ abstract class ServiceReference extends TServiceReference { /** * Gets a call that invokes the referenced service. */ - DataFlow::CallNode getACall() { result.getCalleeNode() = getAnAccess() } + DataFlow::CallNode getACall() { result.getCalleeNode() = this.getAnAccess() } /** * Gets a method call that invokes method `methodName` on the referenced service. */ DataFlow::MethodCallNode getAMethodCall(string methodName) { - result.getReceiver() = getAnAccess() and + result.getReceiver() = this.getAnAccess() and result.getMethodName() = methodName } @@ -65,7 +65,7 @@ abstract class ServiceReference extends TServiceReference { * Gets an access to property `propertyName` on the referenced service. */ DataFlow::PropRef getAPropertyAccess(string propertyName) { - result.getBase() = getAnAccess() and + result.getBase() = this.getAnAccess() and result.getPropertyName() = propertyName } @@ -244,17 +244,17 @@ abstract class RecipeDefinition extends DataFlow::CallNode, CustomServiceDefinit this = moduleRef(_).getAMethodCall(methodName) or this = builtinServiceRef("$provide").getAMethodCall(methodName) ) and - getArgument(0).mayHaveStringValue(name) + this.getArgument(0).mayHaveStringValue(name) } override string getName() { result = name } - override DataFlow::SourceNode getAFactoryFunction() { result.flowsTo(getArgument(1)) } + override DataFlow::SourceNode getAFactoryFunction() { result.flowsTo(this.getArgument(1)) } override DataFlow::Node getAnInjectableFunction() { methodName != "value" and methodName != "constant" and - result = getAFactoryFunction() + result = this.getAFactoryFunction() } } @@ -269,7 +269,7 @@ abstract class RecipeDefinition extends DataFlow::CallNode, CustomServiceDefinit */ abstract private class CustomSpecialServiceDefinition extends CustomServiceDefinition, DependencyInjection { - override DataFlow::Node getAnInjectableFunction() { result = getAFactoryFunction() } + override DataFlow::Node getAnInjectableFunction() { result = this.getAFactoryFunction() } } /** @@ -498,7 +498,9 @@ class InjectableFunctionServiceRequest extends ServiceRequestNode { /** * Gets a name of a requested service. */ - string getAServiceName() { exists(getAnInjectedFunction().getADependencyDeclaration(result)) } + string getAServiceName() { + exists(this.getAnInjectedFunction().getADependencyDeclaration(result)) + } /** * Gets a service with the specified name, relative to this request. @@ -576,7 +578,7 @@ class ServiceRecipeDefinition extends RecipeDefinition { */ exists(InjectableFunction f | - f = getAFactoryFunction() and + f = this.getAFactoryFunction() and result = f.asFunction() ) } @@ -589,7 +591,7 @@ class ServiceRecipeDefinition extends RecipeDefinition { class ValueRecipeDefinition extends RecipeDefinition { ValueRecipeDefinition() { methodName = "value" } - override DataFlow::SourceNode getAService() { result = getAFactoryFunction() } + override DataFlow::SourceNode getAService() { result = this.getAFactoryFunction() } } /** @@ -599,7 +601,7 @@ class ValueRecipeDefinition extends RecipeDefinition { class ConstantRecipeDefinition extends RecipeDefinition { ConstantRecipeDefinition() { methodName = "constant" } - override DataFlow::SourceNode getAService() { result = getAFactoryFunction() } + override DataFlow::SourceNode getAService() { result = this.getAFactoryFunction() } } /** @@ -622,7 +624,7 @@ class ProviderRecipeDefinition extends RecipeDefinition { */ exists(DataFlow::ThisNode thiz, InjectableFunction f | - f = getAFactoryFunction() and + f = this.getAFactoryFunction() and thiz.getBinder() = f.asFunction() and result = thiz.getAPropertySource("$get") ) @@ -647,7 +649,9 @@ class ConfigMethodDefinition extends ModuleApiCall { /** * Gets a provided configuration method. */ - InjectableFunction getConfigMethod() { result.(DataFlow::SourceNode).flowsTo(getArgument(0)) } + InjectableFunction getConfigMethod() { + result.(DataFlow::SourceNode).flowsTo(this.getArgument(0)) + } } /** @@ -660,12 +664,12 @@ class RunMethodDefinition extends ModuleApiCall { /** * Gets a provided run method. */ - InjectableFunction getRunMethod() { result.(DataFlow::SourceNode).flowsTo(getArgument(0)) } + InjectableFunction getRunMethod() { result.(DataFlow::SourceNode).flowsTo(this.getArgument(0)) } } /** * The `$scope` or `$rootScope` service. */ class ScopeServiceReference extends BuiltinServiceReference { - ScopeServiceReference() { getName() = "$scope" or getName() = "$rootScope" } + ScopeServiceReference() { this.getName() = "$scope" or this.getName() = "$rootScope" } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll index 1094a9fa4f98..86abe01f5d66 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Express.qll @@ -158,7 +158,9 @@ module Express { * This differs from `getARouteHandler` in that the argument expression is * returned, not its dataflow source. */ - deprecated Expr getRouteHandlerExpr(int index) { result = getRouteHandlerNode(index).asExpr() } + deprecated Expr getRouteHandlerExpr(int index) { + result = this.getRouteHandlerNode(index).asExpr() + } /** * Gets the `n`th handler registered by this setup, with 0 being the first. diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/lib/semmle/javascript/frameworks/Firebase.qll index 5327fc1bf461..d22bb782630e 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Firebase.qll @@ -114,13 +114,13 @@ module Firebase { class QueryListenCall extends DataFlow::MethodCallNode { QueryListenCall() { this = query().getAMethodCall() and - (getMethodName() = "on" or getMethodName() = "once") + (this.getMethodName() = "on" or this.getMethodName() = "once") } /** * Gets the argument in which the callback is passed. */ - DataFlow::Node getCallbackNode() { result = getArgument(1) } + DataFlow::Node getCallbackNode() { result = this.getArgument(1) } } /** @@ -183,13 +183,13 @@ module Firebase { class RefBuilderListenCall extends DataFlow::MethodCallNode { RefBuilderListenCall() { this = ref().getAMethodCall() and - getMethodName() = "on" + any(string s) + this.getMethodName() = "on" + any(string s) } /** * Gets the data flow node holding the listener callback. */ - DataFlow::Node getCallbackNode() { result = getArgument(0) } + DataFlow::Node getCallbackNode() { result = this.getArgument(0) } } /** @@ -199,14 +199,14 @@ module Firebase { RouteSetup() { this = namespace().getAPropertyRead("https").getAMemberCall("onRequest") } override DataFlow::SourceNode getARouteHandler() { - result = getARouteHandler(DataFlow::TypeBackTracker::end()) + result = this.getARouteHandler(DataFlow::TypeBackTracker::end()) } private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { t.start() and - result = getArgument(0).getALocalSource() + result = this.getArgument(0).getALocalSource() or - exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t)) + exists(DataFlow::TypeBackTracker t2 | result = this.getARouteHandler(t2).backtrack(t2, t)) } override DataFlow::Node getServer() { none() } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll index b66ab8d484fa..c5700f257287 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll @@ -25,18 +25,18 @@ module Hapi { /** * Gets the parameter of the route handler that contains the request object. */ - DataFlow::ParameterNode getRequestParameter() { result = getParameter(0) } + DataFlow::ParameterNode getRequestParameter() { result = this.getParameter(0) } /** * Gets the parameter of the route handler that contains the "request toolkit", * usually named `h`. */ - DataFlow::ParameterNode getRequestToolkitParameter() { result = getParameter(1) } + DataFlow::ParameterNode getRequestToolkitParameter() { result = this.getParameter(1) } /** * Gets a source node referring to the request toolkit parameter, usually named `h`. */ - DataFlow::SourceNode getRequestToolkit() { result = getRequestToolkitParameter() } + DataFlow::SourceNode getRequestToolkit() { result = this.getRequestToolkitParameter() } } /** @@ -203,24 +203,24 @@ module Hapi { server.ref().getAMethodCall() = this and ( // server.route({ handler: fun }) - getMethodName() = "route" and - getOptionArgument(0, "handler") = handler + this.getMethodName() = "route" and + this.getOptionArgument(0, "handler") = handler or // server.ext('/', fun) - getMethodName() = "ext" and - handler = getArgument(1) + this.getMethodName() = "ext" and + handler = this.getArgument(1) ) } override DataFlow::SourceNode getARouteHandler() { - result = getARouteHandler(DataFlow::TypeBackTracker::end()) + result = this.getARouteHandler(DataFlow::TypeBackTracker::end()) } private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { t.start() and - result = getRouteHandler().getALocalSource() + result = this.getRouteHandler().getALocalSource() or - exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t)) + exists(DataFlow::TypeBackTracker t2 | result = this.getARouteHandler(t2).backtrack(t2, t)) } pragma[noinline] @@ -268,9 +268,9 @@ module Hapi { override DataFlow::SourceNode getOutput() { none() } - override DataFlow::Node getTemplateFileNode() { result = getArgument(0) } + override DataFlow::Node getTemplateFileNode() { result = this.getArgument(0) } - override DataFlow::Node getTemplateParamsNode() { result = getArgument(1) } + override DataFlow::Node getTemplateParamsNode() { result = this.getArgument(1) } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll index bb3a91036ff2..80cba72fd3cb 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll @@ -56,7 +56,7 @@ module NestJS { */ predicate isReturnValueReflected() { getAFunctionDecorator(this) = nestjs().getMember(["Get", "Post"]).getACall() and - not hasRedirectDecorator() and + not this.hasRedirectDecorator() and not getAFunctionDecorator(this) = nestjs().getMember("Render").getACall() } @@ -93,7 +93,7 @@ module NestJS { NestJSRequestInput() { decoratorName = ["Query", "Param", "Headers", "Body", "HostParam", "UploadedFile", "UploadedFiles"] and - decorator = getADecorator() and + decorator = this.getADecorator() and decorator = nestjs().getMember(decoratorName).getACall() } @@ -105,7 +105,7 @@ module NestJS { /** Gets a pipe applied to this parameter, not including global pipes. */ DataFlow::Node getAPipe() { - result = getNestRouteHandler().getAPipe() + result = this.getNestRouteHandler().getAPipe() or result = decorator.getArgument(1) or @@ -132,7 +132,7 @@ module NestJS { hasSanitizingPipe(this, false) or hasSanitizingPipe(this, true) and - isSanitizingType(getParameter().getType().unfold()) + isSanitizingType(this.getParameter().getType().unfold()) } } @@ -240,14 +240,14 @@ module NestJS { ) } - DataFlow::FunctionNode getTransformFunction() { result = getInstanceMethod("transform") } + DataFlow::FunctionNode getTransformFunction() { result = this.getInstanceMethod("transform") } - DataFlow::ParameterNode getInputData() { result = getTransformFunction().getParameter(0) } + DataFlow::ParameterNode getInputData() { result = this.getTransformFunction().getParameter(0) } - DataFlow::Node getOutputData() { result = getTransformFunction().getReturnNode() } + DataFlow::Node getOutputData() { result = this.getTransformFunction().getReturnNode() } NestJSRequestInput getAnAffectedParameter() { - [getAnInstanceReference(), getAClassReference()].flowsTo(result.getAPipe()) + [this.getAnInstanceReference(), this.getAClassReference()].flowsTo(result.getAPipe()) } } @@ -297,16 +297,16 @@ module NestJS { private class NestJSRequestInputAsRequestInputAccess extends NestJSRequestInput, HTTP::RequestInputAccess { NestJSRequestInputAsRequestInputAccess() { - not isSanitizedByPipe() and + not this.isSanitizedByPipe() and not this = any(CustomPipeClass cls).getAnAffectedParameter() } - override HTTP::RouteHandler getRouteHandler() { result = getNestRouteHandler() } + override HTTP::RouteHandler getRouteHandler() { result = this.getNestRouteHandler() } - override string getKind() { result = getInputKind() } + override string getKind() { result = this.getInputKind() } override predicate isUserControlledObject() { - not exists(getAPipe()) and // value is not transformed by a pipe + not exists(this.getAPipe()) and // value is not transformed by a pipe ( decorator.getNumArgument() = 0 or @@ -389,15 +389,15 @@ module NestJS { CustomParameterDecorator() { this = nestjs().getMember("createParamDecorator").getACall() } /** Gets the `context` parameter. */ - API::Node getExecutionContext() { result = getParameter(0).getParameter(1) } + API::Node getExecutionContext() { result = this.getParameter(0).getParameter(1) } /** Gets a parameter with this decorator applied. */ DataFlow::ParameterNode getADecoratedParameter() { - result.getADecorator() = getReturn().getReturn().getAValueReachableFromSource() + result.getADecorator() = this.getReturn().getReturn().getAValueReachableFromSource() } /** Gets a value returned by the decorator's callback, which becomes the value of the decorated parameter. */ - DataFlow::Node getResult() { result = getParameter(0).getReturn().asSink() } + DataFlow::Node getResult() { result = this.getParameter(0).getReturn().asSink() } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll b/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll index 0a782b32f1c8..492416171dac 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Restify.qll @@ -162,7 +162,7 @@ module Restify { server.ref().getAMethodCall(any(HTTP::RequestMethodName m).toLowerCase()) = this } - override DataFlow::SourceNode getARouteHandler() { result.flowsTo(getArgument(1)) } + override DataFlow::SourceNode getARouteHandler() { result.flowsTo(this.getArgument(1)) } override DataFlow::Node getServer() { result = server } } From 54eb0414cbf2c9e6c8ed3daaae4928de94315e7b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 28 Apr 2022 10:29:39 +0200 Subject: [PATCH 38/39] rename an upper-cased acronym --- .../ql/lib/semmle/javascript/security/dataflow/DOM.qll | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll index 45a840645174..21fb6f785aff 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll @@ -155,10 +155,14 @@ class DomMethodCallNode extends DataFlow::MethodCallNode { } /** DEPRECATED: Alias for interpretsArgumentsAsUrl */ - deprecated predicate interpretsArgumentsAsURL(DataFlow::Node arg) { this.interpretsArgumentsAsUrl(arg) } + deprecated predicate interpretsArgumentsAsURL(DataFlow::Node arg) { + this.interpretsArgumentsAsUrl(arg) + } /** DEPRECATED: Alias for interpretsArgumentsAsHtml */ - deprecated predicate interpretsArgumentsAsHTML(DataFlow::Node arg) { this.interpretsArgumentsAsHtml(arg) } + deprecated predicate interpretsArgumentsAsHTML(DataFlow::Node arg) { + this.interpretsArgumentsAsHtml(arg) + } } /** From 4e14177614fdaa74dd8323601ad40fbcb5b92206 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 28 Apr 2022 13:03:26 +0200 Subject: [PATCH 39/39] fix typo in change-note --- javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md b/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md index a7c325bb6bdc..4a454f51b202 100644 --- a/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md +++ b/javascript/ql/lib/change-notes/2022-04-04-dataflow-models.md @@ -5,7 +5,7 @@ category: breaking The types of some classes have been changed, and these changes may break existing code. Other classes and predicates have been renamed, in these cases the old name is still available as a deprecated feature. -* The basetype of the following list of classes has changed from an expression to a dataflow node, and and thus code using these classes might break. +* The basetype of the following list of classes has changed from an expression to a dataflow node, and thus code using these classes might break. The fix to these breakages is usually to use `asExpr()` to get an expression from a dataflow node, or to use `.flow()` to get a dataflow node from an expression. - DOM.qll#WebStorageWrite - CryptoLibraries.qll#CryptographicOperation