Merge pull request #8604 from erik-krogh/httpNode

JS: refactor most library models away from AST nodes
This commit is contained in:
Erik Krogh Kristensen
2022-09-09 10:04:17 +02:00
committed by GitHub
153 changed files with 1924 additions and 1163 deletions

View File

@@ -175,7 +175,7 @@ predicate isOtherModeledArgument(DataFlow::Node n, FilteringReason reason) {
or or
n instanceof CryptographicKey and reason instanceof CryptographicKeyReason n instanceof CryptographicKey and reason instanceof CryptographicKeyReason
or or
any(CryptographicOperation op).getInput().flow() = n and any(CryptographicOperation op).getInput() = n and
reason instanceof CryptographicOperationFlowReason reason instanceof CryptographicOperationFlowReason
or or
exists(DataFlow::CallNode call | n = call.getAnArgument() | exists(DataFlow::CallNode call | n = call.getAnArgument() |

View File

@@ -144,7 +144,7 @@ private module AccessPaths {
not param = base.getReceiver() not param = base.getReceiver()
| |
result = param and result = param and
name = param.asSource().asExpr().(Parameter).getName() name = param.asSource().(DataFlow::ParameterNode).getName()
or or
param.asSource().asExpr() instanceof DestructuringPattern and param.asSource().asExpr() instanceof DestructuringPattern and
result = param.getMember(name) result = param.getMember(name)

View File

@@ -42,10 +42,10 @@ module SinkEndpointFilter {
result = "modeled database access" result = "modeled database access"
or or
// Remove calls to APIs that aren't relevant to NoSQL injection // 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" result = "receiver is a HTTP request expression"
or or
call.getReceiver().asExpr() instanceof HTTP::ResponseExpr and call.getReceiver() instanceof HTTP::ResponseNode and
result = "receiver is a HTTP response expression" result = "receiver is a HTTP response expression"
) )
or or
@@ -115,7 +115,7 @@ predicate isBaseAdditionalFlowStep(
inlbl = TaintedObject::label() and inlbl = TaintedObject::label() and
outlbl = TaintedObject::label() and outlbl = TaintedObject::label() and
exists(NoSql::Query query, DataFlow::SourceNode queryObj | exists(NoSql::Query query, DataFlow::SourceNode queryObj |
queryObj.flowsToExpr(query) and queryObj.flowsTo(query) and
queryObj.flowsTo(trg) and queryObj.flowsTo(trg) and
src = queryObj.getAPropertyWrite().getRhs() src = queryObj.getAPropertyWrite().getRhs()
) )

View File

@@ -0,0 +1,57 @@
---
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.
* 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
- 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

View File

@@ -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`. * 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. * Gets the static type of this expression, as determined by the TypeScript type system.

View File

@@ -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`. * 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. * Holds if this element is at the specified location.

View File

@@ -472,6 +472,12 @@ class FunctionNode extends DataFlow::ValueNode, DataFlow::SourceNode {
/** Gets a parameter of this function. */ /** Gets a parameter of this function. */
ParameterNode getAParameter() { result = this.getParameter(_) } ParameterNode getAParameter() { result = this.getParameter(_) }
/** Gets the parameter named `name` of this function, if any. */
DataFlow::ParameterNode getParameterByName(string name) {
result = this.getAParameter() and
result.getName() = name
}
/** Gets the number of parameters declared on this function. */ /** Gets the number of parameters declared on this function. */
int getNumParameter() { result = count(astNode.getAParameter()) } int getNumParameter() { result = count(astNode.getAParameter()) }
@@ -556,6 +562,14 @@ class ObjectLiteralNode extends DataFlow::ValueNode, DataFlow::SourceNode {
DataFlow::FunctionNode getPropertySetter(string name) { DataFlow::FunctionNode getPropertySetter(string name) {
result = astNode.getPropertyByName(name).(PropertySetter).getInit().flow() 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()
)
}
} }
/** /**

View File

@@ -482,17 +482,13 @@ module TaintTracking {
*/ */
private class HeapTaintStep extends SharedTaintStep { private class HeapTaintStep extends SharedTaintStep {
override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) { override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(Expr e, Expr f | e = succ.asExpr() and f = pred.asExpr() | succ.(DataFlow::ObjectLiteralNode).getAComputedPropertyName() = pred
exists(Property prop | e.(ObjectExpr).getAProperty() = prop |
prop.isComputed() and f = prop.getNameExpr()
)
or or
// spreading a tainted object into an object literal gives a tainted object // spreading a tainted object into an object literal gives a tainted object
e.(ObjectExpr).getAProperty().(SpreadProperty).getInit().(SpreadElement).getOperand() = f succ.(DataFlow::ObjectLiteralNode).getASpreadProperty() = pred
or or
// spreading a tainted value into an array literal gives a tainted array // spreading a tainted value into an array literal gives a tainted array
e.(ArrayExpr).getAnElement().(SpreadElement).getOperand() = f succ.(DataFlow::ArrayCreationNode).getASpreadArgument() = pred
)
or or
// arrays with tainted elements and objects with tainted property names are tainted // arrays with tainted elements and objects with tainted property names are tainted
succ.(DataFlow::ArrayCreationNode).getAnElement() = pred and succ.(DataFlow::ArrayCreationNode).getAnElement() = pred and
@@ -546,16 +542,16 @@ module TaintTracking {
*/ */
private class ComputedPropWriteTaintStep extends SharedTaintStep { private class ComputedPropWriteTaintStep extends SharedTaintStep {
override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) { override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(AssignExpr assgn, IndexExpr idx, DataFlow::SourceNode obj | exists(DataFlow::PropWrite assgn, DataFlow::SourceNode obj |
assgn.getTarget() = idx and not exists(assgn.getPropertyName()) and
obj.flowsToExpr(idx.getBase()) and not assgn.getWriteNode() instanceof Property and // not a write inside an object literal
not exists(idx.getPropertyName()) and pred = assgn.getRhs() and
pred = DataFlow::valueNode(assgn.getRhs()) and assgn = obj.getAPropertyWrite() and
succ = obj succ = obj
| |
obj instanceof DataFlow::ObjectLiteralNode obj instanceof DataFlow::ObjectLiteralNode
or or
obj.getAPropertyRead("length").flowsToExpr(idx.getPropertyNameExpr()) obj.getAPropertyRead("length").flowsToExpr(assgn.getPropertyNameExpr())
) )
} }
} }
@@ -580,8 +576,8 @@ module TaintTracking {
override predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node target) { override predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node target) {
exists(DataFlow::ValueNode succ | target = succ | exists(DataFlow::ValueNode succ | target = succ |
// string operations that propagate taint // string operations that propagate taint
exists(string name | name = succ.getAstNode().(MethodCallExpr).getMethodName() | exists(string name | name = succ.(DataFlow::MethodCallNode).getMethodName() |
pred.asExpr() = succ.getAstNode().(MethodCallExpr).getReceiver() and pred = succ.(DataFlow::MethodCallNode).getReceiver() and
( (
// sorted, interesting, properties of String.prototype // sorted, interesting, properties of String.prototype
name = name =
@@ -600,7 +596,7 @@ module TaintTracking {
name = "join" name = "join"
) )
or or
exists(int i | pred.asExpr() = succ.getAstNode().(MethodCallExpr).getArgument(i) | exists(int i | pred = succ.(DataFlow::MethodCallNode).getArgument(i) |
name = "concat" name = "concat"
or or
name = ["replace", "replaceAll"] and i = 1 name = ["replace", "replaceAll"] and i = 1
@@ -615,10 +611,10 @@ module TaintTracking {
) )
or or
// String.fromCharCode and String.fromCodePoint // String.fromCharCode and String.fromCodePoint
exists(int i, MethodCallExpr mce | exists(int i, DataFlow::MethodCallNode mcn |
mce = succ.getAstNode() and mcn = succ and
pred.asExpr() = mce.getArgument(i) and pred = mcn.getArgument(i) and
(mce.getMethodName() = "fromCharCode" or mce.getMethodName() = "fromCodePoint") mcn.getMethodName() = ["fromCharCode", "fromCodePoint"]
) )
or or
// `(encode|decode)URI(Component)?` propagate taint // `(encode|decode)URI(Component)?` propagate taint
@@ -744,11 +740,11 @@ module TaintTracking {
* the parameters in `input`. * the parameters in `input`.
*/ */
predicate isUrlSearchParams(DataFlow::SourceNode params, DataFlow::Node 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 urlSearchParams.getName() = "URLSearchParams" and
newUrlSearchParams = urlSearchParams.getAnInstantiation().asExpr() and newUrlSearchParams = urlSearchParams.getAnInstantiation() and
params.asExpr() = newUrlSearchParams and params = newUrlSearchParams and
input.asExpr() = newUrlSearchParams.getArgument(0) input = newUrlSearchParams.getArgument(0)
) )
} }

View File

@@ -8,19 +8,19 @@ module AWS {
/** /**
* Holds if the `i`th argument of `invk` is an object hash for `AWS.Config`. * 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" | exists(DataFlow::ModuleImportNode mod | mod.getPath() = "aws-sdk" |
// `AWS.config.update(nd)` // `AWS.config.update(nd)`
invk = mod.getAPropertyRead("config").getAMemberCall("update").asExpr() and invk = mod.getAPropertyRead("config").getAMemberCall("update") and
i = 0 i = 0
or or
exists(DataFlow::SourceNode cfg | cfg = mod.getAConstructorInvocation("Config") | exists(DataFlow::SourceNode cfg | cfg = mod.getAConstructorInvocation("Config") |
// `new AWS.Config(nd)` // `new AWS.Config(nd)`
invk = cfg.asExpr() and invk = cfg and
i = 0 i = 0
or or
// `var config = new AWS.Config(...); config.update(nd);` // `var config = new AWS.Config(...); config.update(nd);`
invk = cfg.getAMemberCall("update").asExpr() and invk = cfg.getAMemberCall("update") and
i = 0 i = 0
) )
) )
@@ -29,13 +29,13 @@ module AWS {
/** /**
* An expression that is used as an AWS config value: `{ accessKeyId: <user>, secretAccessKey: <password>}`. * An expression that is used as an AWS config value: `{ accessKeyId: <user>, secretAccessKey: <password>}`.
*/ */
class Credentials extends CredentialsExpr { class Credentials extends CredentialsNode {
string kind; string kind;
Credentials() { Credentials() {
exists(string prop, InvokeExpr invk, int i | exists(string prop, DataFlow::InvokeNode invk, int i |
takesConfigurationObject(invk, i) and takesConfigurationObject(invk, i) and
invk.hasOptionArgument(i, prop, this) this = invk.getOptionArgument(i, prop)
| |
prop = "accessKeyId" and kind = "user name" prop = "accessKeyId" and kind = "user name"
or or

View File

@@ -68,7 +68,7 @@ private class TrackStringsInAngularCode extends DataFlow::SourceNode::Range, Dat
*/ */
private DataFlow::CallNode angularModuleCall(string name) { private DataFlow::CallNode angularModuleCall(string name) {
result = angular().getAMemberCall("module") and result = angular().getAMemberCall("module") and
result.getArgument(0).asExpr().mayHaveStringValue(name) result.getArgument(0).mayHaveStringValue(name)
} }
/** /**
@@ -105,8 +105,8 @@ class AngularModule extends TAngularModule {
/** /**
* Get the array of dependencies from this module's definition. * Get the array of dependencies from this module's definition.
*/ */
ArrayExpr getDependencyArray() { DataFlow::ArrayCreationNode getDependencyArray() {
this.getADefinition().getArgument(1).getALocalSource().asExpr() = result this.getADefinition().getArgument(1).getALocalSource() = result
} }
/** /**
@@ -160,14 +160,10 @@ class ModuleApiCall extends DataFlow::CallNode {
string getMethodName() { result = methodName } string getMethodName() { result = methodName }
} }
class ModuleApiCallDependencyInjection extends DependencyInjection { class ModuleApiCallDependencyInjection extends DependencyInjection instanceof ModuleApiCall {
ModuleApiCall call;
string methodName; string methodName;
ModuleApiCallDependencyInjection() { ModuleApiCallDependencyInjection() { methodName = super.getMethodName() }
this = call and
methodName = call.getMethodName()
}
/** /**
* Gets the argument position for this method call that expects an injectable function. * 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() { 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)) } DataFlow::SourceNode getMember(string name) { result.flowsTo(this.getMemberInit(name)) }
/** Gets the method `name` of this directive. */ /** 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. */ /** 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. */ /** Holds if this directive's properties are bound to the controller. */
abstract predicate bindsToController(); abstract predicate bindsToController();
@@ -284,7 +280,7 @@ abstract class CustomDirective extends DirectiveInstance {
InjectableFunction getController() { result = this.getMember("controller") } InjectableFunction getController() { result = this.getMember("controller") }
/** Gets the template URL of this directive, if any. */ /** 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. * Gets a template file for this directive, if any.
@@ -302,9 +298,7 @@ abstract class CustomDirective extends DirectiveInstance {
else result = DirectiveInstance.super.getAScope() else result = DirectiveInstance.super.getAScope()
} }
private string getRestrictionString() { private string getRestrictionString() { this.getMember("restrict").mayHaveStringValue(result) }
this.getMember("restrict").asExpr().mayHaveStringValue(result)
}
private predicate hasTargetType(DirectiveTargetType type) { private predicate hasTargetType(DirectiveTargetType type) {
not exists(this.getRestrictionString()) or not exists(this.getRestrictionString()) or
@@ -332,10 +326,10 @@ class GeneralDirective extends CustomDirective, MkCustomDirective {
/** Gets a node that contributes to the return value of the factory function. */ /** Gets a node that contributes to the return value of the factory function. */
override DataFlow::SourceNode getAnInstantiation() { override DataFlow::SourceNode getAnInstantiation() {
exists(Function factory, InjectableFunction f | exists(DataFlow::FunctionNode factory, InjectableFunction f |
f = definition.getAFactoryFunction() and f = definition.getAFactoryFunction() and
factory = f.asFunction() and factory = f.asFunction() and
result.flowsToExpr(factory.getAReturnedExpr()) result.flowsTo(factory.getAReturn())
) )
} }
@@ -344,7 +338,7 @@ class GeneralDirective extends CustomDirective, MkCustomDirective {
} }
/** Gets the compile function of this directive, if any. */ /** 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. * Gets a pre/post link function of this directive defined on its definition object.
@@ -365,9 +359,8 @@ class GeneralDirective extends CustomDirective, MkCustomDirective {
result = this.getMember("link").getAPropertySource(kind) result = this.getMember("link").getAPropertySource(kind)
or or
// { compile: function() { ... return link; } } // { compile: function() { ... return link; } }
exists(Expr compileReturn, DataFlow::SourceNode compileReturnSrc | exists(DataFlow::SourceNode compileReturnSrc |
compileReturn = this.getCompileFunction().getAReturnedExpr() and compileReturnSrc.flowsTo(this.getCompileFunction().getAReturn())
compileReturnSrc.flowsToExpr(compileReturn)
| |
// link = function postLink() { ... } // link = function postLink() { ... }
kind = "post" and kind = "post" and
@@ -380,18 +373,20 @@ class GeneralDirective extends CustomDirective, MkCustomDirective {
} }
/** Gets the pre-link function of this directive. */ /** 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. */ /** 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() { 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
}
} }
/** /**
@@ -412,7 +407,7 @@ class ComponentDirective extends CustomDirective, MkCustomComponent {
comp.getConfig().hasPropertyWrite(name, result) comp.getConfig().hasPropertyWrite(name, result)
} }
override Function getALinkFunction() { none() } override DataFlow::FunctionNode getALinkFunction() { none() }
override predicate bindsToController() { none() } override predicate bindsToController() { none() }
@@ -561,13 +556,12 @@ class DirectiveTargetName extends string {
* *
* See https://docs.angularjs.org/api/ng/service/$location for details. * 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() { LocationFlowSource() {
exists(ServiceReference service, MethodCallExpr mce, string m, int n | exists(ServiceReference service, string m, int n |
service.getName() = "$location" and service.getName() = "$location" and
this.asExpr() = mce and this = service.getAMethodCall(m) and
mce = service.getAMethodCall(m) and n = super.getNumArgument()
n = mce.getNumArgument()
| |
m = "search" and n < 2 m = "search" and n < 2
or or
@@ -605,7 +599,7 @@ private class JQLiteObject extends JQuery::ObjectSource::Range {
JQLiteObject() { JQLiteObject() {
this = angular().getAMemberCall("element") this = angular().getAMemberCall("element")
or or
exists(Parameter param | this = DataFlow::parameterNode(param) | exists(DataFlow::ParameterNode param | this = param |
// element parameters to user-functions invoked by AngularJS // element parameters to user-functions invoked by AngularJS
param = any(LinkFunction link).getElementParameter() param = any(LinkFunction link).getElementParameter()
or or
@@ -613,13 +607,13 @@ private class JQLiteObject extends JQuery::ObjectSource::Range {
param = d.getCompileFunction().getParameter(0) param = d.getCompileFunction().getParameter(0)
or or
exists(DataFlow::FunctionNode f, int i | exists(DataFlow::FunctionNode f, int i |
f.flowsToExpr(d.getCompileFunction().getAReturnedExpr()) and i = 1 f.flowsTo(d.getCompileFunction().getAReturn()) and i = 1
or or
f = d.getMember("template") and i = 0 f = d.getMember("template") and i = 0
or or
f = d.getMember("templateUrl") and i = 0 f = d.getMember("templateUrl") and i = 0
| |
param = f.getAstNode().(Function).getParameter(i) param = f.getParameter(i)
) )
) )
) )
@@ -631,99 +625,111 @@ private class JQLiteObject extends JQuery::ObjectSource::Range {
} }
/** /**
* DEPRECATED: Use `AngularJSCallNode` instead.
* A call to an AngularJS function. * A call to an AngularJS function.
* *
* Used for exposing behavior that is similar to the behavior of other libraries. * Used for exposing behavior that is similar to the behavior of other libraries.
*/ */
abstract class AngularJSCall extends CallExpr { 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 AngularJSCallNode extends DataFlow::CallNode {
/** /**
* Holds if `e` is an argument that this call interprets as HTML. * 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. * 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. * 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. * A call to a method on the AngularJS object itself.
*/ */
private class AngularMethodCall extends AngularJSCall { private class AngularMethodCall extends AngularJSCallNode {
MethodCallExpr mce; AngularMethodCall() { this = angular().getAMemberCall(_) }
AngularMethodCall() { override predicate interpretsArgumentAsHtml(DataFlow::Node e) {
mce = angular().getAMemberCall(_).asExpr() and super.getCalleeName() = "element" and
mce = this e = super.getArgument(0)
} }
override predicate interpretsArgumentAsHtml(Expr e) { override predicate storesArgumentGlobally(DataFlow::Node e) { none() }
mce.getMethodName() = "element" and
e = mce.getArgument(0)
}
override predicate storesArgumentGlobally(Expr e) { none() } override predicate interpretsArgumentAsCode(DataFlow::Node e) { none() }
override predicate interpretsArgumentAsCode(Expr e) { none() }
} }
/** /**
* A call to a builtin service or one of its methods. * A call to a builtin service or one of its methods.
*/ */
private class BuiltinServiceCall extends AngularJSCall { private class BuiltinServiceCall extends AngularJSCallNode {
CallExpr call;
BuiltinServiceCall() { BuiltinServiceCall() {
exists(BuiltinServiceReference service | exists(BuiltinServiceReference service |
service.getAMethodCall(_) = this or service.getAMethodCall(_) = this or
service.getACall() = this service.getACall() = this
|
call = this
) )
} }
override predicate interpretsArgumentAsHtml(Expr e) { override predicate interpretsArgumentAsHtml(DataFlow::Node e) {
exists(ServiceReference service, string methodName | exists(ServiceReference service, string methodName |
service.getName() = "$sce" and service.getName() = "$sce" and
call = service.getAMethodCall(methodName) this = service.getAMethodCall(methodName)
| |
// specialized call // specialized call
(methodName = "trustAsHtml" or methodName = "trustAsCss") and (methodName = "trustAsHtml" or methodName = "trustAsCss") and
e = call.getArgument(0) e = this.getArgument(0)
or or
// generic call with enum argument // generic call with enum argument
methodName = "trustAs" and methodName = "trustAs" and
exists(DataFlow::PropRead prn | 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 (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 | exists(ServiceReference service, string serviceName, string methodName |
service.getName() = serviceName and service.getName() = serviceName and
call = service.getAMethodCall(methodName) this = service.getAMethodCall(methodName)
| |
// AngularJS caches (only available during runtime, so similar to sessionStorage) // AngularJS caches (only available during runtime, so similar to sessionStorage)
(serviceName = "$cacheFactory" or serviceName = "$templateCache") and (serviceName = "$cacheFactory" or serviceName = "$templateCache") and
methodName = "put" and methodName = "put" and
e = call.getArgument(1) e = this.getArgument(1)
or or
serviceName = "$cookies" and serviceName = "$cookies" and
(methodName = "put" or methodName = "putObject") 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 | exists(ScopeServiceReference scope, string methodName |
methodName = methodName =
[ [
@@ -731,22 +737,21 @@ private class BuiltinServiceCall extends AngularJSCall {
"$watchGroup" "$watchGroup"
] ]
| |
call = scope.getAMethodCall(methodName) and this = scope.getAMethodCall(methodName) and
e = call.getArgument(0) e = this.getArgument(0)
) )
or or
exists(ServiceReference service | service.getName() = ["$compile", "$parse", "$interpolate"] | exists(ServiceReference service | service.getName() = ["$compile", "$parse", "$interpolate"] |
call = service.getACall() and this = service.getACall() and
e = call.getArgument(0) e = this.getArgument(0)
) )
or or
exists(ServiceReference service, CallExpr filterInvocation | exists(ServiceReference service |
// `$filter('orderBy')(collection, expression)` // `$filter('orderBy')(collection, expression)`
service.getName() = "$filter" and service.getName() = "$filter" and
call = service.getACall() and this = service.getACall() and
call.getArgument(0).mayHaveStringValue("orderBy") and this.getArgument(0).mayHaveStringValue("orderBy") and
filterInvocation.getCallee() = call and e = this.getACall().getArgument(1)
e = filterInvocation.getArgument(1)
) )
} }
} }
@@ -754,33 +759,33 @@ private class BuiltinServiceCall extends AngularJSCall {
/** /**
* A link-function used in a custom AngularJS directive. * A link-function used in a custom AngularJS directive.
*/ */
class LinkFunction extends Function { class LinkFunction extends DataFlow::FunctionNode {
LinkFunction() { this = any(GeneralDirective d).getALinkFunction() } LinkFunction() { this = any(GeneralDirective d).getALinkFunction() }
/** /**
* Gets the scope parameter of this function. * 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). * 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. * 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. * 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. * 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. * Gets an access to this scope object.
*/ */
Expr getAnAccess() { DataFlow::Node getAnAccess() {
exists(CustomDirective d | this = d.getAScope() | exists(CustomDirective d | this = d.getAScope() |
exists(Parameter p | exists(DataFlow::ParameterNode p |
p = d.getController().getDependencyParameter("$scope") or p = d.getController().getDependencyParameter("$scope") or
p = d.getALinkFunction().getParameter(0) p = d.getALinkFunction().getParameter(0)
| |
result.mayReferToParameter(p) p.flowsTo(result)
) )
or or
exists(DataFlow::ThisNode dis | exists(DataFlow::ThisNode dis |
dis.flowsToExpr(result) and dis.flowsTo(result) and
dis.getBinder().getAstNode() = d.getController().asFunction() and dis.getBinder() = d.getController().asFunction() and
d.bindsToController() d.bindsToController()
) )
or or
d.hasIsolateScope() and result = d.getMember("scope").asExpr() d.hasIsolateScope() and result = d.getMember("scope")
) )
or or
exists(DirectiveController c, DOM::ElementDefinition elem, Parameter p | exists(DirectiveController c, DOM::ElementDefinition elem, DataFlow::ParameterNode p |
c.boundTo(elem) and c.boundTo(elem) and
this.mayApplyTo(elem) and this.mayApplyTo(elem) and
p = c.getFactoryFunction().getDependencyParameter("$scope") and p = c.getFactoryFunction().getDependencyParameter("$scope") and
result.mayReferToParameter(p) p.flowsTo(result)
) )
} }
@@ -925,9 +930,7 @@ class RouteSetup extends DataFlow::CallNode, DependencyInjection {
| |
result = controllerProperty result = controllerProperty
or or
exists(ControllerDefinition def | exists(ControllerDefinition def | controllerProperty.mayHaveStringValue(def.getName()) |
controllerProperty.asExpr().mayHaveStringValue(def.getName())
|
result = def.getAService() result = def.getAService()
) )
) )
@@ -1007,7 +1010,7 @@ private class RouteInstantiatedController extends Controller {
override predicate boundTo(DOM::ElementDefinition elem) { override predicate boundTo(DOM::ElementDefinition elem) {
exists(string url, HTML::HtmlFile template | 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 template.getAbsolutePath().regexpMatch(".*\\Q" + url + "\\E") and
elem.getFile() = template elem.getFile() = template
) )
@@ -1015,22 +1018,19 @@ private class RouteInstantiatedController extends Controller {
override predicate boundToAs(DOM::ElementDefinition elem, string name) { override predicate boundToAs(DOM::ElementDefinition elem, string name) {
this.boundTo(elem) and this.boundTo(elem) and
setup.getRouteParam("controllerAs").asExpr().mayHaveStringValue(name) setup.getRouteParam("controllerAs").mayHaveStringValue(name)
} }
} }
/** /**
* Dataflow for the arguments of AngularJS dependency-injected functions. * 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; DataFlow::AnalyzedNode service;
DependencyInjectedArgumentInitializer() { DependencyInjectedArgumentInitializer() {
exists( exists(AngularJS::InjectableFunction f, AngularJS::CustomServiceDefinition def |
AngularJS::InjectableFunction f, Parameter param, AngularJS::CustomServiceDefinition def def.getServiceReference() = f.getAResolvedDependency(this) and
|
this = DataFlow::parameterNode(param) and
def.getServiceReference() = f.getAResolvedDependency(param) and
service = def.getAService() service = def.getAService()
) )
} }

View File

@@ -41,33 +41,35 @@ abstract class DependencyInjection extends DataFlow::ValueNode {
*/ */
abstract class InjectableFunction extends DataFlow::ValueNode { abstract class InjectableFunction extends DataFlow::ValueNode {
/** Gets the parameter corresponding to dependency `name`. */ /** 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`. * 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. */ /** Gets the function underlying this injectable function. */
abstract Function asFunction(); abstract DataFlow::FunctionNode asFunction();
/** Gets a location where this function is explicitly dependency injected. */ /** Gets a node where this function is explicitly dependency injected. */
abstract AstNode getAnExplicitDependencyInjection(); abstract DataFlow::Node getAnExplicitDependencyInjection();
/** /**
* Gets a service corresponding to the dependency-injected `parameter`. * Gets a service corresponding to the dependency-injected `parameter`.
*/ */
ServiceReference getAResolvedDependency(Parameter parameter) { ServiceReference getAResolvedDependency(DataFlow::ParameterNode parameter) {
exists(string name, InjectableFunctionServiceRequest request | exists(string name, InjectableFunctionServiceRequest request |
this = request.getAnInjectedFunction() and this = request.getAnInjectedFunction() and
parameter = getDependencyParameter(name) 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`. * Gets a Custom service corresponding to the dependency-injected `parameter`.
* (this is a convenience variant of `getAResolvedDependency`) * (this is a convenience variant of `getAResolvedDependency`)
*/ */
DataFlow::Node getCustomServiceDependency(Parameter parameter) { DataFlow::Node getCustomServiceDependency(DataFlow::ParameterNode parameter) {
exists(CustomServiceDefinition custom | exists(CustomServiceDefinition custom |
custom.getServiceReference() = getAResolvedDependency(parameter) and custom.getServiceReference() = getAResolvedDependency(parameter) and
result = custom.getAService() result = custom.getAService()
@@ -91,100 +93,88 @@ abstract class InjectableFunction extends DataFlow::ValueNode {
* An injectable function that does not explicitly list its dependencies, * An injectable function that does not explicitly list its dependencies,
* instead relying on implicit matching by parameter names. * instead relying on implicit matching by parameter names.
*/ */
private class FunctionWithImplicitDependencyAnnotation extends InjectableFunction { private class FunctionWithImplicitDependencyAnnotation extends InjectableFunction instanceof DataFlow::FunctionNode {
override Function astNode;
FunctionWithImplicitDependencyAnnotation() { FunctionWithImplicitDependencyAnnotation() {
this.(DataFlow::FunctionNode).flowsTo(any(DependencyInjection d).getAnInjectableFunction()) and this.(DataFlow::FunctionNode).flowsTo(any(DependencyInjection d).getAnInjectableFunction()) and
not exists(getAPropertyDependencyInjection(astNode)) not exists(getAPropertyDependencyInjection(this))
} }
override Parameter getDependencyParameter(string name) { override DataFlow::ParameterNode getDependencyParameter(string name) {
result = astNode.getParameterByName(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.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) { private DataFlow::PropWrite getAPropertyDependencyInjection(DataFlow::FunctionNode function) {
exists(DataFlow::FunctionNode ltf | result = function.getAPropertyWrite("$inject")
ltf.getAstNode() = function and
result = ltf.getAPropertyWrite("$inject")
)
} }
/** /**
* An injectable function with an `$inject` property that lists its * An injectable function with an `$inject` property that lists its
* dependencies. * dependencies.
*/ */
private class FunctionWithInjectProperty extends InjectableFunction { private class FunctionWithInjectProperty extends InjectableFunction instanceof DataFlow::FunctionNode {
override Function astNode;
DataFlow::ArrayCreationNode dependencies; DataFlow::ArrayCreationNode dependencies;
FunctionWithInjectProperty() { FunctionWithInjectProperty() {
( (
this.(DataFlow::FunctionNode).flowsTo(any(DependencyInjection d).getAnInjectableFunction()) or this.(DataFlow::FunctionNode).flowsTo(any(DependencyInjection d).getAnInjectableFunction()) or
exists(FunctionWithExplicitDependencyAnnotation f | f.asFunction() = astNode) exists(FunctionWithExplicitDependencyAnnotation f | f.asFunction() = this)
) and ) and
exists(DataFlow::PropWrite pwn | exists(DataFlow::PropWrite pwn |
pwn = getAPropertyDependencyInjection(astNode) and pwn = getAPropertyDependencyInjection(this) and
pwn.getRhs().getALocalSource() = dependencies pwn.getRhs().getALocalSource() = dependencies
) )
} }
override Parameter getDependencyParameter(string name) { override DataFlow::ParameterNode getDependencyParameter(string name) {
exists(int i | exists(getDependencyDeclaration(i, name)) | result = astNode.getParameter(i)) exists(int i | exists(getDependencyDeclaration(i, name)) | result = super.getParameter(i))
} }
override AstNode getDependencyDeclaration(int i, string name) { override DataFlow::Node getDependencyDeclaration(int i, string name) {
exists(DataFlow::ValueNode decl | result = dependencies.getElement(i) and
decl = dependencies.getElement(i) and result.mayHaveStringValue(name)
decl.mayHaveStringValue(name) and
result = decl.getAstNode()
)
} }
override Function asFunction() { result = astNode } override DataFlow::FunctionNode asFunction() { result = this }
override AstNode getAnExplicitDependencyInjection() { override DataFlow::Node getAnExplicitDependencyInjection() {
result = getAPropertyDependencyInjection(astNode).getAstNode() result = getAPropertyDependencyInjection(this)
} }
} }
/** /**
* An injectable function embedded in an array of dependencies. * 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; DataFlow::FunctionNode function;
override ArrayExpr astNode;
FunctionWithExplicitDependencyAnnotation() { FunctionWithExplicitDependencyAnnotation() {
this.(DataFlow::SourceNode).flowsTo(any(DependencyInjection d).getAnInjectableFunction()) and 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) { override DataFlow::ParameterNode getDependencyParameter(string name) {
exists(int i | astNode.getElement(i).mayHaveStringValue(name) | exists(int i | super.getElement(i).mayHaveStringValue(name) | result = function.getParameter(i))
result = asFunction().getParameter(i)
)
} }
override AstNode getDependencyDeclaration(int i, string name) { override DataFlow::Node getDependencyDeclaration(int i, string name) {
result = astNode.getElement(i) and result = super.getElement(i) and
result.(Expr).mayHaveStringValue(name) result.mayHaveStringValue(name)
} }
override Function asFunction() { result = function.getAstNode() } override DataFlow::FunctionNode asFunction() { result = function }
override AstNode getAnExplicitDependencyInjection() { override DataFlow::Node getAnExplicitDependencyInjection() {
result = astNode or result = this or
result = function.(InjectableFunction).getAnExplicitDependencyInjection() result = function.(InjectableFunction).getAnExplicitDependencyInjection()
} }
} }

View File

@@ -27,7 +27,7 @@ private newtype TServiceReference =
*/ */
abstract class ServiceReference extends TServiceReference { abstract class ServiceReference extends TServiceReference {
/** Gets a textual representation of this element. */ /** Gets a textual representation of this element. */
string toString() { result = getName() } string toString() { result = this.getName() }
/** /**
* Gets the name of this reference. * Gets the name of this reference.
@@ -38,26 +38,26 @@ abstract class ServiceReference extends TServiceReference {
* Gets a data flow node that may refer to this service. * Gets a data flow node that may refer to this service.
*/ */
DataFlow::SourceNode getAReference() { DataFlow::SourceNode getAReference() {
result = DataFlow::parameterNode(any(ServiceRequest request).getDependencyParameter(this)) result = any(ServiceRequestNode request).getDependencyParameter(this)
} }
/** /**
* Gets an access to the referenced service. * Gets an access to the referenced service.
*/ */
Expr getAnAccess() { DataFlow::Node getAnAccess() {
result.mayReferToParameter(any(ServiceRequest request).getDependencyParameter(this)) any(ServiceRequestNode request).getDependencyParameter(this).flowsTo(result)
} }
/** /**
* Gets a call that invokes the referenced service. * Gets a call that invokes the referenced service.
*/ */
CallExpr getACall() { result.getCallee() = getAnAccess() } DataFlow::CallNode getACall() { result.getCalleeNode() = this.getAnAccess() }
/** /**
* Gets a method call that invokes method `methodName` on the referenced service. * 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.getReceiver() = this.getAnAccess() and
result.getMethodName() = methodName result.getMethodName() = methodName
} }
@@ -65,7 +65,7 @@ abstract class ServiceReference extends TServiceReference {
* Gets an access to property `propertyName` on the referenced service. * Gets an access to property `propertyName` on the referenced service.
*/ */
DataFlow::PropRef getAPropertyAccess(string propertyName) { DataFlow::PropRef getAPropertyAccess(string propertyName) {
result.getBase().asExpr() = getAnAccess() and result.getBase() = this.getAnAccess() and
result.getPropertyName() = propertyName result.getPropertyName() = propertyName
} }
@@ -93,7 +93,7 @@ class BuiltinServiceReference extends ServiceReference, MkBuiltinServiceReferenc
DataFlow::ParameterNode builtinServiceRef(string serviceName) { DataFlow::ParameterNode builtinServiceRef(string serviceName) {
exists(InjectableFunction f, BuiltinServiceReference service | exists(InjectableFunction f, BuiltinServiceReference service |
service.getName() = serviceName and service.getName() = serviceName and
result = DataFlow::parameterNode(f.getDependencyParameter(serviceName)) result = f.getDependencyParameter(serviceName)
) )
} }
@@ -244,17 +244,17 @@ abstract class RecipeDefinition extends DataFlow::CallNode, CustomServiceDefinit
this = moduleRef(_).getAMethodCall(methodName) or this = moduleRef(_).getAMethodCall(methodName) or
this = builtinServiceRef("$provide").getAMethodCall(methodName) this = builtinServiceRef("$provide").getAMethodCall(methodName)
) and ) and
getArgument(0).asExpr().mayHaveStringValue(name) this.getArgument(0).mayHaveStringValue(name)
} }
override string getName() { result = 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() { override DataFlow::Node getAnInjectableFunction() {
methodName != "value" and methodName != "value" and
methodName != "constant" 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, abstract private class CustomSpecialServiceDefinition extends CustomServiceDefinition,
DependencyInjection { DependencyInjection {
override DataFlow::Node getAnInjectableFunction() { result = getAFactoryFunction() } override DataFlow::Node getAnInjectableFunction() { result = this.getAFactoryFunction() }
} }
/** /**
@@ -281,7 +281,7 @@ private predicate isCustomServiceDefinitionOnModule(
DataFlow::Node factoryFunction DataFlow::Node factoryFunction
) { ) {
mce = moduleRef(_).getAMethodCall(moduleMethodName) and mce = moduleRef(_).getAMethodCall(moduleMethodName) and
mce.getArgument(0).asExpr().mayHaveStringValue(serviceName) and mce.getArgument(0).mayHaveStringValue(serviceName) and
factoryFunction = mce.getArgument(1) factoryFunction = mce.getArgument(1)
} }
@@ -296,7 +296,7 @@ private predicate isCustomServiceDefinitionOnProvider(
factoryArgument = mce.getOptionArgument(0, serviceName) factoryArgument = mce.getOptionArgument(0, serviceName)
or or
mce.getNumArgument() = 2 and mce.getNumArgument() = 2 and
mce.getArgument(0).asExpr().mayHaveStringValue(serviceName) and mce.getArgument(0).mayHaveStringValue(serviceName) and
factoryArgument = mce.getArgument(1) factoryArgument = mce.getArgument(1)
) )
} }
@@ -338,7 +338,7 @@ class FilterDefinition extends CustomSpecialServiceDefinition {
override DataFlow::SourceNode getAService() { override DataFlow::SourceNode getAService() {
exists(InjectableFunction f | exists(InjectableFunction f |
f = factoryFunction.getALocalSource() and 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() { override DataFlow::SourceNode getAService() {
exists(InjectableFunction f | exists(InjectableFunction f |
f = factoryFunction.getALocalSource() and 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. * 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. * 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. * 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 } LinkFunctionWithScopeInjection() { this instanceof LinkFunction }
override Parameter getDependencyParameter(ServiceReference service) { override DataFlow::ParameterNode getDependencyParameter(ServiceReference service) {
service instanceof ScopeServiceReference and service instanceof ScopeServiceReference and
result = this.(LinkFunction).getScopeParameter() 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. * A request for a service, in the form of a dependency-injected function.
*/ */
class InjectableFunctionServiceRequest extends ServiceRequest { class InjectableFunctionServiceRequest extends ServiceRequestNode {
InjectableFunction injectedFunction; InjectableFunction injectedFunction;
InjectableFunctionServiceRequest() { injectedFunction.getAstNode() = this } InjectableFunctionServiceRequest() { injectedFunction = this }
/** /**
* Gets the function of this request. * Gets the function of this request.
@@ -483,7 +498,9 @@ class InjectableFunctionServiceRequest extends ServiceRequest {
/** /**
* Gets a name of a requested service. * 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. * Gets a service with the specified name, relative to this request.
@@ -494,16 +511,16 @@ class InjectableFunctionServiceRequest extends ServiceRequest {
result.isInjectable() result.isInjectable()
} }
override Parameter getDependencyParameter(ServiceReference service) { override DataFlow::ParameterNode getDependencyParameter(ServiceReference service) {
service = injectedFunction.getAResolvedDependency(result) service = injectedFunction.getAResolvedDependency(result)
} }
} }
private DataFlow::SourceNode getFactoryFunctionResult(RecipeDefinition def) { private DataFlow::SourceNode getFactoryFunctionResult(RecipeDefinition def) {
exists(Function factoryFunction, InjectableFunction f | exists(DataFlow::FunctionNode factoryFunction, InjectableFunction f |
f = def.getAFactoryFunction() and f = def.getAFactoryFunction() and
factoryFunction = f.asFunction() and factoryFunction = f.asFunction() and
result.flowsToExpr(factoryFunction.getAReturnedExpr()) result.flowsTo(factoryFunction.getAReturn())
) )
} }
@@ -561,8 +578,8 @@ class ServiceRecipeDefinition extends RecipeDefinition {
*/ */
exists(InjectableFunction f | exists(InjectableFunction f |
f = getAFactoryFunction() and f = this.getAFactoryFunction() and
result.getAstNode() = f.asFunction() result = f.asFunction()
) )
} }
} }
@@ -574,7 +591,7 @@ class ServiceRecipeDefinition extends RecipeDefinition {
class ValueRecipeDefinition extends RecipeDefinition { class ValueRecipeDefinition extends RecipeDefinition {
ValueRecipeDefinition() { methodName = "value" } ValueRecipeDefinition() { methodName = "value" }
override DataFlow::SourceNode getAService() { result = getAFactoryFunction() } override DataFlow::SourceNode getAService() { result = this.getAFactoryFunction() }
} }
/** /**
@@ -584,7 +601,7 @@ class ValueRecipeDefinition extends RecipeDefinition {
class ConstantRecipeDefinition extends RecipeDefinition { class ConstantRecipeDefinition extends RecipeDefinition {
ConstantRecipeDefinition() { methodName = "constant" } ConstantRecipeDefinition() { methodName = "constant" }
override DataFlow::SourceNode getAService() { result = getAFactoryFunction() } override DataFlow::SourceNode getAService() { result = this.getAFactoryFunction() }
} }
/** /**
@@ -607,8 +624,8 @@ class ProviderRecipeDefinition extends RecipeDefinition {
*/ */
exists(DataFlow::ThisNode thiz, InjectableFunction f | exists(DataFlow::ThisNode thiz, InjectableFunction f |
f = getAFactoryFunction() and f = this.getAFactoryFunction() and
thiz.getBinder().getFunction() = f.asFunction() and thiz.getBinder() = f.asFunction() and
result = thiz.getAPropertySource("$get") result = thiz.getAPropertySource("$get")
) )
} }
@@ -632,7 +649,9 @@ class ConfigMethodDefinition extends ModuleApiCall {
/** /**
* Gets a provided configuration method. * Gets a provided configuration method.
*/ */
InjectableFunction getConfigMethod() { result.(DataFlow::SourceNode).flowsTo(getArgument(0)) } InjectableFunction getConfigMethod() {
result.(DataFlow::SourceNode).flowsTo(this.getArgument(0))
}
} }
/** /**
@@ -645,12 +664,12 @@ class RunMethodDefinition extends ModuleApiCall {
/** /**
* Gets a provided run method. * 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. * The `$scope` or `$rootScope` service.
*/ */
class ScopeServiceReference extends BuiltinServiceReference { class ScopeServiceReference extends BuiltinServiceReference {
ScopeServiceReference() { getName() = "$scope" or getName() = "$rootScope" } ScopeServiceReference() { this.getName() = "$scope" or this.getName() = "$rootScope" }
} }

View File

@@ -8,13 +8,14 @@ module Azure {
/** /**
* An expression that is used for authentication at Azure`. * An expression that is used for authentication at Azure`.
*/ */
class Credentials extends CredentialsExpr { class Credentials extends CredentialsNode {
string kind; string kind;
Credentials() { Credentials() {
exists(CallExpr mce, string methodName | exists(DataFlow::CallNode mce |
(methodName = "loginWithUsernamePassword" or methodName = "loginWithServicePrincipalSecret") and mce =
mce = DataFlow::moduleMember("ms-rest-azure", methodName).getACall().asExpr() DataFlow::moduleMember("ms-rest-azure",
["loginWithUsernamePassword", "loginWithServicePrincipalSecret"]).getACall()
| |
this = mce.getArgument(0) and kind = "user name" this = mce.getArgument(0) and kind = "user name"
or or

View File

@@ -270,16 +270,16 @@ module ClientRequest {
} }
/** An expression that is used as a credential in a request. */ /** An expression that is used as a credential in a request. */
private class AuthorizationHeader extends CredentialsExpr { private class AuthorizationHeader extends CredentialsNode {
AuthorizationHeader() { AuthorizationHeader() {
exists(DataFlow::PropWrite write | write.getPropertyName().regexpMatch("(?i)authorization") | exists(DataFlow::PropWrite write | write.getPropertyName().regexpMatch("(?i)authorization") |
this = write.getRhs().asExpr() this = write.getRhs()
) )
or or
exists(DataFlow::MethodCallNode call | call.getMethodName() = ["append", "set"] | exists(DataFlow::MethodCallNode call | call.getMethodName() = ["append", "set"] |
call.getNumArgument() = 2 and call.getNumArgument() = 2 and
call.getArgument(0).getStringValue().regexpMatch("(?i)authorization") and call.getArgument(0).getStringValue().regexpMatch("(?i)authorization") and
this = call.getArgument(1).asExpr() this = call.getArgument(1)
) )
} }

View File

@@ -10,10 +10,10 @@ module Connect {
/** /**
* An expression that creates a new Connect server. * An expression that creates a new Connect server.
*/ */
class ServerDefinition extends HTTP::Servers::StandardServerDefinition, CallExpr { class ServerDefinition extends HTTP::Servers::StandardServerDefinition, DataFlow::CallNode {
ServerDefinition() { ServerDefinition() {
// `app = connect()` // `app = connect()`
this = DataFlow::moduleImport("connect").getAnInvocation().asExpr() this = DataFlow::moduleImport("connect").getAnInvocation()
} }
} }
@@ -30,43 +30,45 @@ module Connect {
* *
* `kind` is one of: "error", "request", "response", "next". * `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. * 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. * 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. * A Connect route handler installed by a route setup.
*/ */
class StandardRouteHandler extends RouteHandler { class StandardRouteHandler extends RouteHandler, DataFlow::FunctionNode {
override Function astNode;
StandardRouteHandler() { this = any(RouteSetup setup).getARouteHandler() } StandardRouteHandler() { this = any(RouteSetup setup).getARouteHandler() }
override Parameter getRouteHandlerParameter(string kind) { override DataFlow::ParameterNode getRouteHandlerParameter(string kind) {
result = getRouteHandlerParameter(astNode, kind) result = getRouteHandlerParameter(this, kind)
} }
} }
/** /**
* A call to a Connect method that sets up a route. * 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; ServerDefinition server;
RouteSetup() { RouteSetup() {
getMethodName() = "use" and getMethodName() = "use" and
( (
// app.use(fun) // app.use(fun)
server.flowsTo(getReceiver()) server.ref().getAMethodCall() = this
or or
// app.use(...).use(fun) // app.use(...).use(fun)
this.getReceiver().(RouteSetup).getServer() = server this.getReceiver().(RouteSetup).getServer() = server
@@ -79,24 +81,32 @@ module Connect {
private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) {
t.start() and t.start() and
result = getARouteHandlerExpr().flow().getALocalSource() result = getARouteHandlerNode().getALocalSource()
or or
exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t)) exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t))
} }
override Expr getServer() { result = server } override DataFlow::Node getServer() { result = server }
/** Gets an argument that represents a route handler being registered. */ /**
Expr getARouteHandlerExpr() { result = getAnArgument() } * 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(<user>, <password>)`. */ /** An expression that is passed as `basicAuthConnect(<user>, <password>)`. */
class Credentials extends CredentialsExpr { class Credentials extends CredentialsNode {
string kind; string kind;
Credentials() { Credentials() {
exists(CallExpr call | exists(DataFlow::CallNode call |
call = DataFlow::moduleImport("basic-auth-connect").getAnInvocation().asExpr() and call = DataFlow::moduleImport("basic-auth-connect").getAnInvocation() and
call.getNumArgument() = 2 call.getNumArgument() = 2
| |
this = call.getArgument(0) and kind = "user name" this = call.getArgument(0) and kind = "user name"
@@ -108,22 +118,24 @@ module Connect {
override string getCredentialsKind() { result = kind } 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. * An access to a user-controlled Connect request input.
*/ */
private class RequestInputAccess extends HTTP::RequestInputAccess { private class RequestInputAccess extends HTTP::RequestInputAccess instanceof DataFlow::MethodCallNode {
RequestExpr request; RequestNode request;
string kind; string kind;
RequestInputAccess() { RequestInputAccess() {
request.getRouteHandler() instanceof StandardRouteHandler and request.getRouteHandler() instanceof StandardRouteHandler and
exists(PropAccess cookies | exists(DataFlow::PropRead cookies |
// `req.cookies.get(<name>)` // `req.cookies.get(<name>)`
kind = "cookie" and kind = "cookie" and
cookies.accesses(request, "cookies") and cookies.accesses(request, "cookies") and
this.asExpr().(MethodCallExpr).calls(cookies, "get") super.calls(cookies, "get")
) )
} }

View File

@@ -52,7 +52,7 @@ module ConnectExpressShared {
/** /**
* Holds if `function` appears to match the given signature based on parameter naming. * 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.getNumParameter() = sig.getArity() and
function.getParameter(sig.getParameterIndex("request")).getName() = ["req", "request"] and function.getParameter(sig.getParameterIndex("request")).getName() = ["req", "request"] and
function.getParameter(sig.getParameterIndex("response")).getName() = ["res", "response"] and function.getParameter(sig.getParameterIndex("response")).getName() = ["res", "response"] and
@@ -71,8 +71,8 @@ module ConnectExpressShared {
* so the caller should restrict the function accordingly. * so the caller should restrict the function accordingly.
*/ */
pragma[inline] pragma[inline]
private Parameter getRouteHandlerParameter( private DataFlow::ParameterNode getRouteHandlerParameter(
Function routeHandler, RouteHandlerSignature sig, string kind DataFlow::FunctionNode routeHandler, RouteHandlerSignature sig, string kind
) { ) {
result = routeHandler.getParameter(sig.getParameterIndex(kind)) result = routeHandler.getParameter(sig.getParameterIndex(kind))
} }
@@ -83,7 +83,9 @@ module ConnectExpressShared {
* `kind` is one of: "error", "request", "response", "next". * `kind` is one of: "error", "request", "response", "next".
*/ */
pragma[inline] pragma[inline]
Parameter getRouteParameterHandlerParameter(Function routeHandler, string kind) { DataFlow::ParameterNode getRouteParameterHandlerParameter(
DataFlow::FunctionNode routeHandler, string kind
) {
result = result =
getRouteHandlerParameter(routeHandler, RouteHandlerSignature::requestResponseNextParameter(), getRouteHandlerParameter(routeHandler, RouteHandlerSignature::requestResponseNextParameter(),
kind) kind)
@@ -95,7 +97,7 @@ module ConnectExpressShared {
* `kind` is one of: "error", "request", "response", "next". * `kind` is one of: "error", "request", "response", "next".
*/ */
pragma[inline] pragma[inline]
Parameter getRouteHandlerParameter(Function routeHandler, string kind) { DataFlow::ParameterNode getRouteHandlerParameter(DataFlow::FunctionNode routeHandler, string kind) {
if routeHandler.getNumParameter() = 4 if routeHandler.getNumParameter() = 4
then then
// For arity 4 there is ambiguity between (err, req, res, next) and (req, res, next, param) // 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 { class RouteHandlerCandidate extends HTTP::RouteHandlerCandidate {
RouteHandlerCandidate() { RouteHandlerCandidate() {
matchesSignature(astNode, _) and matchesSignature(this, _) and
not ( not (
// heuristic: not a class method (the server invokes this with a function call) // heuristic: not a class method (the server invokes this with a function call)
astNode = any(MethodDefinition def).getBody() astNode = any(MethodDefinition def).getBody()

View File

@@ -76,7 +76,7 @@ private predicate canHaveSensitiveCookie(DataFlow::Node node) {
HeuristicNames::nameIndicatesSensitiveData([s, getCookieName(s)], _) HeuristicNames::nameIndicatesSensitiveData([s, getCookieName(s)], _)
) )
or or
node.asExpr() instanceof SensitiveExpr node instanceof SensitiveNode
} }
/** /**
@@ -271,30 +271,27 @@ private module ExpressCookies {
/** /**
* A cookie set using `response.cookie` from `express` module (https://expressjs.com/en/api.html#res.cookie). * A cookie set using `response.cookie` from `express` module (https://expressjs.com/en/api.html#res.cookie).
*/ */
private class InsecureExpressCookieResponse extends CookieWrites::CookieWrite, private class InsecureExpressCookieResponse extends CookieWrites::CookieWrite instanceof Express::SetCookie {
DataFlow::MethodCallNode {
InsecureExpressCookieResponse() { this.asExpr() instanceof Express::SetCookie }
override predicate isSecure() { override predicate isSecure() {
// A cookie is secure if there are cookie options with the `secure` flag set to `true`. // A cookie is secure if there are cookie options with the `secure` flag set to `true`.
// The default is `false`. // 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 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() { override predicate isHttpOnly() {
// A cookie is httpOnly if there are cookie options with the `httpOnly` flag set to `true`. // A cookie is httpOnly if there are cookie options with the `httpOnly` flag set to `true`.
// The default is `false`. // 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 not value.mayHaveBooleanValue(false) // anything but `false` is accepted as being maybe true
) )
} }
override string getSameSite() { 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() { HttpCookieWrite() {
exists(HTTP::CookieDefinition setCookie | exists(HTTP::CookieDefinition setCookie |
this.asExpr() = setCookie.getHeaderArgument() and this = setCookie.getHeaderArgument() and
not this instanceof DataFlow::ArrayCreationNode not this instanceof DataFlow::ArrayCreationNode
or or
this = setCookie.getHeaderArgument().flow().(DataFlow::ArrayCreationNode).getAnElement() this = setCookie.getHeaderArgument().(DataFlow::ArrayCreationNode).getAnElement()
) and ) and
header = header =
[ [

View File

@@ -6,10 +6,27 @@
import javascript import javascript
/** /**
* DEPRECATED: Use `CredentialsNode` instead.
* An expression whose value is used to supply credentials such * An expression whose value is used to supply credentials such
* as a user name, a password, or a key. * 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, * Gets a description of the kind of credential this expression is used as,
* such as `"user name"`, `"password"`, `"key"`. * such as `"user name"`, `"password"`, `"key"`.
@@ -17,12 +34,10 @@ abstract class CredentialsExpr extends Expr {
abstract string getCredentialsKind(); abstract string getCredentialsKind();
} }
private class CredentialsFromModel extends CredentialsExpr { private class CredentialsFromModel extends CredentialsNode {
string kind; string kind;
CredentialsFromModel() { CredentialsFromModel() { this = ModelOutput::getASinkNode("credentials[" + kind + "]").asSink() }
this = ModelOutput::getASinkNode("credentials[" + kind + "]").asSink().asExpr()
}
override string getCredentialsKind() { result = kind } override string getCredentialsKind() { result = kind }
} }

View File

@@ -8,11 +8,11 @@ import semmle.javascript.security.CryptoAlgorithms
/** /**
* An application of a cryptographic algorithm. * 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. * 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. * Gets the applied algorithm.
@@ -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 { class CryptographicKeyCredentialsExpr extends CredentialsNode instanceof CryptographicKey {
CryptographicKeyCredentialsExpr() { this = any(CryptographicKey k).asExpr() }
override string getCredentialsKind() { result = "key" } override string getCredentialsKind() { result = "key" }
} }
@@ -58,8 +56,8 @@ class CryptographicKeyCredentialsExpr extends CredentialsExpr {
* A model of the asmCrypto library. * A model of the asmCrypto library.
*/ */
private module AsmCrypto { private module AsmCrypto {
private class Apply extends CryptographicOperation { private class Apply extends CryptographicOperation instanceof DataFlow::CallNode {
Expr input; DataFlow::Node input;
CryptographicAlgorithm algorithm; // non-functional CryptographicAlgorithm algorithm; // non-functional
Apply() { Apply() {
@@ -73,17 +71,15 @@ private module AsmCrypto {
* ``` * ```
*/ */
exists(DataFlow::CallNode mce | this = mce.asExpr() |
exists(DataFlow::SourceNode asmCrypto, string algorithmName | exists(DataFlow::SourceNode asmCrypto, string algorithmName |
asmCrypto = DataFlow::globalVarRef("asmCrypto") and asmCrypto = DataFlow::globalVarRef("asmCrypto") and
algorithm.matchesName(algorithmName) and algorithm.matchesName(algorithmName) and
mce = asmCrypto.getAPropertyRead(algorithmName).getAMemberCall(_) and this = asmCrypto.getAPropertyRead(algorithmName).getAMemberCall(_) and
input = mce.getAnArgument().asExpr() input = this.getAnArgument()
)
) )
} }
override Expr getInput() { result = input } override DataFlow::Node getInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm } override CryptographicAlgorithm getAlgorithm() { result = algorithm }
} }
@@ -97,9 +93,8 @@ private module BrowserIdCrypto {
Key() { this = any(Apply apply).getKey() } Key() { this = any(Apply apply).getKey() }
} }
private class Apply extends CryptographicOperation { private class Apply extends CryptographicOperation instanceof DataFlow::MethodCallNode {
CryptographicAlgorithm algorithm; // non-functional CryptographicAlgorithm algorithm; // non-functional
MethodCallExpr mce;
Apply() { Apply() {
/* /*
@@ -118,7 +113,6 @@ private module BrowserIdCrypto {
* ``` * ```
*/ */
this = mce and
exists( exists(
DataFlow::SourceNode mod, DataFlow::Node algorithmNameNode, DataFlow::CallNode keygen, DataFlow::SourceNode mod, DataFlow::Node algorithmNameNode, DataFlow::CallNode keygen,
DataFlow::FunctionNode callback DataFlow::FunctionNode callback
@@ -128,15 +122,15 @@ private module BrowserIdCrypto {
algorithmNameNode = keygen.getOptionArgument(0, "algorithm") and algorithmNameNode = keygen.getOptionArgument(0, "algorithm") and
algorithm.matchesName(algorithmNameNode.getStringValue()) and algorithm.matchesName(algorithmNameNode.getStringValue()) and
callback = keygen.getCallback(1) 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 } override CryptographicAlgorithm getAlgorithm() { result = algorithm }
DataFlow::Node getKey() { result.asExpr() = mce.getArgument(1) } DataFlow::Node getKey() { result = super.getArgument(1) }
} }
} }
@@ -217,14 +211,12 @@ private module NodeJSCrypto {
override predicate isSymmetricKey() { none() } override predicate isSymmetricKey() { none() }
} }
private class Apply extends CryptographicOperation, MethodCallExpr { private class Apply extends CryptographicOperation instanceof DataFlow::MethodCallNode {
InstantiatedAlgorithm instantiation; InstantiatedAlgorithm instantiation;
Apply() { Apply() { this = instantiation.getAMethodCall(any(string m | m = "update" or m = "write")) }
this = instantiation.getAMethodCall(any(string m | m = "update" or m = "write")).asExpr()
}
override Expr getInput() { result = this.getArgument(0) } override DataFlow::Node getInput() { result = super.getArgument(0) }
override CryptographicAlgorithm getAlgorithm() { result = instantiation.getAlgorithm() } override CryptographicAlgorithm getAlgorithm() { result = instantiation.getAlgorithm() }
} }
@@ -260,7 +252,7 @@ private module CryptoJS {
/** /**
* Matches `CryptoJS.<algorithmName>` and `require("crypto-js/<algorithmName>")` * Matches `CryptoJS.<algorithmName>` and `require("crypto-js/<algorithmName>")`
*/ */
private DataFlow::SourceNode getAlgorithmExpr(CryptographicAlgorithm algorithm) { private DataFlow::SourceNode getAlgorithmNode(CryptographicAlgorithm algorithm) {
exists(string algorithmName | algorithm.matchesName(algorithmName) | exists(string algorithmName | algorithm.matchesName(algorithmName) |
exists(DataFlow::SourceNode mod | mod = DataFlow::moduleImport("crypto-js") | exists(DataFlow::SourceNode mod | mod = DataFlow::moduleImport("crypto-js") |
result = mod.getAPropertyRead(algorithmName) or result = mod.getAPropertyRead(algorithmName) or
@@ -274,7 +266,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"); * var CryptoJS = require("crypto-js");
@@ -288,11 +282,13 @@ private module CryptoJS {
* Also matches where `CryptoJS.<algorithmName>` has been replaced by `require("crypto-js/<algorithmName>")` * Also matches where `CryptoJS.<algorithmName>` has been replaced by `require("crypto-js/<algorithmName>")`
*/ */
result = getAlgorithmExpr(algorithm).getAMemberCall("encrypt") and result = getAlgorithmNode(algorithm).getAMemberCall("encrypt") and
input = result.getArgument(0).asExpr() 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"); * var CryptoJS = require("crypto-js");
@@ -307,20 +303,20 @@ private module CryptoJS {
* Also matches where `CryptoJS.<algorithmName>` has been replaced by `require("crypto-js/<algorithmName>")` * Also matches where `CryptoJS.<algorithmName>` has been replaced by `require("crypto-js/<algorithmName>")`
*/ */
result = getAlgorithmExpr(algorithm).getACall() and result = getAlgorithmNode(algorithm).getACall() and
input = result.getArgument(0).asExpr() input = result.getArgument(0)
} }
private class Apply extends CryptographicOperation { private class Apply extends CryptographicOperation {
Expr input; DataFlow::Node input;
CryptographicAlgorithm algorithm; // non-functional CryptographicAlgorithm algorithm; // non-functional
Apply() { Apply() {
this = getEncryptionApplication(input, algorithm).asExpr() or this = getEncryptionApplication(input, algorithm) or
this = getDirectApplication(input, algorithm).asExpr() this = getDirectApplication(input, algorithm)
} }
override Expr getInput() { result = input } override DataFlow::Node getInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm } override CryptographicAlgorithm getAlgorithm() { result = algorithm }
} }
@@ -328,7 +324,7 @@ private module CryptoJS {
private class Key extends CryptographicKey { private class Key extends CryptographicKey {
Key() { Key() {
exists(DataFlow::SourceNode e, CryptographicAlgorithm algorithm | exists(DataFlow::SourceNode e, CryptographicAlgorithm algorithm |
e = getAlgorithmExpr(algorithm) e = getAlgorithmNode(algorithm)
| |
exists(string name | exists(string name |
name = "encrypt" or name = "encrypt" or
@@ -351,7 +347,7 @@ private module CryptoJS {
CreateKey() { CreateKey() {
// var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 }); // var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 });
this = this =
getAlgorithmExpr(any(CryptographicAlgorithm algo | algo.getName() = algorithm)).getACall() and getAlgorithmNode(any(CryptographicAlgorithm algo | algo.getName() = algorithm)).getACall() and
optionArg = 2 optionArg = 2
or or
// var key = CryptoJS.algo.PBKDF2.create({ keySize: 8 }); // var key = CryptoJS.algo.PBKDF2.create({ keySize: 8 });
@@ -378,8 +374,8 @@ private module CryptoJS {
* A model of the TweetNaCl library. * A model of the TweetNaCl library.
*/ */
private module TweetNaCl { private module TweetNaCl {
private class Apply extends CryptographicOperation instanceof MethodCallExpr { private class Apply extends CryptographicOperation instanceof DataFlow::CallNode {
Expr input; DataFlow::Node input;
CryptographicAlgorithm algorithm; CryptographicAlgorithm algorithm;
Apply() { Apply() {
@@ -400,12 +396,12 @@ private module TweetNaCl {
name = "sign" and algorithm.matchesName("ed25519") name = "sign" and algorithm.matchesName("ed25519")
| |
(mod = DataFlow::moduleImport("nacl") or mod = DataFlow::moduleImport("nacl-fast")) and (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 super.getArgument(0) = input
) )
} }
override Expr getInput() { result = input } override DataFlow::Node getInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm } override CryptographicAlgorithm getAlgorithm() { result = algorithm }
} }
@@ -421,7 +417,7 @@ private module HashJs {
* - `require("hash.js/lib/hash/<algorithmName>")`() * - `require("hash.js/lib/hash/<algorithmName>")`()
* - `require("hash.js/lib/hash/sha/<sha-algorithm-suffix>")`() * - `require("hash.js/lib/hash/sha/<sha-algorithm-suffix>")`()
*/ */
private DataFlow::CallNode getAlgorithmExpr(CryptographicAlgorithm algorithm) { private DataFlow::CallNode getAlgorithmNode(CryptographicAlgorithm algorithm) {
exists(string algorithmName | algorithm.matchesName(algorithmName) | exists(string algorithmName | algorithm.matchesName(algorithmName) |
result = DataFlow::moduleMember("hash.js", algorithmName).getACall() result = DataFlow::moduleMember("hash.js", algorithmName).getACall()
or or
@@ -438,8 +434,8 @@ private module HashJs {
) )
} }
private class Apply extends CryptographicOperation instanceof MethodCallExpr { private class Apply extends CryptographicOperation instanceof DataFlow::CallNode {
Expr input; DataFlow::Node input;
CryptographicAlgorithm algorithm; // non-functional CryptographicAlgorithm algorithm; // non-functional
Apply() { Apply() {
@@ -456,11 +452,11 @@ private module HashJs {
* Also matches where `hash.<algorithmName>()` has been replaced by a more specific require a la `require("hash.js/lib/hash/sha/512")` * Also matches where `hash.<algorithmName>()` 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) input = super.getArgument(0)
} }
override Expr getInput() { result = input } override DataFlow::Node getInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm } override CryptographicAlgorithm getAlgorithm() { result = algorithm }
} }
@@ -492,7 +488,7 @@ private module Forge {
// `require('forge').cipher.createCipher("3DES-CBC").update("secret", "key");` // `require('forge').cipher.createCipher("3DES-CBC").update("secret", "key");`
(createName = "createCipher" or createName = "createDecipher") and (createName = "createCipher" or createName = "createDecipher") and
this = mod.getAPropertyRead("cipher").getAMemberCall(createName) 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 cipherName = cipherPrefix + "-" + cipherSuffix and
cipherSuffix = ["CBC", "CFB", "CTR", "ECB", "GCM", "OFB"] and cipherSuffix = ["CBC", "CFB", "CTR", "ECB", "GCM", "OFB"] and
algorithmName = cipherPrefix and algorithmName = cipherPrefix and
@@ -531,19 +527,19 @@ private module Forge {
override CryptographicAlgorithm getAlgorithm() { result = algorithm } override CryptographicAlgorithm getAlgorithm() { result = algorithm }
} }
private class Apply extends CryptographicOperation instanceof MethodCallExpr { private class Apply extends CryptographicOperation instanceof DataFlow::CallNode {
Expr input; DataFlow::Node input;
CryptographicAlgorithm algorithm; // non-functional CryptographicAlgorithm algorithm; // non-functional
Apply() { Apply() {
exists(Cipher cipher | exists(Cipher cipher |
this = cipher.getAMemberCall("update").asExpr() and this = cipher.getAMemberCall("update") and
super.getArgument(0) = input and super.getArgument(0) = input and
algorithm = cipher.getAlgorithm() algorithm = cipher.getAlgorithm()
) )
} }
override Expr getInput() { result = input } override DataFlow::Node getInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm } override CryptographicAlgorithm getAlgorithm() { result = algorithm }
} }
@@ -590,8 +586,8 @@ private module Forge {
* A model of the md5 library. * A model of the md5 library.
*/ */
private module Md5 { private module Md5 {
private class Apply extends CryptographicOperation instanceof CallExpr { private class Apply extends CryptographicOperation instanceof DataFlow::CallNode {
Expr input; DataFlow::Node input;
CryptographicAlgorithm algorithm; CryptographicAlgorithm algorithm;
Apply() { Apply() {
@@ -599,12 +595,12 @@ private module Md5 {
exists(DataFlow::SourceNode mod | exists(DataFlow::SourceNode mod |
mod = DataFlow::moduleImport("md5") and mod = DataFlow::moduleImport("md5") and
algorithm.matchesName("MD5") and algorithm.matchesName("MD5") and
this = mod.getACall().asExpr() and this = mod.getACall() and
super.getArgument(0) = input super.getArgument(0) = input
) )
} }
override Expr getInput() { result = input } override DataFlow::Node getInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm } override CryptographicAlgorithm getAlgorithm() { result = algorithm }
} }
@@ -614,8 +610,8 @@ private module Md5 {
* A model of the bcrypt, bcryptjs, bcrypt-nodejs libraries. * A model of the bcrypt, bcryptjs, bcrypt-nodejs libraries.
*/ */
private module Bcrypt { private module Bcrypt {
private class Apply extends CryptographicOperation instanceof MethodCallExpr { private class Apply extends CryptographicOperation instanceof DataFlow::CallNode {
Expr input; DataFlow::Node input;
CryptographicAlgorithm algorithm; CryptographicAlgorithm algorithm;
Apply() { Apply() {
@@ -632,12 +628,12 @@ private module Bcrypt {
methodName = "hashSync" methodName = "hashSync"
) and ) and
mod = DataFlow::moduleImport(moduleName) and mod = DataFlow::moduleImport(moduleName) and
this = mod.getAMemberCall(methodName).asExpr() and this = mod.getAMemberCall(methodName) and
super.getArgument(0) = input super.getArgument(0) = input
) )
} }
override Expr getInput() { result = input } override DataFlow::Node getInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm } override CryptographicAlgorithm getAlgorithm() { result = algorithm }
} }
@@ -647,23 +643,23 @@ private module Bcrypt {
* A model of the hasha library. * A model of the hasha library.
*/ */
private module Hasha { private module Hasha {
private class Apply extends CryptographicOperation instanceof CallExpr { private class Apply extends CryptographicOperation instanceof DataFlow::CallNode {
Expr input; DataFlow::Node input;
CryptographicAlgorithm algorithm; CryptographicAlgorithm algorithm;
Apply() { Apply() {
// `require('hasha')('unicorn', { algorithm: "md5" });` // `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 mod = DataFlow::moduleImport("hasha") and
this = mod.getACall().asExpr() and this = mod.getACall() and
super.getArgument(0) = input and super.getArgument(0) = input and
algorithm.matchesName(algorithmName) and algorithm.matchesName(algorithmName) and
super.hasOptionArgument(1, "algorithm", algorithmNameNode) and super.getOptionArgument(1, "algorithm") = algorithmNameNode and
algorithmNameNode.mayHaveStringValue(algorithmName) algorithmNameNode.mayHaveStringValue(algorithmName)
) )
} }
override Expr getInput() { result = input } override DataFlow::Node getInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm } override CryptographicAlgorithm getAlgorithm() { result = algorithm }
} }

View File

@@ -8,12 +8,12 @@ module DigitalOcean {
/** /**
* An expression that is used for authentication at DigitalOcean: `digitalocean.client(<token>)`. * An expression that is used for authentication at DigitalOcean: `digitalocean.client(<token>)`.
*/ */
class Credentials extends CredentialsExpr { class Credentials extends CredentialsNode {
string kind; string kind;
Credentials() { Credentials() {
exists(CallExpr mce | exists(DataFlow::CallNode mce |
mce = DataFlow::moduleMember("digitalocean", "client").getACall().asExpr() mce = DataFlow::moduleMember("digitalocean", "client").getACall()
| |
this = mce.getArgument(0) and kind = "token" this = mce.getArgument(0) and kind = "token"
) )

View File

@@ -40,31 +40,27 @@ module Express {
) )
} }
/** /** Holds if `e` may refer to the given `router` object. */
* Holds if `e` may refer to the given `router` object. private predicate isRouter(DataFlow::Node e, RouterDefinition router) { router.ref().flowsTo(e) }
*/
private predicate isRouter(Expr e, RouterDefinition router) { router.flowsTo(e) }
/** /**
* Holds if `e` may refer to a router object. * Holds if `e` may refer to a router object.
*/ */
private predicate isRouter(Expr e) { private predicate isRouter(DataFlow::Node e) {
isRouter(e, _) isRouter(e, _)
or or
e.getType().hasUnderlyingType("express", "Router") e.asExpr().getType().hasUnderlyingType("express", "Router")
or or
// created by `webpack-dev-server` // created by `webpack-dev-server`
WebpackDevServer::webpackDevServerApp().flowsToExpr(e) WebpackDevServer::webpackDevServerApp().flowsTo(e)
} }
/** /**
* DEPRECATED: Use `RouterDefinition.ref()` or `RouteSetup` instead.
* An expression that refers to a route. * An expression that refers to a route.
*/ */
class RouteExpr extends MethodCallExpr { deprecated class RouteExpr extends MethodCallExpr {
RouteExpr() { isRouter(this) } RouteExpr() { isRouter(this.flow()) }
/** Gets the router from which this route was created, if it is known. */
RouterDefinition getRouter() { isRouter(this, result) }
} }
/** /**
@@ -83,13 +79,13 @@ module Express {
private class RouterRange extends Routing::Router::Range { private class RouterRange extends Routing::Router::Range {
RouterDefinition def; RouterDefinition def;
RouterRange() { this = def.flow() } RouterRange() { this = def }
override DataFlow::SourceNode getAReference() { result = def.ref() } override DataFlow::SourceNode getAReference() { result = def.ref() }
} }
private class RoutingTreeSetup extends Routing::RouteSetup::MethodCall { private class RoutingTreeSetup extends Routing::RouteSetup::MethodCall {
RoutingTreeSetup() { this.asExpr() instanceof RouteSetup } RoutingTreeSetup() { this instanceof RouteSetup }
override string getRelativePath() { override string getRelativePath() {
not this.getMethodName() = "param" and // do not treat parameter name as a path not this.getMethodName() = "param" and // do not treat parameter name as a path
@@ -140,7 +136,7 @@ module Express {
/** /**
* A call to an Express router method that sets up a route. * 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() { RouteSetup() {
isRouter(this.getReceiver()) and isRouter(this.getReceiver()) and
this.getMethodName() = routeSetupMethodName() this.getMethodName() = routeSetupMethodName()
@@ -156,12 +152,23 @@ module Express {
predicate isUseCall() { this.getMethodName() = "use" } predicate isUseCall() { this.getMethodName() = "use" }
/** /**
* DEPRECATED: Use `getRouteHandlerNode` instead.
* Gets the `n`th handler registered by this setup, with 0 being the first. * Gets the `n`th handler registered by this setup, with 0 being the first.
* *
* This differs from `getARouteHandler` in that the argument expression is * This differs from `getARouteHandler` in that the argument expression is
* returned, not its dataflow source. * returned, not its dataflow source.
*/ */
Expr getRouteHandlerExpr(int index) { deprecated Expr getRouteHandlerExpr(int index) {
result = this.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 // 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. // a function, we consider it to be a route handler, otherwise a URI pattern.
exists(AnalyzedNode firstArg | firstArg = this.getArgument(0).analyze() | exists(AnalyzedNode firstArg | firstArg = this.getArgument(0).analyze() |
@@ -173,21 +180,39 @@ module Express {
) )
} }
/** 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) 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() { override DataFlow::SourceNode getARouteHandler() {
result = this.getARouteHandler(DataFlow::TypeBackTracker::end()) result = this.getARouteHandler(DataFlow::TypeBackTracker::end())
} }
private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) {
t.start() and t.start() and
result = this.getARouteHandlerExpr().flow().getALocalSource() result = this.getARouteHandlerNode().getALocalSource()
or or
exists(DataFlow::TypeBackTracker t2, DataFlow::SourceNode succ | exists(DataFlow::TypeBackTracker t2, DataFlow::SourceNode succ |
succ = this.getARouteHandler(t2) succ = this.getARouteHandler(t2)
@@ -199,7 +224,9 @@ module Express {
) )
} }
override Expr getServer() { result.(Application).getARouteHandler() = this.getARouteHandler() } override DataFlow::Node getServer() {
result.(Application).getARouteHandler() = this.getARouteHandler()
}
/** /**
* Gets the HTTP request type this is registered for, if any. * Gets the HTTP request type this is registered for, if any.
@@ -233,16 +260,16 @@ module Express {
/** /**
* A call that sets up a Passport router that includes the request object. * 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::ModuleImportNode importNode;
DataFlow::FunctionNode callback; DataFlow::FunctionNode callback;
// looks for this pattern: passport.use(new Strategy({passReqToCallback: true}, callback)) // looks for this pattern: passport.use(new Strategy({passReqToCallback: true}, callback))
PassportRouteSetup() { PassportRouteSetup() {
importNode = DataFlow::moduleImport("passport") and importNode = DataFlow::moduleImport("passport") and
this = importNode.getAMemberCall("use").asExpr() and this = importNode.getAMemberCall("use") and
exists(DataFlow::NewNode strategy | exists(DataFlow::NewNode strategy |
strategy.flowsToExpr(this.getArgument(0)) and strategy.flowsTo(this.getArgument(0)) and
strategy.getNumArgument() = 2 and strategy.getNumArgument() = 2 and
// new Strategy({passReqToCallback: true}, ...) // new Strategy({passReqToCallback: true}, ...)
strategy.getOptionArgument(0, "passReqToCallback").mayHaveBooleanValue(true) and strategy.getOptionArgument(0, "passReqToCallback").mayHaveBooleanValue(true) and
@@ -250,7 +277,7 @@ module Express {
) )
} }
override Expr getServer() { result = importNode.asExpr() } override DataFlow::Node getServer() { result = importNode }
override DataFlow::SourceNode getARouteHandler() { result = callback } override DataFlow::SourceNode getARouteHandler() { result = callback }
} }
@@ -259,17 +286,61 @@ module Express {
* The callback given to passport in PassportRouteSetup. * The callback given to passport in PassportRouteSetup.
*/ */
private class PassportRouteHandler extends RouteHandler, HTTP::Servers::StandardRouteHandler, private class PassportRouteHandler extends RouteHandler, HTTP::Servers::StandardRouteHandler,
DataFlow::ValueNode { DataFlow::FunctionNode {
override Function astNode;
PassportRouteHandler() { this = any(PassportRouteSetup setup).getARouteHandler() } PassportRouteHandler() { this = any(PassportRouteSetup setup).getARouteHandler() }
override Parameter getRouteHandlerParameter(string kind) { override DataFlow::ParameterNode getRouteHandlerParameter(string kind) {
kind = "request" and kind = "request" and
result = astNode.getParameter(0) result = this.getParameter(0)
} }
} }
/**
* DEPRECATED: Use `RouteHandlerNode` instead.
* 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.
*/
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: * An expression used as an Express route handler, such as `submitHandler` below:
* ``` * ```
@@ -279,11 +350,11 @@ module Express {
* Unlike `RouterHandler`, this is the argument passed to a setup, as opposed to * Unlike `RouterHandler`, this is the argument passed to a setup, as opposed to
* a function that flows into such an argument. * a function that flows into such an argument.
*/ */
class RouteHandlerExpr extends Expr { class RouteHandlerNode extends DataFlow::Node {
RouteSetup setup; RouteSetup setup;
int index; int index;
RouteHandlerExpr() { this = setup.getRouteHandlerExpr(index) } RouteHandlerNode() { this = setup.getRouteHandlerNode(index) }
/** /**
* Gets the setup call that registers this route handler. * Gets the setup call that registers this route handler.
@@ -294,7 +365,7 @@ module Express {
* Gets the function body of this handler, if it is defined locally. * Gets the function body of this handler, if it is defined locally.
*/ */
RouteHandler getBody() { RouteHandler getBody() {
exists(DataFlow::SourceNode source | source = this.flow().getALocalSource() | exists(DataFlow::SourceNode source | source = this.getALocalSource() |
result = source result = source
or or
DataFlow::functionOneWayForwardingStep(result.(DataFlow::SourceNode).getALocalUse(), source) DataFlow::functionOneWayForwardingStep(result.(DataFlow::SourceNode).getALocalUse(), source)
@@ -306,7 +377,7 @@ module Express {
*/ */
predicate isLastHandler() { predicate isLastHandler() {
not setup.isUseCall() and not setup.isUseCall() and
not exists(setup.getRouteHandlerExpr(index + 1)) not exists(setup.getRouteHandlerNode(index + 1))
} }
/** /**
@@ -331,10 +402,11 @@ module Express {
* In this case, the previous from `foo` is `auth` although they do not act on the * In this case, the previous from `foo` is `auth` although they do not act on the
* same requests. * same requests.
*/ */
Express::RouteHandlerExpr getPreviousMiddleware() { Express::RouteHandlerNode getPreviousMiddleware() {
index = 0 and result = setup.getRouter().getMiddlewareStackAt(setup.getAPredecessor()) index = 0 and
result = setup.getRouter().getMiddlewareStackAt(setup.asExpr().getAPredecessor())
or or
index > 0 and result = setup.getRouteHandlerExpr(index - 1) index > 0 and result = setup.getRouteHandlerNode(index - 1)
or or
// Outside the router's original container, use the flow-insensitive model of its middleware stack. // 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. // Its state is not tracked to CFG nodes outside its original container.
@@ -348,7 +420,7 @@ module Express {
/** /**
* Gets a route handler that may follow immediately after this one in its route stack. * 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 * Gets a route handler that precedes this one (not necessarily immediately), may handle
@@ -361,7 +433,7 @@ module Express {
* router installs a route handler `r1` on a path that matches the path of a route handler * 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`. * `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 result = this.getPreviousMiddleware+() and
exists(RouteSetup resSetup | resSetup = result.getSetup() | exists(RouteSetup resSetup | resSetup = result.getSetup() |
// check whether request methods are compatible // check whether request methods are compatible
@@ -378,7 +450,7 @@ module Express {
or or
// if this is a sub-router, any previously installed middleware for the same // if this is a sub-router, any previously installed middleware for the same
// request method will necessarily match // request method will necessarily match
exists(RouteHandlerExpr outer | exists(RouteHandlerNode outer |
setup.getRouter() = outer.getAsSubRouter() and setup.getRouter() = outer.getAsSubRouter() and
outer.getSetup().handlesSameRequestMethodAs(setup) and outer.getSetup().handlesSameRequestMethodAs(setup) and
result = outer.getAMatchingAncestor() result = outer.getAMatchingAncestor()
@@ -404,46 +476,51 @@ module Express {
* *
* `kind` is one of: "error", "request", "response", "next", or "parameter". * `kind` is one of: "error", "request", "response", "next", or "parameter".
*/ */
abstract Parameter getRouteHandlerParameter(string kind); abstract DataFlow::ParameterNode getRouteHandlerParameter(string kind);
/** /**
* Gets the parameter of the route handler that contains the request object. * Gets the parameter of the route handler that contains the request object.
*/ */
Parameter getRequestParameter() { result = this.getRouteHandlerParameter("request") } DataFlow::ParameterNode getRequestParameter() {
result = this.getRouteHandlerParameter("request")
}
/** /**
* Gets the parameter of the route handler that contains the response object. * Gets the parameter of the route handler that contains the response object.
*/ */
Parameter getResponseParameter() { result = this.getRouteHandlerParameter("response") } DataFlow::ParameterNode getResponseParameter() {
result = this.getRouteHandlerParameter("response")
}
/** /**
* Gets a request body access of this handler. * Gets a request body access of this handler.
*/ */
Expr getARequestBodyAccess() { result.(PropAccess).accesses(this.getARequestExpr(), "body") } DataFlow::PropRead getARequestBodyAccess() { result.accesses(this.getARequestNode(), "body") }
} }
/** /**
* An Express route handler installed by a route setup. * An Express route handler installed by a route setup.
*/ */
class StandardRouteHandler extends RouteHandler, HTTP::Servers::StandardRouteHandler, class StandardRouteHandler extends RouteHandler, HTTP::Servers::StandardRouteHandler,
DataFlow::ValueNode { DataFlow::FunctionNode {
override Function astNode;
RouteSetup routeSetup; RouteSetup routeSetup;
StandardRouteHandler() { this = routeSetup.getARouteHandler() } StandardRouteHandler() { this = routeSetup.getARouteHandler() }
override Parameter getRouteHandlerParameter(string kind) { override DataFlow::ParameterNode getRouteHandlerParameter(string kind) {
if routeSetup.isParameterHandler() if routeSetup.isParameterHandler()
then result = getRouteParameterHandlerParameter(astNode, kind) then result = getRouteParameterHandlerParameter(this, kind)
else result = getRouteHandlerParameter(astNode, kind) else result = getRouteHandlerParameter(this, kind)
} }
} }
/** /**
* Holds if `call` is a chainable method call on the response object of `handler`. * Holds if `call` is a chainable method call on the response object of `handler`.
*/ */
private predicate isChainableResponseMethodCall(RouteHandler handler, MethodCallExpr call) { private predicate isChainableResponseMethodCall(
exists(string name | call.calls(handler.getAResponseExpr(), name) | RouteHandler handler, DataFlow::MethodCallNode call
) {
exists(string name | call.calls(handler.getAResponseNode(), name) |
name = name =
[ [
"append", "attachment", "location", "send", "sendStatus", "set", "status", "type", "vary", "append", "attachment", "location", "send", "sendStatus", "set", "status", "type", "vary",
@@ -463,9 +540,9 @@ module Express {
RouteHandler rh; RouteHandler rh;
ExplicitResponseSource() { ExplicitResponseSource() {
this = DataFlow::parameterNode(rh.getResponseParameter()) this = rh.getResponseParameter()
or or
isChainableResponseMethodCall(rh, this.asExpr()) isChainableResponseMethodCall(rh, this)
} }
/** /**
@@ -493,7 +570,7 @@ module Express {
private class ExplicitRequestSource extends RequestSource { private class ExplicitRequestSource extends RequestSource {
RouteHandler rh; RouteHandler rh;
ExplicitRequestSource() { this = DataFlow::parameterNode(rh.getRequestParameter()) } ExplicitRequestSource() { this = rh.getRequestParameter() }
/** /**
* Gets the route handler that handles this request. * Gets the route handler that handles this request.
@@ -511,16 +588,32 @@ module Express {
} }
/** /**
* DEPRECATED: Use `ResponseNode` instead.
* An Express response expression. * 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; 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. * An Express request expression.
*/ */
class RequestExpr extends NodeJSLib::RequestExpr { class RequestNode extends NodeJSLib::RequestNode {
override RequestSource src; override RequestSource src;
} }
@@ -544,7 +637,7 @@ module Express {
ParamHandlerInputAccess() { ParamHandlerInputAccess() {
exists(RouteSetup setup | rh = setup.getARouteHandler() | exists(RouteSetup setup | rh = setup.getARouteHandler() |
this = DataFlow::parameterNode(rh.getRouteHandlerParameter("parameter")) this = rh.getRouteHandlerParameter("parameter")
) )
} }
@@ -674,35 +767,35 @@ module Express {
/** /**
* Holds if `e` is an HTTP request object. * Holds if `e` is an HTTP request object.
*/ */
predicate isRequest(Expr e) { any(RouteHandler rh).getARequestExpr() = e } predicate isRequest(DataFlow::Node e) { any(RouteHandler rh).getARequestNode() = e }
/** /**
* Holds if `e` is an HTTP response object. * Holds if `e` is an HTTP response object.
*/ */
predicate isResponse(Expr e) { any(RouteHandler rh).getAResponseExpr() = e } predicate isResponse(DataFlow::Node e) { any(RouteHandler rh).getAResponseNode() = e }
/** /**
* An access to the HTTP request body. * An access to the HTTP request body.
*/ */
class RequestBodyAccess extends Expr { class RequestBodyAccess extends DataFlow::Node {
RequestBodyAccess() { any(RouteHandler h).getARequestBodyAccess() = this } RequestBodyAccess() { any(RouteHandler h).getARequestBodyAccess() = this }
} }
abstract private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { abstract private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition {
HeaderDefinition() { isResponse(astNode.getReceiver()) } HeaderDefinition() { isResponse(this.getReceiver()) }
override RouteHandler getRouteHandler() { astNode.getReceiver() = result.getAResponseExpr() } override RouteHandler getRouteHandler() { this.getReceiver() = result.getAResponseNode() }
} }
/** /**
* An invocation of the `redirect` method of an HTTP response object. * 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; 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() } override RouteHandler getRouteHandler() { result = response.getRouteHandler() }
} }
@@ -713,8 +806,8 @@ module Express {
*/ */
private class SetOneHeader extends HeaderDefinition { private class SetOneHeader extends HeaderDefinition {
SetOneHeader() { SetOneHeader() {
astNode.getMethodName() = any(string n | n = "set" or n = "header") and this.getMethodName() = any(string n | n = "set" or n = "header") and
astNode.getNumArgument() = 2 this.getNumArgument() = 2
} }
} }
@@ -735,18 +828,18 @@ module Express {
*/ */
private DataFlow::SourceNode getAHeaderSource() { result.flowsTo(this.getArgument(0)) } 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 | exists(string header |
this.getAHeaderSource().hasPropertyWrite(header, DataFlow::valueNode(headerValue)) and this.getAHeaderSource().hasPropertyWrite(header, headerValue) and
headerName = header.toLowerCase() headerName = header.toLowerCase()
) )
} }
override RouteHandler getRouteHandler() { result = response.getRouteHandler() } override RouteHandler getRouteHandler() { result = response.getRouteHandler() }
override Expr getNameExpr() { override DataFlow::Node getNameNode() {
exists(DataFlow::PropWrite write | this.getAHeaderSource().getAPropertyWrite() = write | exists(DataFlow::PropWrite write | this.getAHeaderSource().getAPropertyWrite() = write |
result = write.getPropertyNameExpr() result = write.getPropertyNameExpr().flow()
) )
} }
} }
@@ -755,7 +848,7 @@ module Express {
* An invocation of the `append` method on an HTTP response object. * An invocation of the `append` method on an HTTP response object.
*/ */
private class AppendHeader extends HeaderDefinition { private class AppendHeader extends HeaderDefinition {
AppendHeader() { astNode.getMethodName() = "append" } AppendHeader() { this.getMethodName() = "append" }
} }
/** /**
@@ -764,7 +857,7 @@ module Express {
private class ResponseSendArgument extends HTTP::ResponseSendArgument { private class ResponseSendArgument extends HTTP::ResponseSendArgument {
ResponseSource response; 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() } override RouteHandler getRouteHandler() { result = response.getRouteHandler() }
} }
@@ -772,14 +865,14 @@ module Express {
/** /**
* An invocation of the `cookie` method on an HTTP response object. * 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; 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() } override RouteHandler getRouteHandler() { result = response.getRouteHandler() }
} }
@@ -792,7 +885,7 @@ module Express {
TemplateObjectInput obj; TemplateObjectInput obj;
TemplateInput() { TemplateInput() {
obj.getALocalSource().(DataFlow::ObjectLiteralNode).hasPropertyWrite(_, this.flow()) obj.getALocalSource().(DataFlow::ObjectLiteralNode).hasPropertyWrite(_, this)
} }
override RouteHandler getRouteHandler() { result = obj.getRouteHandler() } override RouteHandler getRouteHandler() { result = obj.getRouteHandler() }
@@ -821,7 +914,7 @@ module Express {
* An Express server application. * An Express server application.
*/ */
private class Application extends HTTP::ServerDefinition { private class Application extends HTTP::ServerDefinition {
Application() { this = appCreation().asExpr() } Application() { this = appCreation() }
/** /**
* Gets a route handler of the application, regardless of nesting. * Gets a route handler of the application, regardless of nesting.
@@ -831,15 +924,13 @@ module Express {
} }
} }
/** /** An Express router. */
* An Express router. class RouterDefinition extends DataFlow::Node instanceof DataFlow::InvokeNode {
*/ RouterDefinition() { this = routerCreation() }
class RouterDefinition extends InvokeExpr {
RouterDefinition() { this = routerCreation().asExpr() }
private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { private DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
t.start() and t.start() and
result = DataFlow::exprNode(this) result = this
or or
exists(string name | result = this.ref(t.continue()).getAMethodCall(name) | exists(string name | result = this.ref(t.continue()).getAMethodCall(name) |
name = "route" or name = "route" or
@@ -852,22 +943,17 @@ module Express {
/** Gets a data flow node referring to this router. */ /** Gets a data flow node referring to this router. */
DataFlow::SourceNode ref() { result = this.ref(DataFlow::TypeTracker::end()) } DataFlow::SourceNode ref() { result = this.ref(DataFlow::TypeTracker::end()) }
/**
* Holds if `sink` may refer to this router.
*/
predicate flowsTo(Expr sink) { this.ref().flowsToExpr(sink) }
/** /**
* Gets a `RouteSetup` that was used for setting up a route on this router. * 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().flowsTo(result.getReceiver()) }
/** /**
* Gets a sub-router registered on this router. * Gets a sub-router registered on this router.
* *
* Example: `router2` for `router1.use(router2)` or `router1.use("/route2", router2)` * Example: `router2` for `router1.use(router2)` or `router1.use("/route2", router2)`
*/ */
RouterDefinition getASubRouter() { result.flowsTo(this.getARouteSetup().getAnArgument()) } RouterDefinition getASubRouter() { result.ref().flowsTo(this.getARouteSetup().getAnArgument()) }
/** /**
* Gets a route handler registered on this router. * Gets a route handler registered on this router.
@@ -875,7 +961,7 @@ module Express {
* Example: `fun` for `router1.use(fun)` or `router.use("/route", fun)` * Example: `fun` for `router1.use(fun)` or `router.use("/route", fun)`
*/ */
HTTP::RouteHandler getARouteHandler() { HTTP::RouteHandler getARouteHandler() {
result.(DataFlow::SourceNode).flowsToExpr(this.getARouteSetup().getAnArgument()) result.(DataFlow::SourceNode).flowsTo(this.getARouteSetup().getAnArgument())
} }
/** /**
@@ -893,25 +979,25 @@ module Express {
* *
* If `node` is not in the same container where `router` was defined, the predicate has no result. * If `node` is not in the same container where `router` was defined, the predicate has no result.
*/ */
Express::RouteHandlerExpr getMiddlewareStackAt(ControlFlowNode node) { Express::RouteHandlerNode getMiddlewareStackAt(ControlFlowNode node) {
if if
exists(Express::RouteSetup setup | node = setup and setup.getRouter() = this | exists(Express::RouteSetup setup | node = setup.asExpr() and setup.getRouter() = this |
setup.isUseCall() setup.isUseCall()
) )
then result = node.(Express::RouteSetup).getLastRouteHandlerExpr() then result = node.(AST::ValueNode).flow().(Express::RouteSetup).getLastRouteHandlerNode()
else result = this.getMiddlewareStackAt(node.getAPredecessor()) else result = this.getMiddlewareStackAt(node.getAPredecessor())
} }
/** /**
* Gets the final middleware registered on this router. * Gets the final middleware registered on this router.
*/ */
Express::RouteHandlerExpr getMiddlewareStack() { Express::RouteHandlerNode getMiddlewareStack() {
result = this.getMiddlewareStackAt(this.getContainer().getExit()) result = this.getMiddlewareStackAt(this.getContainer().getExit())
} }
} }
/** An expression that is passed as `expressBasicAuth({ users: { <user>: <password> }})`. */ /** An expression that is passed as `expressBasicAuth({ users: { <user>: <password> }})`. */
class Credentials extends CredentialsExpr { class Credentials extends CredentialsNode {
string kind; string kind;
Credentials() { Credentials() {
@@ -922,9 +1008,9 @@ module Express {
usersSrc.flowsTo(call.getOptionArgument(0, "users")) and usersSrc.flowsTo(call.getOptionArgument(0, "users")) and
usersSrc.flowsTo(pwn.getBase()) usersSrc.flowsTo(pwn.getBase())
| |
this = pwn.getPropertyNameExpr() and kind = "user name" this = pwn.getPropertyNameExpr().flow() and kind = "user name"
or or
this = pwn.getRhs().asExpr() and kind = "password" this = pwn.getRhs() and kind = "password"
) )
) )
} }
@@ -937,7 +1023,7 @@ module Express {
DataFlow::MethodCallNode { DataFlow::MethodCallNode {
ResponseSendFileAsFileSystemAccess() { ResponseSendFileAsFileSystemAccess() {
exists(string name | name = "sendFile" or name = "sendfile" | exists(string name | name = "sendFile" or name = "sendfile" |
this.calls(any(ResponseExpr res).flow(), name) this.calls(any(ResponseNode res), name)
) )
} }
@@ -963,10 +1049,10 @@ module Express {
TrackedRouteHandlerCandidateWithSetup() { this = routeSetup.getARouteHandler() } TrackedRouteHandlerCandidateWithSetup() { this = routeSetup.getARouteHandler() }
override Parameter getRouteHandlerParameter(string kind) { override DataFlow::ParameterNode getRouteHandlerParameter(string kind) {
if routeSetup.isParameterHandler() if routeSetup.isParameterHandler()
then result = getRouteParameterHandlerParameter(astNode, kind) then result = getRouteParameterHandlerParameter(this, kind)
else result = getRouteHandlerParameter(astNode, kind) else result = getRouteHandlerParameter(this, kind)
} }
} }

View File

@@ -18,9 +18,7 @@ module Fastify {
* A standard way to create a Fastify server. * A standard way to create a Fastify server.
*/ */
class StandardServerDefinition extends ServerDefinition { class StandardServerDefinition extends ServerDefinition {
StandardServerDefinition() { StandardServerDefinition() { this = DataFlow::moduleImport("fastify").getAnInvocation() }
this = DataFlow::moduleImport("fastify").getAnInvocation().asExpr()
}
} }
/** Gets a data flow node referring to a fastify server. */ /** Gets a data flow node referring to a fastify server. */
@@ -134,12 +132,12 @@ module Fastify {
/** /**
* A call to a Fastify method that sets up a route. * 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; ServerDefinition server;
string methodName; string methodName;
RouteSetup() { RouteSetup() {
this = server(server.flow()).getAMethodCall(methodName).asExpr() and this = server(server).getAMethodCall(methodName) and
methodName = ["route", "get", "head", "post", "put", "delete", "options", "patch"] methodName = ["route", "get", "head", "post", "put", "delete", "options", "patch"]
} }
@@ -149,25 +147,30 @@ module Fastify {
private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) {
t.start() and t.start() and
result = this.getARouteHandlerExpr().getALocalSource() result = this.getARouteHandlerNode().getALocalSource()
or or
exists(DataFlow::TypeBackTracker t2 | result = this.getARouteHandler(t2).backtrack(t2, t)) exists(DataFlow::TypeBackTracker t2 | result = this.getARouteHandler(t2).backtrack(t2, t))
} }
override Expr getServer() { result = server } override DataFlow::SourceNode getServer() { result = server }
/**
* 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. */ /** Gets an argument that represents a route handler being registered. */
DataFlow::Node getARouteHandlerExpr() { DataFlow::Node getARouteHandlerNode() {
if methodName = "route" if methodName = "route"
then then result = this.getOptionArgument(0, getNthHandlerName(_))
result = this.flow().(DataFlow::MethodCallNode).getOptionArgument(0, getNthHandlerName(_)) else result = this.getLastArgument()
else result = this.getLastArgument().flow()
} }
} }
private class ShorthandRoutingTreeSetup extends Routing::RouteSetup::MethodCall { private class ShorthandRoutingTreeSetup extends Routing::RouteSetup::MethodCall {
ShorthandRoutingTreeSetup() { ShorthandRoutingTreeSetup() {
this.asExpr() instanceof RouteSetup and this instanceof RouteSetup and
not this.getMethodName() = "route" not this.getMethodName() = "route"
} }
@@ -185,7 +188,7 @@ module Fastify {
private class FullRoutingTreeSetup extends Routing::RouteSetup::MethodCall { private class FullRoutingTreeSetup extends Routing::RouteSetup::MethodCall {
FullRoutingTreeSetup() { FullRoutingTreeSetup() {
this.asExpr() instanceof RouteSetup and this instanceof RouteSetup and
this.getMethodName() = "route" this.getMethodName() = "route"
} }
@@ -287,13 +290,7 @@ module Fastify {
*/ */
private predicate usesFastifyPlugin(RouteHandler rh, DataFlow::SourceNode plugin) { private predicate usesFastifyPlugin(RouteHandler rh, DataFlow::SourceNode plugin) {
exists(RouteSetup setup | exists(RouteSetup setup |
plugin plugin.flowsTo(setup.getServer().getAMethodCall("register").getArgument(0)) and // only matches the plugins that apply to all routes
.flowsTo(setup
.getServer()
.flow()
.(DataFlow::SourceNode)
.getAMethodCall("register")
.getArgument(0)) and // only matches the plugins that apply to all routes
rh = setup.getARouteHandler() rh = setup.getARouteHandler()
) )
} }
@@ -303,13 +300,7 @@ module Fastify {
*/ */
private predicate usesMiddleware(RouteHandler rh, DataFlow::SourceNode middleware) { private predicate usesMiddleware(RouteHandler rh, DataFlow::SourceNode middleware) {
exists(RouteSetup setup | exists(RouteSetup setup |
middleware middleware.flowsTo(setup.getServer().getAMethodCall("use").getArgument(0)) and // only matches the middlewares that apply to all routes
.flowsTo(setup
.getServer()
.flow()
.(DataFlow::SourceNode)
.getAMethodCall("use")
.getArgument(0)) and // only matches the middlewares that apply to all routes
rh = setup.getARouteHandler() rh = setup.getARouteHandler()
) )
} }
@@ -340,9 +331,9 @@ module Fastify {
RouteHandler rh; RouteHandler rh;
ResponseSendArgument() { ResponseSendArgument() {
this = rh.getAResponseSource().ref().getAMethodCall("send").getArgument(0).asExpr() this = rh.getAResponseSource().ref().getAMethodCall("send").getArgument(0)
or or
this = rh.(DataFlow::FunctionNode).getAReturn().asExpr() this = rh.(DataFlow::FunctionNode).getAReturn()
} }
override RouteHandler getRouteHandler() { result = rh } override RouteHandler getRouteHandler() { result = rh }
@@ -351,14 +342,12 @@ module Fastify {
/** /**
* An invocation of the `redirect` method of an HTTP response object. * 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; RouteHandler rh;
RedirectInvocation() { RedirectInvocation() { this = rh.getAResponseSource().ref().getAMethodCall("redirect") }
this = rh.getAResponseSource().ref().getAMethodCall("redirect").asExpr()
}
override Expr getUrlArgument() { result = this.getLastArgument() } override DataFlow::Node getUrlArgument() { result = this.getLastArgument() }
override RouteHandler getRouteHandler() { result = rh } override RouteHandler getRouteHandler() { result = rh }
} }
@@ -394,18 +383,18 @@ module Fastify {
*/ */
private DataFlow::SourceNode getAHeaderSource() { result.flowsTo(this.getArgument(0)) } 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 | exists(string header |
this.getAHeaderSource().hasPropertyWrite(header, headerValue.flow()) and this.getAHeaderSource().hasPropertyWrite(header, headerValue) and
headerName = header.toLowerCase() headerName = header.toLowerCase()
) )
} }
override RouteHandler getRouteHandler() { result = rh } override RouteHandler getRouteHandler() { result = rh }
override Expr getNameExpr() { override DataFlow::Node getNameNode() {
exists(DataFlow::PropWrite write | this.getAHeaderSource().getAPropertyWrite() = write | exists(DataFlow::PropWrite write | this.getAHeaderSource().getAPropertyWrite() = write |
result = write.getPropertyNameExpr() result = write.getPropertyNameExpr().flow()
) )
} }
} }

View File

@@ -114,13 +114,13 @@ module Firebase {
class QueryListenCall extends DataFlow::MethodCallNode { class QueryListenCall extends DataFlow::MethodCallNode {
QueryListenCall() { QueryListenCall() {
this = query().getAMethodCall() and 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. * Gets the argument in which the callback is passed.
*/ */
DataFlow::Node getCallbackNode() { result = getArgument(1) } DataFlow::Node getCallbackNode() { result = this.getArgument(1) }
} }
/** /**
@@ -183,50 +183,46 @@ module Firebase {
class RefBuilderListenCall extends DataFlow::MethodCallNode { class RefBuilderListenCall extends DataFlow::MethodCallNode {
RefBuilderListenCall() { RefBuilderListenCall() {
this = ref().getAMethodCall() and this = ref().getAMethodCall() and
getMethodName() = "on" + any(string s) this.getMethodName() = "on" + any(string s)
} }
/** /**
* Gets the data flow node holding the listener callback. * Gets the data flow node holding the listener callback.
*/ */
DataFlow::Node getCallbackNode() { result = getArgument(0) } DataFlow::Node getCallbackNode() { result = this.getArgument(0) }
} }
/** /**
* A call to a Firebase method that sets up a route. * A call to a Firebase method that sets up a route.
*/ */
private class RouteSetup extends HTTP::Servers::StandardRouteSetup, CallExpr { private class RouteSetup extends HTTP::Servers::StandardRouteSetup, DataFlow::CallNode {
RouteSetup() { RouteSetup() { this = namespace().getAPropertyRead("https").getAMemberCall("onRequest") }
this = namespace().getAPropertyRead("https").getAMemberCall("onRequest").asExpr()
}
override DataFlow::SourceNode getARouteHandler() { override DataFlow::SourceNode getARouteHandler() {
result = getARouteHandler(DataFlow::TypeBackTracker::end()) result = this.getARouteHandler(DataFlow::TypeBackTracker::end())
} }
private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) {
t.start() and t.start() and
result = getArgument(0).flow().getALocalSource() result = this.getArgument(0).getALocalSource()
or or
exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t)) exists(DataFlow::TypeBackTracker t2 | result = this.getARouteHandler(t2).backtrack(t2, t))
} }
override Expr getServer() { none() } override DataFlow::Node getServer() { none() }
} }
/** /**
* A function used as a route handler. * A function used as a route handler.
*/ */
private class RouteHandler extends Express::RouteHandler, HTTP::Servers::StandardRouteHandler, private class RouteHandler extends Express::RouteHandler, HTTP::Servers::StandardRouteHandler,
DataFlow::ValueNode { DataFlow::FunctionNode {
override Function astNode;
RouteHandler() { this = any(RouteSetup setup).getARouteHandler() } RouteHandler() { this = any(RouteSetup setup).getARouteHandler() }
override Parameter getRouteHandlerParameter(string kind) { override DataFlow::ParameterNode getRouteHandlerParameter(string kind) {
kind = "request" and result = astNode.getParameter(0) kind = "request" and result = this.getParameter(0)
or or
kind = "response" and result = astNode.getParameter(1) kind = "response" and result = this.getParameter(1)
} }
} }
} }

View File

@@ -12,9 +12,9 @@ module HTTP {
/** /**
* A function invocation that causes a redirect response to be sent. * 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. */ /** Gets the argument specifying the URL to redirect to. */
abstract Expr getUrlArgument(); abstract DataFlow::Node getUrlArgument();
/** Gets the route handler this redirect occurs in. */ /** Gets the route handler this redirect occurs in. */
abstract RouteHandler getRouteHandler(); abstract RouteHandler getRouteHandler();
@@ -56,24 +56,34 @@ module HTTP {
* An expression that sets HTTP response headers explicitly. * An expression that sets HTTP response headers explicitly.
*/ */
abstract class ExplicitHeaderDefinition extends HeaderDefinition { abstract class ExplicitHeaderDefinition extends HeaderDefinition {
override string getAHeaderName() { this.definesExplicitly(result, _) } override string getAHeaderName() { this.definesHeaderValue(result, _) }
override predicate defines(string headerName, string headerValue) { override predicate defines(string headerName, string headerValue) {
exists(Expr e | exists(DataFlow::Node e |
this.definesExplicitly(headerName, e) and this.definesHeaderValue(headerName, e) and
headerValue = e.getStringValue() headerValue = e.getStringValue()
) )
} }
/** /**
* DEPRECATED: use `definesHeaderValue` instead.
* Holds if the header with (lower-case) name `headerName` is set to the value of `headerValue`. * Holds if the header with (lower-case) name `headerName` is set to the value of `headerValue`.
*/ */
abstract predicate definesExplicitly(string headerName, Expr headerValue); 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.
* Returns the expression used to compute the header name. * 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();
} }
/** /**
@@ -107,7 +117,7 @@ module HTTP {
/** /**
* An expression whose value is sent as (part of) the body of an HTTP response. * 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. * Gets the route handler that sends this expression.
*/ */
@@ -123,21 +133,21 @@ module HTTP {
/** /**
* An expression that sets a cookie in an HTTP response. * An expression that sets a cookie in an HTTP response.
*/ */
abstract class CookieDefinition extends Expr { abstract class CookieDefinition extends DataFlow::Node {
/** /**
* Gets the argument, if any, specifying the raw cookie header. * Gets the argument, if any, specifying the raw cookie header.
*/ */
Expr getHeaderArgument() { none() } DataFlow::Node getHeaderArgument() { none() }
/** /**
* Gets the argument, if any, specifying the cookie name. * Gets the argument, if any, specifying the cookie name.
*/ */
Expr getNameArgument() { none() } DataFlow::Node getNameArgument() { none() }
/** /**
* Gets the argument, if any, specifying the cookie value. * Gets the argument, if any, specifying the cookie value.
*/ */
Expr getValueArgument() { none() } DataFlow::Node getValueArgument() { none() }
/** Gets the route handler that sets this cookie. */ /** Gets the route handler that sets this cookie. */
abstract RouteHandler getRouteHandler(); abstract RouteHandler getRouteHandler();
@@ -150,12 +160,12 @@ module HTTP {
HeaderDefinition header; HeaderDefinition header;
SetCookieHeader() { SetCookieHeader() {
this = header.asExpr() and this = header and
header.getAHeaderName() = "set-cookie" header.getAHeaderName() = "set-cookie"
} }
override Expr getHeaderArgument() { override DataFlow::Node getHeaderArgument() {
header.(ExplicitHeaderDefinition).definesExplicitly("set-cookie", result) header.(ExplicitHeaderDefinition).definesHeaderValue("set-cookie", result)
} }
override RouteHandler getRouteHandler() { result = header.getRouteHandler() } override RouteHandler getRouteHandler() { result = header.getRouteHandler() }
@@ -164,7 +174,7 @@ module HTTP {
/** /**
* An expression that creates a new server. * 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. * Gets a route handler of the server.
*/ */
@@ -198,16 +208,30 @@ module HTTP {
final Servers::ResponseSource getAResponseSource() { result.getRouteHandler() = this } final Servers::ResponseSource getAResponseSource() { result.getRouteHandler() = this }
/** /**
* DEPRECATED: Use `getARequestNode()` instead.
* Gets an expression that contains a request object handled * Gets an expression that contains a request object handled
* by this handler. * by this handler.
*/ */
RequestExpr getARequestExpr() { result.getRouteHandler() = this } 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 * Gets an expression that contains a response object provided
* by this handler. * by this handler.
*/ */
ResponseExpr getAResponseExpr() { result.getRouteHandler() = this } ResponseNode getAResponseNode() { result.getRouteHandler() = this }
} }
/** /**
@@ -232,26 +256,42 @@ module HTTP {
/** /**
* An expression that sets up a route on a server. * An expression that sets up a route on a server.
*/ */
abstract class RouteSetup extends Expr { } abstract class RouteSetup extends DataFlow::Node { }
/** /** A dataflow node that may contain a request object. */
* An expression that may contain a request object. abstract class RequestNode extends DataFlow::Node {
*/ /** Gets the route handler that handles this request. */
abstract class RequestExpr extends Expr { abstract RouteHandler getRouteHandler();
/** }
* Gets the route handler that handles this request.
*/ /** 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(); abstract RouteHandler getRouteHandler();
} }
/** /**
* An expression that may contain a response object. * DEPRECATED: Use `RequestNode` instead.
* An expression that may contain a request object.
*/ */
abstract class ResponseExpr extends Expr { deprecated class RequestExpr extends Expr {
RequestExpr() { this.flow() instanceof ResponseNode }
/** /**
* Gets the route handler that handles this request. * 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.
*/
deprecated class ResponseExpr extends Expr {
/**
* Gets the route handler that handles this request.
*/
RouteHandler getRouteHandler() { result = this.flow().(ResponseNode).getRouteHandler() }
} }
/** /**
@@ -267,15 +307,19 @@ module HTTP {
private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { private DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
t.start() and t.start() and
result = DataFlow::exprNode(this) result = this.getALocalSource()
or or
exists(DataFlow::TypeTracker t2 | result = this.ref(t2).track(t2, t)) 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. * 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) }
} }
/** /**
@@ -290,7 +334,7 @@ module HTTP {
/** /**
* Gets the server this route handler is registered on. * Gets the server this route handler is registered on.
*/ */
Expr getServer() { DataFlow::Node getServer() {
exists(StandardRouteSetup setup | setup.getARouteHandler() = this | exists(StandardRouteSetup setup | setup.getARouteHandler() = this |
result = setup.getServer() result = setup.getServer()
) )
@@ -350,10 +394,10 @@ module HTTP {
/** /**
* A request expression arising from a request source. * A request expression arising from a request source.
*/ */
class StandardRequestExpr extends RequestExpr { class StandardRequestNode extends RequestNode {
RequestSource src; RequestSource src;
StandardRequestExpr() { src.ref().flowsTo(DataFlow::valueNode(this)) } StandardRequestNode() { src.ref().flowsTo(this) }
override RouteHandler getRouteHandler() { result = src.getRouteHandler() } override RouteHandler getRouteHandler() { result = src.getRouteHandler() }
} }
@@ -361,26 +405,49 @@ module HTTP {
/** /**
* A response expression arising from a response source. * A response expression arising from a response source.
*/ */
class StandardResponseExpr extends ResponseExpr { class StandardResponseNode extends ResponseNode {
ResponseSource src; ResponseSource src;
StandardResponseExpr() { src.ref().flowsTo(DataFlow::valueNode(this)) } StandardResponseNode() { src.ref().flowsTo(this) }
override RouteHandler getRouteHandler() { result = src.getRouteHandler() } override RouteHandler getRouteHandler() { result = src.getRouteHandler() }
} }
/** /**
* A standard header definition. * A request expression arising from a request source.
*/ */
abstract class StandardHeaderDefinition extends ExplicitHeaderDefinition, DataFlow::ValueNode { deprecated class StandardRequestExpr extends RequestExpr {
override MethodCallExpr astNode; RequestSource src;
override predicate definesExplicitly(string headerName, Expr headerValue) { StandardRequestExpr() { src.ref().flowsToExpr(this) }
headerName = this.getNameExpr().getStringValue().toLowerCase() and
headerValue = astNode.getArgument(1) override RouteHandler getRouteHandler() { result = src.getRouteHandler() }
} }
override Expr getNameExpr() { result = astNode.getArgument(0) } /**
* 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.
*/
abstract class StandardHeaderDefinition extends ExplicitHeaderDefinition,
DataFlow::MethodCallNode {
override predicate definesHeaderValue(string headerName, DataFlow::Node headerValue) {
headerName = this.getNameNode().getStringValue().toLowerCase() and
headerValue = this.getArgument(1)
}
override DataFlow::Node getNameNode() { result = this.getArgument(0) }
} }
/** /**
@@ -396,7 +463,7 @@ module HTTP {
/** /**
* Gets the server on which this route setup sets up routes. * Gets the server on which this route setup sets up routes.
*/ */
abstract Expr getServer(); abstract DataFlow::Node getServer();
} }
/** /**

View File

@@ -9,39 +9,34 @@ module Hapi {
/** /**
* An expression that creates a new Hapi server. * An expression that creates a new Hapi server.
*/ */
class ServerDefinition extends HTTP::Servers::StandardServerDefinition, NewExpr { class ServerDefinition extends HTTP::Servers::StandardServerDefinition, DataFlow::NewNode {
ServerDefinition() { ServerDefinition() {
// `server = new Hapi.Server()` // `server = new Hapi.Server()`
this = DataFlow::moduleMember("hapi", "Server").getAnInstantiation().asExpr() this = DataFlow::moduleMember("hapi", "Server").getAnInstantiation()
} }
} }
/** /**
* A Hapi route handler. * A Hapi route handler.
*/ */
class RouteHandler extends HTTP::Servers::StandardRouteHandler, DataFlow::ValueNode { class RouteHandler extends HTTP::Servers::StandardRouteHandler, DataFlow::FunctionNode {
Function function; RouteHandler() { exists(RouteSetup setup | this = setup.getARouteHandler()) }
RouteHandler() {
function = astNode and
exists(RouteSetup setup | this = setup.getARouteHandler())
}
/** /**
* Gets the parameter of the route handler that contains the request object. * Gets the parameter of the route handler that contains the request object.
*/ */
Parameter getRequestParameter() { result = function.getParameter(0) } DataFlow::ParameterNode getRequestParameter() { result = this.getParameter(0) }
/** /**
* Gets the parameter of the route handler that contains the "request toolkit", * Gets the parameter of the route handler that contains the "request toolkit",
* usually named `h`. * usually named `h`.
*/ */
Parameter getRequestToolkitParameter() { result = function.getParameter(1) } DataFlow::ParameterNode getRequestToolkitParameter() { result = this.getParameter(1) }
/** /**
* Gets a source node referring to the request toolkit parameter, usually named `h`. * Gets a source node referring to the request toolkit parameter, usually named `h`.
*/ */
DataFlow::SourceNode getRequestToolkit() { result = getRequestToolkitParameter().flow() } DataFlow::SourceNode getRequestToolkit() { result = this.getRequestToolkitParameter() }
} }
/** /**
@@ -49,9 +44,9 @@ module Hapi {
* of a request object. * of a request object.
*/ */
private class ResponseSource extends HTTP::Servers::ResponseSource { 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. * Gets the route handler that provides this response.
@@ -66,7 +61,7 @@ module Hapi {
private class RequestSource extends HTTP::Servers::RequestSource { private class RequestSource extends HTTP::Servers::RequestSource {
RouteHandler rh; RouteHandler rh;
RequestSource() { this = DataFlow::parameterNode(rh.getRequestParameter()) } RequestSource() { this = rh.getRequestParameter() }
/** /**
* Gets the route handler that handles this request. * Gets the route handler that handles this request.
@@ -75,16 +70,32 @@ module Hapi {
} }
/** /**
* DEPRECATED: Use `ResponseNode` instead.
* A Hapi response expression. * 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; override ResponseSource src;
} }
/** /**
* DEPRECATED: Use `RequestNode` instead.
* An Hapi request expression. * 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; override RequestSource src;
} }
@@ -96,38 +107,38 @@ module Hapi {
string kind; string kind;
RequestInputAccess() { RequestInputAccess() {
exists(Expr request | request = rh.getARequestExpr() | exists(DataFlow::Node request | request = rh.getARequestNode() |
kind = "body" and kind = "body" and
( (
// `request.rawPayload` // `request.rawPayload`
this.asExpr().(PropAccess).accesses(request, "rawPayload") this.(DataFlow::PropRead).accesses(request, "rawPayload")
or or
exists(PropAccess payload | exists(DataFlow::PropRead payload |
// `request.payload.name` // `request.payload.name`
payload.accesses(request, "payload") and payload.accesses(request, "payload") and
this.asExpr().(PropAccess).accesses(payload, _) this.(DataFlow::PropRead).accesses(payload, _)
) )
) )
or or
kind = "parameter" and kind = "parameter" and
exists(PropAccess query | exists(DataFlow::PropRead query |
// `request.query.name` // `request.query.name`
query.accesses(request, "query") and query.accesses(request, "query") and
this.asExpr().(PropAccess).accesses(query, _) this.(DataFlow::PropRead).accesses(query, _)
) )
or or
exists(PropAccess url | exists(DataFlow::PropRead url |
// `request.url.path` // `request.url.path`
kind = "url" and kind = "url" and
url.accesses(request, "url") and url.accesses(request, "url") and
this.asExpr().(PropAccess).accesses(url, "path") this.(DataFlow::PropRead).accesses(url, "path")
) )
or or
exists(PropAccess state | exists(DataFlow::PropRead state |
// `request.state.<name>` // `request.state.<name>`
kind = "cookie" and kind = "cookie" and
state.accesses(request, "state") and state.accesses(request, "state") and
this.asExpr().(PropAccess).accesses(state, _) this.(DataFlow::PropRead).accesses(state, _)
) )
) )
or or
@@ -149,11 +160,11 @@ module Hapi {
RouteHandler rh; RouteHandler rh;
RequestHeaderAccess() { RequestHeaderAccess() {
exists(Expr request | request = rh.getARequestExpr() | exists(DataFlow::Node request | request = rh.getARequestNode() |
exists(PropAccess headers | exists(DataFlow::PropRead headers |
// `request.headers.<name>` // `request.headers.<name>`
headers.accesses(request, "headers") and headers.accesses(request, "headers") and
this.asExpr().(PropAccess).accesses(headers, _) this.(DataFlow::PropRead).accesses(headers, _)
) )
) )
} }
@@ -171,11 +182,11 @@ module Hapi {
* An HTTP header defined in a Hapi server. * An HTTP header defined in a Hapi server.
*/ */
private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition {
ResponseExpr res; ResponseNode res;
HeaderDefinition() { HeaderDefinition() {
// request.response.header('Cache-Control', 'no-cache') // request.response.header('Cache-Control', 'no-cache')
astNode.calls(res, "header") this.calls(res, "header")
} }
override RouteHandler getRouteHandler() { result = res.getRouteHandler() } override RouteHandler getRouteHandler() { result = res.getRouteHandler() }
@@ -184,40 +195,40 @@ module Hapi {
/** /**
* A call to a Hapi method that sets up a route. * 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; ServerDefinition server;
Expr handler; DataFlow::Node handler;
RouteSetup() { RouteSetup() {
server.flowsTo(getReceiver()) and server.ref().getAMethodCall() = this and
( (
// server.route({ handler: fun }) // server.route({ handler: fun })
getMethodName() = "route" and this.getMethodName() = "route" and
hasOptionArgument(0, "handler", handler) this.getOptionArgument(0, "handler") = handler
or or
// server.ext('/', fun) // server.ext('/', fun)
getMethodName() = "ext" and this.getMethodName() = "ext" and
handler = getArgument(1) handler = this.getArgument(1)
) )
} }
override DataFlow::SourceNode getARouteHandler() { override DataFlow::SourceNode getARouteHandler() {
result = getARouteHandler(DataFlow::TypeBackTracker::end()) result = this.getARouteHandler(DataFlow::TypeBackTracker::end())
} }
private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) {
t.start() and t.start() and
result = getRouteHandler().getALocalSource() result = this.getRouteHandler().getALocalSource()
or or
exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t)) exists(DataFlow::TypeBackTracker t2 | result = this.getARouteHandler(t2).backtrack(t2, t))
} }
pragma[noinline] pragma[noinline]
private DataFlow::Node getRouteHandler() { result = handler.flow() } private DataFlow::Node getRouteHandler() { result = handler }
Expr getRouteHandlerExpr() { result = handler } deprecated Expr getRouteHandlerExpr() { result = handler.asExpr() }
override Expr getServer() { result = server } override DataFlow::Node getServer() { result = server }
} }
/** /**
@@ -257,9 +268,9 @@ module Hapi {
override DataFlow::SourceNode getOutput() { none() } 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) }
} }
/** /**
@@ -268,7 +279,7 @@ module Hapi {
private class HandlerReturn extends HTTP::ResponseSendArgument { private class HandlerReturn extends HTTP::ResponseSendArgument {
RouteHandler handler; RouteHandler handler;
HandlerReturn() { this = handler.(DataFlow::FunctionNode).getAReturn().asExpr() } HandlerReturn() { this = handler.(DataFlow::FunctionNode).getAReturn() }
override RouteHandler getRouteHandler() { result = handler } override RouteHandler getRouteHandler() { result = handler }
} }

View File

@@ -83,16 +83,12 @@ private module HttpProxy {
) )
} }
override Parameter getRequestParameter() { override DataFlow::ParameterNode getRequestParameter() {
exists(int req | routeHandlingEventHandler(event, req, _) | exists(int req | routeHandlingEventHandler(event, req, _) | result = getParameter(req))
result = getFunction().getParameter(req)
)
} }
override Parameter getResponseParameter() { override DataFlow::ParameterNode getResponseParameter() {
exists(int res | routeHandlingEventHandler(event, _, res) | exists(int res | routeHandlingEventHandler(event, _, res) | result = getParameter(res))
result = getFunction().getParameter(res)
)
} }
} }
} }

View File

@@ -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 { private class JwtKey extends CredentialsNode {
JwtKey() { JwtKey() { this = DataFlow::moduleMember("jsonwebtoken", "sign").getACall().getArgument(1) }
this = DataFlow::moduleMember("jsonwebtoken", "sign").getACall().getArgument(1).asExpr()
}
override string getCredentialsKind() { result = "key" } override string getCredentialsKind() { result = "key" }
} }

View File

@@ -43,7 +43,7 @@ module Knex {
/** A SQL string passed to a raw Knex method. */ /** A SQL string passed to a raw Knex method. */
private class RawKnexSqlString extends SQL::SqlString { 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. */ /** A call that triggers a SQL query submission by calling then/stream/asCallback. */

View File

@@ -9,10 +9,10 @@ module Koa {
/** /**
* An expression that creates a new Koa application. * An expression that creates a new Koa application.
*/ */
class AppDefinition extends HTTP::Servers::StandardServerDefinition, InvokeExpr { class AppDefinition extends HTTP::Servers::StandardServerDefinition, DataFlow::InvokeNode {
AppDefinition() { AppDefinition() {
// `app = new Koa()` / `app = Koa()` // `app = new Koa()` / `app = Koa()`
this = DataFlow::moduleImport("koa").getAnInvocation().asExpr() this = DataFlow::moduleImport("koa").getAnInvocation()
} }
} }
@@ -24,10 +24,10 @@ module Koa {
HeaderDefinition() { HeaderDefinition() {
// ctx.set('Cache-Control', 'no-cache'); // ctx.set('Cache-Control', 'no-cache');
astNode.calls(rh.getAResponseOrContextExpr(), "set") this.calls(rh.getAResponseOrContextNode(), "set")
or or
// ctx.response.header('Cache-Control', 'no-cache') // ctx.response.header('Cache-Control', 'no-cache')
astNode.calls(rh.getAResponseExpr(), "header") this.calls(rh.getAResponseNode(), "header")
} }
override RouteHandler getRouteHandler() { result = rh } override RouteHandler getRouteHandler() { result = rh }
@@ -40,10 +40,17 @@ module Koa {
/** /**
* Gets the parameter of the route handler that contains the context object. * Gets the parameter of the route handler that contains the context object.
*/ */
Parameter getContextParameter() { DataFlow::ParameterNode getContextParameter() {
result = this.getAFunctionValue().getFunction().getParameter(0) 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 = this.getAContextNode().asExpr() }
/** /**
* Gets an expression that contains the "context" object of * Gets an expression that contains the "context" object of
* a route handler invocation. * a route handler invocation.
@@ -52,22 +59,38 @@ module Koa {
* `this` or `ctx`, given as the first and only argument to the * `this` or `ctx`, given as the first and only argument to the
* route handler. * 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.
*/
deprecated Expr getAResponseOrContextExpr() {
result = this.getAResponseOrContextNode().asExpr()
}
/** /**
* Gets an expression that contains the context or response * Gets an expression that contains the context or response
* object of a route handler invocation. * object of a route handler invocation.
*/ */
Expr getAResponseOrContextExpr() { DataFlow::Node getAResponseOrContextNode() {
result = this.getAResponseExpr() or result = this.getAContextExpr() 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.
*/
deprecated Expr getARequestOrContextExpr() { result = this.getARequestOrContextNode().asExpr() }
/** /**
* Gets an expression that contains the context or request * Gets an expression that contains the context or request
* object of a route handler invocation. * object of a route handler invocation.
*/ */
Expr getARequestOrContextExpr() { DataFlow::Node getARequestOrContextNode() {
result = this.getARequestExpr() or result = this.getAContextExpr() result = this.getARequestNode() or result = this.getAContextNode()
} }
/** /**
@@ -108,7 +131,7 @@ module Koa {
RouteHandler rh; RouteHandler rh;
ContextSource() { ContextSource() {
this = DataFlow::parameterNode(rh.getContextParameter()) this = rh.getContextParameter()
or or
this.(DataFlow::ThisNode).getBinder() = rh this.(DataFlow::ThisNode).getBinder() = rh
} }
@@ -118,8 +141,6 @@ module Koa {
*/ */
RouteHandler getRouteHandler() { result = rh } RouteHandler getRouteHandler() { result = rh }
predicate flowsTo(DataFlow::Node nd) { this.ref().flowsTo(nd) }
private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { private DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
t.start() and t.start() and
result = this result = this
@@ -206,10 +227,10 @@ module Koa {
* A Koa request source, that is, an access to the `request` property * A Koa request source, that is, an access to the `request` property
* of a context object. * of a context object.
*/ */
private class RequestSource extends HTTP::Servers::RequestSource { private class RequestSource extends HTTP::Servers::RequestSource instanceof DataFlow::PropRead {
ContextExpr ctx; ContextNode ctx;
RequestSource() { this.asExpr().(PropAccess).accesses(ctx, "request") } RequestSource() { super.accesses(ctx, "request") }
/** /**
* Gets the route handler that provides this response. * Gets the route handler that provides this response.
@@ -241,10 +262,10 @@ module Koa {
* A Koa response source, that is, an access to the `response` property * A Koa response source, that is, an access to the `response` property
* of a context object. * of a context object.
*/ */
private class ResponseSource extends HTTP::Servers::ResponseSource { private class ResponseSource extends HTTP::Servers::ResponseSource instanceof DataFlow::PropRead {
ContextExpr ctx; ContextNode ctx;
ResponseSource() { this.asExpr().(PropAccess).accesses(ctx, "response") } ResponseSource() { super.accesses(ctx, "response") }
/** /**
* Gets the route handler that provides this response. * Gets the route handler that provides this response.
@@ -253,12 +274,25 @@ module Koa {
} }
/** /**
* DEPRECATED: Use `ContextNode` instead.
* An expression that may hold a Koa context object. * An expression that may hold a Koa context object.
*/ */
class ContextExpr extends Expr { 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 ContextNode extends DataFlow::Node {
ContextSource src; ContextSource src;
ContextExpr() { src.flowsTo(DataFlow::valueNode(this)) } ContextNode() { src.ref().flowsTo(this) }
/** /**
* Gets the route handler that provides this response. * Gets the route handler that provides this response.
@@ -267,16 +301,32 @@ module Koa {
} }
/** /**
* DEPRECATED: Use `RequestNode` instead.
* An expression that may hold a Koa request object. * An expression that may hold a Koa request object.
*/ */
class RequestExpr extends HTTP::Servers::StandardRequestExpr { deprecated class RequestExpr extends HTTP::Servers::StandardRequestExpr {
RequestExpr() { this.flow() instanceof RequestNode }
}
/**
* An expression that may hold a Koa request object.
*/
class RequestNode extends HTTP::Servers::StandardRequestNode {
override RequestSource src; 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. * An expression that may hold a Koa response object.
*/ */
class ResponseExpr extends HTTP::Servers::StandardResponseExpr { class ResponseNode extends HTTP::Servers::StandardResponseNode {
override ResponseSource src; override ResponseSource src;
} }
@@ -294,11 +344,11 @@ module Koa {
kind = "parameter" and kind = "parameter" and
this = rh.getARequestParameterAccess() this = rh.getARequestParameterAccess()
or or
exists(Expr e | rh.getARequestOrContextExpr() = e | exists(DataFlow::Node e | rh.getARequestOrContextNode() = e |
// `ctx.request.url`, `ctx.request.originalUrl`, or `ctx.request.href` // `ctx.request.url`, `ctx.request.originalUrl`, or `ctx.request.href`
exists(string propName | exists(string propName |
kind = "url" and kind = "url" and
this.asExpr().(PropAccess).accesses(e, propName) this.(DataFlow::PropRead).accesses(e, propName)
| |
propName = "url" propName = "url"
or or
@@ -309,19 +359,19 @@ module Koa {
or or
// params, when handler is registered by `koa-router` or similar. // params, when handler is registered by `koa-router` or similar.
kind = "parameter" and kind = "parameter" and
this.asExpr().(PropAccess).accesses(e, "params") this.(DataFlow::PropRead).accesses(e, "params")
or or
// `ctx.request.body` // `ctx.request.body`
e instanceof RequestExpr and e instanceof RequestNode and
kind = "body" and kind = "body" and
this.asExpr().(PropAccess).accesses(e, "body") this.(DataFlow::PropRead).accesses(e, "body")
or or
// `ctx.cookies.get(<name>)` // `ctx.cookies.get(<name>)`
exists(PropAccess cookies | exists(DataFlow::PropRead cookies |
e instanceof ContextExpr and e instanceof ContextNode and
kind = "cookie" and kind = "cookie" and
cookies.accesses(e, "cookies") and cookies.accesses(e, "cookies") and
this = cookies.flow().(DataFlow::SourceNode).getAMethodCall("get") this = cookies.getAMethodCall("get")
) )
or or
exists(RequestHeaderAccess access | access = this | exists(RequestHeaderAccess access | access = this |
@@ -340,9 +390,9 @@ module Koa {
private DataFlow::Node getAQueryParameterAccess(RouteHandler rh) { private DataFlow::Node getAQueryParameterAccess(RouteHandler rh) {
// `ctx.query.name` or `ctx.request.query.name` // `ctx.query.name` or `ctx.request.query.name`
exists(PropAccess q | exists(DataFlow::PropRead q |
q.accesses(rh.getARequestOrContextExpr(), "query") and q.accesses(rh.getARequestOrContextNode(), "query") and
result = q.flow().(DataFlow::SourceNode).getAPropertyRead() result = q.getAPropertyRead()
) )
} }
@@ -353,18 +403,18 @@ module Koa {
RouteHandler rh; RouteHandler rh;
RequestHeaderAccess() { RequestHeaderAccess() {
exists(Expr e | e = rh.getARequestOrContextExpr() | exists(DataFlow::Node e | e = rh.getARequestOrContextNode() |
exists(string propName, PropAccess headers | exists(string propName, DataFlow::PropRead headers |
// `ctx.request.header.<name>`, `ctx.request.headers.<name>` // `ctx.request.header.<name>`, `ctx.request.headers.<name>`
headers.accesses(e, propName) and headers.accesses(e, propName) and
this = headers.flow().(DataFlow::SourceNode).getAPropertyRead() this = headers.getAPropertyRead()
| |
propName = "header" or propName = "header" or
propName = "headers" propName = "headers"
) )
or or
// `ctx.request.get(<name>)` // `ctx.request.get(<name>)`
this.asExpr().(MethodCallExpr).calls(e, "get") this.(DataFlow::MethodCallNode).calls(e, "get")
) )
} }
@@ -385,24 +435,23 @@ module Koa {
/** /**
* A call to a Koa method that sets up a route. * 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; AppDefinition server;
RouteSetup() { RouteSetup() {
// app.use(fun) // app.use(fun)
server.flowsTo(this.getReceiver()) and server.ref().getAMethodCall("use") = this
this.getMethodName() = "use"
} }
override DataFlow::SourceNode getARouteHandler() { override DataFlow::SourceNode getARouteHandler() {
// `StandardRouteHandler` uses this predicate in it's charpred, so making this predicate return a `RouteHandler` would give an empty recursion. // `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.flowsTo(this.getArgument(0))
or or
// For the route-handlers that does not depend on this predicate in their charpred. // 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 } override DataFlow::Node getServer() { result = server }
} }
/** /**
@@ -412,10 +461,7 @@ module Koa {
RouteHandler rh; RouteHandler rh;
ResponseSendArgument() { ResponseSendArgument() {
exists(DataFlow::PropWrite pwn | exists(DataFlow::PropWrite pwn | pwn.writes(rh.getAResponseOrContextNode(), "body", this))
pwn.writes(DataFlow::valueNode(rh.getAResponseOrContextExpr()), "body",
DataFlow::valueNode(this))
)
} }
override RouteHandler getRouteHandler() { result = rh } override RouteHandler getRouteHandler() { result = rh }
@@ -424,12 +470,12 @@ module Koa {
/** /**
* An invocation of the `redirect` method of an HTTP response object. * An invocation of the `redirect` method of an HTTP response object.
*/ */
private class RedirectInvocation extends HTTP::RedirectInvocation, MethodCallExpr { private class RedirectInvocation extends HTTP::RedirectInvocation instanceof DataFlow::MethodCallNode {
RouteHandler rh; RouteHandler rh;
RedirectInvocation() { this.(MethodCallExpr).calls(rh.getAResponseOrContextExpr(), "redirect") } RedirectInvocation() { super.calls(rh.getAResponseOrContextNode(), "redirect") }
override Expr getUrlArgument() { result = this.getArgument(0) } override DataFlow::Node getUrlArgument() { result = this.getArgument(0) }
override RouteHandler getRouteHandler() { result = rh } override RouteHandler getRouteHandler() { result = rh }
} }

View File

@@ -10,9 +10,9 @@ private module LiveServer {
* An expression that imports the live-server package, seen as a server-definition. * An expression that imports the live-server package, seen as a server-definition.
*/ */
class ServerDefinition extends HTTP::Servers::StandardServerDefinition { 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 }
} }
/** /**
@@ -22,26 +22,22 @@ private module LiveServer {
class RouteHandler extends Connect::RouteHandler, DataFlow::FunctionNode { class RouteHandler extends Connect::RouteHandler, DataFlow::FunctionNode {
RouteHandler() { this = any(RouteSetup setup).getARouteHandler() } RouteHandler() { this = any(RouteSetup setup).getARouteHandler() }
override Parameter getRouteHandlerParameter(string kind) { override DataFlow::ParameterNode getRouteHandlerParameter(string kind) {
result = ConnectExpressShared::getRouteHandlerParameter(astNode, kind) result = ConnectExpressShared::getRouteHandlerParameter(this, kind)
} }
} }
/** /**
* The call to `require("live-server").start()`, seen as a route setup. * 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; ServerDefinition server;
API::CallNode call;
RouteSetup() { RouteSetup() { this = server.getImportNode().getMember("start").getACall() }
call = server.getImportNode().getMember("start").getACall() and
this = call.asExpr()
}
override DataFlow::SourceNode getARouteHandler() { override DataFlow::SourceNode getARouteHandler() {
exists(DataFlow::SourceNode middleware | 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() result = middleware.getAMemberCall(["push", "unshift"]).getArgument(0).getAFunctionValue()
or or
@@ -49,6 +45,6 @@ private module LiveServer {
) )
} }
override Expr getServer() { result = server } override DataFlow::Node getServer() { result = server }
} }
} }

View File

@@ -349,8 +349,8 @@ private module Pino {
or or
// `pino` is installed as the "log" property on the request object in `Express` and similar libraries. // `pino` is installed as the "log" property on the request object in `Express` and similar libraries.
// in `Hapi` the property is "logger". // in `Hapi` the property is "logger".
exists(HTTP::RequestExpr req, API::Node reqNode | exists(HTTP::RequestNode req, API::Node reqNode |
reqNode.asSource() = req.flow().getALocalSource() and reqNode.asSource() = req.getALocalSource() and
result = reqNode.getMember(["log", "logger"]) result = reqNode.getMember(["log", "logger"])
) )
} }

View File

@@ -62,11 +62,19 @@ private module Micro {
override HTTP::RouteHandler getRouteHandler() { result = h } override HTTP::RouteHandler getRouteHandler() { result = h }
} }
class MicroRequestExpr extends NodeJSLib::RequestExpr { deprecated class MicroRequestExpr extends NodeJSLib::RequestExpr {
override MicroRequestSource src; 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; override MicroResponseSource src;
} }
@@ -104,7 +112,7 @@ private module Micro {
MicroSendArgument() { MicroSendArgument() {
send = moduleMember("micro", ["send", "sendError"]).getACall() and send = moduleMember("micro", ["send", "sendError"]).getACall() and
this = send.getLastArgument().asExpr() this = send.getLastArgument()
} }
override HTTP::RouteHandler getRouteHandler() { override HTTP::RouteHandler getRouteHandler() {

View File

@@ -56,7 +56,7 @@ module NestJS {
*/ */
predicate isReturnValueReflected() { predicate isReturnValueReflected() {
getAFunctionDecorator(this) = nestjs().getMember(["Get", "Post"]).getACall() and getAFunctionDecorator(this) = nestjs().getMember(["Get", "Post"]).getACall() and
not hasRedirectDecorator() and not this.hasRedirectDecorator() and
not getAFunctionDecorator(this) = nestjs().getMember("Render").getACall() not getAFunctionDecorator(this) = nestjs().getMember("Render").getACall()
} }
@@ -93,7 +93,7 @@ module NestJS {
NestJSRequestInput() { NestJSRequestInput() {
decoratorName = decoratorName =
["Query", "Param", "Headers", "Body", "HostParam", "UploadedFile", "UploadedFiles"] and ["Query", "Param", "Headers", "Body", "HostParam", "UploadedFile", "UploadedFiles"] and
decorator = getADecorator() and decorator = this.getADecorator() and
decorator = nestjs().getMember(decoratorName).getACall() decorator = nestjs().getMember(decoratorName).getACall()
} }
@@ -105,7 +105,7 @@ module NestJS {
/** Gets a pipe applied to this parameter, not including global pipes. */ /** Gets a pipe applied to this parameter, not including global pipes. */
DataFlow::Node getAPipe() { DataFlow::Node getAPipe() {
result = getNestRouteHandler().getAPipe() result = this.getNestRouteHandler().getAPipe()
or or
result = decorator.getArgument(1) result = decorator.getArgument(1)
or or
@@ -132,7 +132,7 @@ module NestJS {
hasSanitizingPipe(this, false) hasSanitizingPipe(this, false)
or or
hasSanitizingPipe(this, true) and 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() { 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, private class NestJSRequestInputAsRequestInputAccess extends NestJSRequestInput,
HTTP::RequestInputAccess { HTTP::RequestInputAccess {
NestJSRequestInputAsRequestInputAccess() { NestJSRequestInputAsRequestInputAccess() {
not isSanitizedByPipe() and not this.isSanitizedByPipe() and
not this = any(CustomPipeClass cls).getAnAffectedParameter() 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() { 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 decorator.getNumArgument() = 0
or or
@@ -349,10 +349,10 @@ module NestJS {
ReturnValueAsResponseSend() { ReturnValueAsResponseSend() {
handler.isReturnValueReflected() and handler.isReturnValueReflected() and
this = handler.getAReturn().asExpr() and this = handler.getAReturn() and
// Only returned strings are sinks // Only returned strings are sinks
not exists(Type type | not exists(Type type |
type = getType() and type = this.asExpr().getType() and
not isStringType(type.unfold()) not isStringType(type.unfold())
) )
} }
@@ -389,15 +389,15 @@ module NestJS {
CustomParameterDecorator() { this = nestjs().getMember("createParamDecorator").getACall() } CustomParameterDecorator() { this = nestjs().getMember("createParamDecorator").getACall() }
/** Gets the `context` parameter. */ /** 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. */ /** Gets a parameter with this decorator applied. */
DataFlow::ParameterNode getADecoratedParameter() { 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. */ /** 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() }
} }
/** /**

View File

@@ -35,11 +35,10 @@ module NextJS {
*/ */
Module getAModuleWithFallbackPaths() { Module getAModuleWithFallbackPaths() {
result = getAPagesModule() and result = getAPagesModule() and
exists(DataFlow::FunctionNode staticPaths, Expr fallback | exists(DataFlow::FunctionNode staticPaths, DataFlow::Node fallback |
staticPaths = result.getAnExportedValue("getStaticPaths").getAFunctionValue() and staticPaths = result.getAnExportedValue("getStaticPaths").getAFunctionValue() and
fallback = fallback = staticPaths.getAReturn().getALocalSource().getAPropertyWrite("fallback").getRhs() and
staticPaths.getAReturn().getALocalSource().getAPropertyWrite("fallback").getRhs().asExpr() and not fallback.mayHaveBooleanValue(false)
not fallback.(BooleanLiteral).getValue() = "false"
) )
} }
@@ -230,10 +229,10 @@ module NextJS {
) )
} }
override Parameter getRouteHandlerParameter(string kind) { override DataFlow::ParameterNode getRouteHandlerParameter(string kind) {
kind = "request" and result = this.getFunction().getParameter(0) kind = "request" and result = this.getParameter(0)
or or
kind = "response" and result = this.getFunction().getParameter(1) kind = "response" and result = this.getParameter(1)
} }
} }

View File

@@ -6,8 +6,8 @@ import javascript
/** Provides classes for modeling NoSql query sinks. */ /** Provides classes for modeling NoSql query sinks. */
module NoSql { module NoSql {
/** An expression that is interpreted as a NoSql query. */ /** An expression that is interpreted as a NoSQL query. */
abstract class Query extends Expr { abstract class Query extends DataFlow::Node {
/** Gets an expression that is interpreted as a code operator in this query. */ /** Gets an expression that is interpreted as a code operator in this query. */
DataFlow::Node getACodeOperator() { none() } DataFlow::Node getACodeOperator() { none() }
} }
@@ -84,7 +84,7 @@ private module MongoDB {
class Query extends NoSql::Query { class Query extends NoSql::Query {
QueryCall qc; QueryCall qc;
Query() { this = qc.getAQueryArgument().asExpr() } Query() { this = qc.getAQueryArgument() }
override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() } override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() }
} }
@@ -496,13 +496,11 @@ private module Mongoose {
/** /**
* An expression passed to `mongoose.createConnection` to supply credentials. * An expression passed to `mongoose.createConnection` to supply credentials.
*/ */
class Credentials extends CredentialsExpr { class Credentials extends CredentialsNode {
string kind; string kind;
Credentials() { Credentials() {
exists(string prop | exists(string prop | this = createConnection().getParameter(3).getMember(prop).asSink() |
this = createConnection().getParameter(3).getMember(prop).asSink().asExpr()
|
prop = "user" and kind = "user name" prop = "user" and kind = "user name"
or or
prop = "pass" and kind = "password" prop = "pass" and kind = "password"
@@ -518,7 +516,7 @@ private module Mongoose {
class MongoDBQueryPart extends NoSql::Query { class MongoDBQueryPart extends NoSql::Query {
MongooseFunction f; MongooseFunction f;
MongoDBQueryPart() { this = f.getQueryArgument().asSink().asExpr() } MongoDBQueryPart() { this = f.getQueryArgument().asSink() }
override DataFlow::Node getACodeOperator() { override DataFlow::Node getACodeOperator() {
result = getADollarWhereProperty(f.getQueryArgument()) result = getADollarWhereProperty(f.getQueryArgument())
@@ -625,7 +623,7 @@ private module Minimongo {
class Query extends NoSql::Query { class Query extends NoSql::Query {
QueryCall qc; QueryCall qc;
Query() { this = qc.getAQueryArgument().asExpr() } Query() { this = qc.getAQueryArgument() }
override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() } override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() }
} }
@@ -685,7 +683,7 @@ private module MarsDB {
class Query extends NoSql::Query { class Query extends NoSql::Query {
QueryCall qc; QueryCall qc;
Query() { this = qc.getAQueryArgument().asExpr() } Query() { this = qc.getAQueryArgument() }
override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() } override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() }
} }
@@ -770,7 +768,7 @@ private module Redis {
RedisKeyArgument() { RedisKeyArgument() {
exists(string method, int argIndex | exists(string method, int argIndex |
QuerySignatures::argumentIsAmbiguousKey(method, argIndex) and QuerySignatures::argumentIsAmbiguousKey(method, argIndex) and
this = redis().getMember(method).getParameter(argIndex).asSink().asExpr() this = redis().getMember(method).getParameter(argIndex).asSink()
) )
} }
} }

View File

@@ -49,7 +49,7 @@ module NodeJSLib {
/** /**
* Holds if `call` is an invocation of `http.createServer` or `https.createServer`. * Holds if `call` is an invocation of `http.createServer` or `https.createServer`.
*/ */
predicate isCreateServer(CallExpr call) { predicate isCreateServer(DataFlow::CallNode call) {
exists(string pkg, string fn | exists(string pkg, string fn |
pkg = "http" and fn = "createServer" pkg = "http" and fn = "createServer"
or or
@@ -60,17 +60,39 @@ module NodeJSLib {
or or
pkg = "http2" and fn = "createSecureServer" pkg = "http2" and fn = "createSecureServer"
| |
call = DataFlow::moduleMember(pkg, fn).getAnInvocation().asExpr() call = DataFlow::moduleMember(pkg, fn).getAnInvocation()
) )
} }
/**
* 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.
*/
deprecated class ResponseExpr extends HTTP::Servers::StandardResponseExpr {
ResponseExpr() { this.flow() instanceof ResponseNode }
}
/** /**
* A Node.js HTTP response. * A Node.js HTTP response.
* *
* A server library that provides an (enhanced) NodesJS HTTP response * A server library that provides an (enhanced) NodesJS HTTP response
* object should implement a library specific subclass of this class. * object should implement a library specific subclass of this class.
*/ */
abstract class ResponseExpr extends HTTP::Servers::StandardResponseExpr { } 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. * A Node.js HTTP request.
@@ -78,7 +100,7 @@ module NodeJSLib {
* A server library that provides an (enhanced) NodesJS HTTP request * A server library that provides an (enhanced) NodesJS HTTP request
* object should implement a library specific subclass of this class. * 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. * A function used as an Node.js server route handler.
@@ -91,12 +113,12 @@ module NodeJSLib {
/** /**
* Gets the parameter of the route handler that contains the request object. * 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. * 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) }
} }
/** /**
@@ -118,7 +140,7 @@ module NodeJSLib {
private class StandardResponseSource extends ResponseSource { private class StandardResponseSource extends ResponseSource {
RouteHandler rh; RouteHandler rh;
StandardResponseSource() { this = DataFlow::parameterNode(rh.getResponseParameter()) } StandardResponseSource() { this = rh.getResponseParameter() }
/** /**
* Gets the route handler that provides this response. * Gets the route handler that provides this response.
@@ -138,7 +160,7 @@ module NodeJSLib {
private class StandardRequestSource extends RequestSource { private class StandardRequestSource extends RequestSource {
RouteHandler rh; RouteHandler rh;
StandardRequestSource() { this = DataFlow::parameterNode(rh.getRequestParameter()) } StandardRequestSource() { this = rh.getRequestParameter() }
/** /**
* Gets the route handler that handles this request. * Gets the route handler that handles this request.
@@ -147,36 +169,52 @@ module NodeJSLib {
} }
/** /**
* DEPRECATED: Use `BuiltinRouteHandlerResponseNode` instead.
* A builtin Node.js HTTP response. * A builtin Node.js HTTP response.
*/ */
private class BuiltinRouteHandlerResponseExpr extends ResponseExpr { deprecated private class BuiltinRouteHandlerResponseExpr extends ResponseExpr {
BuiltinRouteHandlerResponseExpr() { src instanceof ResponseSource } 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.
*/
deprecated private class BuiltinRouteHandlerRequestExpr extends RequestExpr {
BuiltinRouteHandlerRequestExpr() { src instanceof RequestSource }
}
/** /**
* A builtin Node.js HTTP request. * A builtin Node.js HTTP request.
*/ */
private class BuiltinRouteHandlerRequestExpr extends RequestExpr { private class BuiltinRouteHandlerRequestNode extends RequestNode {
BuiltinRouteHandlerRequestExpr() { src instanceof RequestSource } BuiltinRouteHandlerRequestNode() { src instanceof RequestSource }
} }
/** /**
* An access to a user-controlled Node.js request input. * An access to a user-controlled Node.js request input.
*/ */
private class RequestInputAccess extends HTTP::RequestInputAccess { private class RequestInputAccess extends HTTP::RequestInputAccess {
RequestExpr request; RequestNode request;
string kind; string kind;
RequestInputAccess() { RequestInputAccess() {
// `req.url` / `req.body` // `req.url` / `req.body`
kind = ["url", "body"] and kind = ["url", "body"] and
this.asExpr().(PropAccess).accesses(request, kind) this.(DataFlow::PropRead).accesses(request, kind)
or or
exists(PropAccess headers | exists(DataFlow::PropRead headers |
// `req.headers.cookie` // `req.headers.cookie`
kind = "cookie" and kind = "cookie" and
headers.accesses(request, "headers") and headers.accesses(request, "headers") and
this.asExpr().(PropAccess).accesses(headers, "cookie") this.(DataFlow::PropRead).accesses(headers, "cookie")
) )
or or
exists(RequestHeaderAccess access | this = access | exists(RequestHeaderAccess access | this = access |
@@ -194,14 +232,14 @@ module NodeJSLib {
* An access to an HTTP header (other than "Cookie") on an incoming Node.js request object. * An access to an HTTP header (other than "Cookie") on an incoming Node.js request object.
*/ */
private class RequestHeaderAccess extends HTTP::RequestHeaderAccess { private class RequestHeaderAccess extends HTTP::RequestHeaderAccess {
RequestExpr request; RequestNode request;
RequestHeaderAccess() { RequestHeaderAccess() {
exists(PropAccess headers, string name | exists(DataFlow::PropRead headers, string name |
// `req.headers.<name>` // `req.headers.<name>`
name != "cookie" and name != "cookie" and
headers.accesses(request, "headers") and headers.accesses(request, "headers") and
this.asExpr().(PropAccess).accesses(headers, name) this.(DataFlow::PropRead).accesses(headers, name)
) )
} }
@@ -213,19 +251,19 @@ module NodeJSLib {
override string getKind() { result = "header" } override string getKind() { result = "header" }
RequestExpr getRequest() { result = request } RequestNode getRequest() { result = request }
} }
class RouteSetup extends CallExpr, HTTP::Servers::StandardRouteSetup { class RouteSetup extends DataFlow::CallNode, HTTP::Servers::StandardRouteSetup {
ServerDefinition server; ServerDefinition server;
Expr handler; DataFlow::Node handler;
RouteSetup() { RouteSetup() {
server.flowsTo(this) and server.ref() = this and
handler = this.getLastArgument() handler = this.getLastArgument()
or or
server.flowsTo(this.getReceiver()) and server.ref().getAMethodCall() = this and
this.(MethodCallExpr).getMethodName().regexpMatch("on(ce)?") and this.getCalleeName().regexpMatch("on(ce)?") and
this.getArgument(0).getStringValue() = "request" and this.getArgument(0).getStringValue() = "request" and
handler = this.getArgument(1) handler = this.getArgument(1)
} }
@@ -236,7 +274,7 @@ module NodeJSLib {
private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) {
t.start() and t.start() and
result = handler.flow().getALocalSource() result = handler.getALocalSource()
or or
exists(DataFlow::TypeBackTracker t2, DataFlow::SourceNode succ | exists(DataFlow::TypeBackTracker t2, DataFlow::SourceNode succ |
succ = this.getARouteHandler(t2) succ = this.getARouteHandler(t2)
@@ -248,18 +286,24 @@ module NodeJSLib {
) )
} }
override Expr getServer() { result = server } override DataFlow::Node getServer() { result = server }
/**
* DEPRECATED: Use `getRouteHandlerNode` instead.
* Gets the expression for the handler registered by this setup.
*/
deprecated Expr getRouteHandlerExpr() { result = handler.asExpr() }
/** /**
* Gets the expression for the handler registered by this setup. * Gets the expression for the handler registered by this setup.
*/ */
Expr getRouteHandlerExpr() { result = handler } DataFlow::Node getRouteHandlerNode() { result = handler }
} }
abstract private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { abstract private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition {
ResponseExpr r; ResponseNode r;
HeaderDefinition() { astNode.getReceiver() = r } HeaderDefinition() { this.getReceiver() = r }
override HTTP::RouteHandler getRouteHandler() { result = r.getRouteHandler() } override HTTP::RouteHandler getRouteHandler() { result = r.getRouteHandler() }
} }
@@ -268,7 +312,7 @@ module NodeJSLib {
* A call to the `setHeader` method of an HTTP response. * A call to the `setHeader` method of an HTTP response.
*/ */
private class SetHeader extends HeaderDefinition { private class SetHeader extends HeaderDefinition {
SetHeader() { astNode.getMethodName() = "setHeader" } SetHeader() { this.getMethodName() = "setHeader" }
} }
/** /**
@@ -276,15 +320,15 @@ module NodeJSLib {
*/ */
private class WriteHead extends HeaderDefinition { private class WriteHead extends HeaderDefinition {
WriteHead() { WriteHead() {
astNode.getMethodName() = "writeHead" and this.getMethodName() = "writeHead" and
astNode.getNumArgument() >= 1 this.getNumArgument() >= 1
} }
override predicate definesExplicitly(string headerName, Expr headerValue) { override predicate definesHeaderValue(string headerName, DataFlow::Node headerValue) {
astNode.getNumArgument() > 1 and this.getNumArgument() > 1 and
exists(DataFlow::SourceNode headers, string header | exists(DataFlow::SourceNode headers, string header |
headers.flowsToExpr(astNode.getLastArgument()) and headers.flowsTo(this.getLastArgument()) and
headers.hasPropertyWrite(header, DataFlow::valueNode(headerValue)) and headers.hasPropertyWrite(header, headerValue) and
headerName = header.toLowerCase() headerName = header.toLowerCase()
) )
} }
@@ -363,9 +407,9 @@ module NodeJSLib {
HTTP::RouteHandler rh; HTTP::RouteHandler rh;
ResponseSendArgument() { ResponseSendArgument() {
exists(MethodCallExpr mce, string m | m = "write" or m = "end" | exists(DataFlow::MethodCallNode mcn, string m | m = "write" or m = "end" |
mce.calls(any(ResponseExpr e | e.getRouteHandler() = rh), m) and mcn.calls(any(ResponseNode e | e.getRouteHandler() = rh), m) and
this = mce.getArgument(0) and this = mcn.getArgument(0) and
// don't mistake callback functions as data // don't mistake callback functions as data
not this.analyze().getAValue() instanceof AbstractFunction not this.analyze().getAValue() instanceof AbstractFunction
) )
@@ -382,11 +426,10 @@ module NodeJSLib {
} }
/** An expression that is passed as `http.request({ auth: <expr> }, ...)`. */ /** An expression that is passed as `http.request({ auth: <expr> }, ...)`. */
class Credentials extends CredentialsExpr { class Credentials extends CredentialsNode {
Credentials() { Credentials() {
exists(string http | http = "http" or http = "https" | exists(string http | http = "http" or http = "https" |
this = this = DataFlow::moduleMember(http, "request").getACall().getOptionArgument(0, "auth")
DataFlow::moduleMember(http, "request").getACall().getOptionArgument(0, "auth").asExpr()
) )
} }
@@ -994,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)})`. * 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() { ClientRequestLoginUsername() {
exists(ClientRequestLoginCallback callback | exists(ClientRequestLoginCallback callback | this = callback.getACall().getArgument(0))
this = callback.getACall().getArgument(0).asExpr()
)
} }
override string getCredentialsKind() { result = "Node.js http(s) client login username" } override string getCredentialsKind() { result = "Node.js http(s) client login username" }
@@ -1007,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)})`. * 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() { ClientRequestLoginPassword() {
exists(ClientRequestLoginCallback callback | exists(ClientRequestLoginCallback callback | this = callback.getACall().getArgument(1))
this = callback.getACall().getArgument(1).asExpr()
)
} }
override string getCredentialsKind() { result = "Node.js http(s) client login password" } override string getCredentialsKind() { result = "Node.js http(s) client login password" }

View File

@@ -31,13 +31,13 @@ module PkgCloud {
/** /**
* An expression that is used for authentication through pkgcloud. * An expression that is used for authentication through pkgcloud.
*/ */
class Credentials extends CredentialsExpr { class Credentials extends CredentialsNode {
string kind; string kind;
Credentials() { Credentials() {
exists(string propertyName, DataFlow::InvokeNode invk, int i | exists(string propertyName, DataFlow::InvokeNode invk, int i |
takesConfigurationObject(invk, i) and takesConfigurationObject(invk, i) and
this = invk.getOptionArgument(0, propertyName).asExpr() this = invk.getOptionArgument(0, propertyName)
| |
/* /*
* Catch-all support for the following providers: * Catch-all support for the following providers:

View File

@@ -6,7 +6,7 @@ import javascript
module Request { module Request {
/** A credentials expression that is used for authentication. */ /** A credentials expression that is used for authentication. */
class Credentials extends CredentialsExpr { class Credentials extends CredentialsNode {
string kind; string kind;
Credentials() { Credentials() {
@@ -20,9 +20,9 @@ module Request {
action = mod.getAMemberCall(any(HTTP::RequestMethodName n).toLowerCase()) 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'); // request.get(url).auth('username', 'password', _, 'token');
auth = action.getAMemberCall("auth").asExpr() and auth = action.getAMemberCall("auth") and
this = auth.getArgument(argIndex) this = auth.getArgument(argIndex)
| |
argIndex = 0 and kind = "user name" argIndex = 0 and kind = "user name"
@@ -35,7 +35,7 @@ module Request {
exists(DataFlow::ObjectLiteralNode auth, string propertyName | exists(DataFlow::ObjectLiteralNode auth, string propertyName |
// request.get(url, { auth: {user: 'username', pass: 'password', bearer: 'token'}}) // request.get(url, { auth: {user: 'username', pass: 'password', bearer: 'token'}})
auth.flowsTo(action.getOptionArgument(1, "auth")) and auth.flowsTo(action.getOptionArgument(1, "auth")) and
auth.hasPropertyWrite(propertyName, DataFlow::valueNode(this)) auth.hasPropertyWrite(propertyName, this)
| |
(propertyName = "user" or propertyName = "username") and (propertyName = "user" or propertyName = "username") and
kind = "user name" kind = "user name"

View File

@@ -9,10 +9,10 @@ module Restify {
/** /**
* An expression that creates a new Restify server. * An expression that creates a new Restify server.
*/ */
class ServerDefinition extends HTTP::Servers::StandardServerDefinition, CallExpr { class ServerDefinition extends HTTP::Servers::StandardServerDefinition, DataFlow::CallNode {
ServerDefinition() { ServerDefinition() {
// `server = restify.createServer()` // `server = restify.createServer()`
this = DataFlow::moduleMember("restify", "createServer").getACall().asExpr() this = DataFlow::moduleMember("restify", "createServer").getACall()
} }
} }
@@ -69,38 +69,54 @@ module Restify {
} }
/** /**
* DEPRECATED: Use `ResponseNode` instead.
* A Node.js HTTP response provided by Restify. * A Node.js HTTP response provided by Restify.
*/ */
class ResponseExpr extends NodeJSLib::ResponseExpr { deprecated class ResponseExpr extends NodeJSLib::ResponseExpr {
ResponseExpr() { src instanceof ResponseSource } ResponseExpr() { src instanceof ResponseSource }
} }
/**
* 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.
*/
deprecated class RequestExpr extends NodeJSLib::RequestExpr {
RequestExpr() { src instanceof RequestSource }
}
/** /**
* A Node.js HTTP request provided by Restify. * A Node.js HTTP request provided by Restify.
*/ */
class RequestExpr extends NodeJSLib::RequestExpr { class RequestNode extends NodeJSLib::RequestNode {
RequestExpr() { src instanceof RequestSource } RequestNode() { src instanceof RequestSource }
} }
/** /**
* An access to a user-controlled Restify request input. * An access to a user-controlled Restify request input.
*/ */
private class RequestInputAccess extends HTTP::RequestInputAccess { private class RequestInputAccess extends HTTP::RequestInputAccess {
RequestExpr request; RequestNode request;
string kind; string kind;
RequestInputAccess() { RequestInputAccess() {
exists(MethodCallExpr query | exists(DataFlow::MethodCallNode query |
// `request.getQuery().<name>` // `request.getQuery().<name>`
kind = "parameter" and kind = "parameter" and
query.calls(request, "getQuery") and query.calls(request, "getQuery") and
this.asExpr().(PropAccess).accesses(query, _) this.(DataFlow::PropRead).accesses(query, _)
) )
or or
exists(string methodName | exists(string methodName |
// `request.href()` or `request.getPath()` // `request.href()` or `request.getPath()`
kind = "url" and kind = "url" and
this.asExpr().(MethodCallExpr).calls(request, methodName) this.(DataFlow::MethodCallNode).calls(request, methodName)
| |
methodName = "href" or methodName = "href" or
methodName = "getPath" methodName = "getPath"
@@ -108,13 +124,12 @@ module Restify {
or or
// `request.getContentType()`, `request.userAgent()`, `request.trailer(...)`, `request.header(...)` // `request.getContentType()`, `request.userAgent()`, `request.trailer(...)`, `request.header(...)`
kind = "header" and kind = "header" and
this.asExpr() this.(DataFlow::MethodCallNode)
.(MethodCallExpr)
.calls(request, ["getContentType", "userAgent", "trailer", "header"]) .calls(request, ["getContentType", "userAgent", "trailer", "header"])
or or
// `req.cookies // `req.cookies
kind = "cookie" and kind = "cookie" and
this.asExpr().(PropAccess).accesses(request, "cookies") this.(DataFlow::PropRead).accesses(request, "cookies")
} }
override RouteHandler getRouteHandler() { result = request.getRouteHandler() } override RouteHandler getRouteHandler() { result = request.getRouteHandler() }
@@ -128,28 +143,27 @@ module Restify {
private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition { private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition {
HeaderDefinition() { HeaderDefinition() {
// response.header('Cache-Control', 'no-cache') // response.header('Cache-Control', 'no-cache')
astNode.getReceiver() instanceof ResponseExpr and this.getReceiver() instanceof ResponseNode and
astNode.getMethodName() = "header" this.getMethodName() = "header"
} }
override RouteHandler getRouteHandler() { astNode.getReceiver() = result.getAResponseExpr() } override RouteHandler getRouteHandler() { this.getReceiver() = result.getAResponseNode() }
} }
/** /**
* A call to a Restify method that sets up a route. * 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; ServerDefinition server;
RouteSetup() { RouteSetup() {
// server.get('/', fun) // server.get('/', fun)
// server.head('/', fun) // server.head('/', fun)
server.flowsTo(getReceiver()) and server.ref().getAMethodCall(any(HTTP::RequestMethodName m).toLowerCase()) = this
getMethodName() = any(HTTP::RequestMethodName m).toLowerCase()
} }
override DataFlow::SourceNode getARouteHandler() { result.flowsToExpr(getArgument(1)) } override DataFlow::SourceNode getARouteHandler() { result.flowsTo(this.getArgument(1)) }
override Expr getServer() { result = server } override DataFlow::Node getServer() { result = server }
} }
} }

View File

@@ -5,26 +5,26 @@
import javascript import javascript
module SQL { module SQL {
/** A string-valued expression that is interpreted as a SQL command. */ /** A string-valued dataflow node that is interpreted as a SQL command. */
abstract class SqlString extends Expr { } abstract class SqlString extends DataFlow::Node { }
private class SqlStringFromModel extends SqlString { 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. * a SQL command.
*/ */
abstract class SqlSanitizer extends Expr { abstract class SqlSanitizer extends DataFlow::Node {
Expr input; DataFlow::Node input;
Expr output; DataFlow::Node output;
/** Gets the input expression being sanitized. */ /** Gets the input expression being sanitized. */
Expr getInput() { result = input } DataFlow::Node getInput() { result = input }
/** Gets the output expression containing the sanitized value. */ /** Gets the output expression containing the sanitized value. */
Expr getOutput() { result = output } DataFlow::Node getOutput() { result = output }
} }
} }
@@ -90,26 +90,26 @@ private module MySql {
/** An expression that is passed to the `query` method and hence interpreted as SQL. */ /** An expression that is passed to the `query` method and hence interpreted as SQL. */
class QueryString extends SQL::SqlString { 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. */ /** 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() { 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 input = this.getArgument(0) and
output = this output = this
} }
} }
/** An expression that is passed as user name or password to `mysql.createConnection`. */ /** An expression that is passed as user name or password to `mysql.createConnection`. */
class Credentials extends CredentialsExpr { class Credentials extends CredentialsNode {
string kind; string kind;
Credentials() { Credentials() {
exists(API::Node callee, string prop | exists(API::Node callee, string prop |
callee in [createConnection(), createPool()] and 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" prop = "user" and kind = "user name"
or or
@@ -198,21 +198,21 @@ private module Postgres {
/** An expression that is passed to the `query` method and hence interpreted as SQL. */ /** An expression that is passed to the `query` method and hence interpreted as SQL. */
class QueryString extends SQL::SqlString { class QueryString extends SQL::SqlString {
QueryString() { QueryString() {
this = any(QueryCall qc).getAQueryArgument().asExpr() this = any(QueryCall qc).getAQueryArgument()
or or
this = API::moduleImport("pg-cursor").getParameter(0).asSink().asExpr() this = API::moduleImport("pg-cursor").getParameter(0).asSink()
} }
} }
/** An expression that is passed as user name or password when creating a client or a pool. */ /** 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; string kind;
Credentials() { Credentials() {
exists(string prop | exists(string prop |
this = [newClient(), newPool()].getParameter(0).getMember(prop).asSink().asExpr() this = [newClient(), newPool()].getParameter(0).getMember(prop).asSink()
or or
this = pgPromise().getParameter(0).getMember(prop).asSink().asExpr() this = pgPromise().getParameter(0).getMember(prop).asSink()
| |
prop = "user" and kind = "user name" prop = "user" and kind = "user name"
or or
@@ -349,7 +349,7 @@ private module Postgres {
/** An expression that is interpreted as SQL by `pg-promise`. */ /** An expression that is interpreted as SQL by `pg-promise`. */
class PgPromiseQueryString extends SQL::SqlString { 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. */ /** An expression that is passed to the `query` method and hence interpreted as SQL. */
class QueryString extends SQL::SqlString { 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 { class QueryString extends SQL::SqlString {
QueryString() { QueryString() {
exists(DatabaseAccess dba | dba instanceof QueryTemplateExpr or dba instanceof QueryCall | exists(DatabaseAccess dba | dba instanceof QueryTemplateExpr or dba instanceof QueryCall |
this = dba.getAQueryArgument().asExpr() this = dba.getAQueryArgument()
) )
} }
} }
@@ -478,14 +478,14 @@ private module MsSql {
/** An element of a query template, which is automatically sanitized. */ /** An element of a query template, which is automatically sanitized. */
class QueryTemplateSanitizer extends SQL::SqlSanitizer { class QueryTemplateSanitizer extends SQL::SqlSanitizer {
QueryTemplateSanitizer() { QueryTemplateSanitizer() {
this = any(QueryTemplateExpr qte).getAQueryArgument().asExpr() and this = any(QueryTemplateExpr qte).getAQueryArgument() and
input = this and input = this and
output = this output = this
} }
} }
/** An expression that is passed as user name or password when creating a client or a pool. */ /** 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; string kind;
Credentials() { Credentials() {
@@ -495,7 +495,7 @@ private module MsSql {
or or
callee = mssql().getMember("ConnectionPool") callee = mssql().getMember("ConnectionPool")
) and ) and
this = callee.getParameter(0).getMember(prop).asSink().asExpr() and this = callee.getParameter(0).getMember(prop).asSink() and
( (
prop = "user" and kind = "user name" prop = "user" and kind = "user name"
or or

View File

@@ -29,8 +29,8 @@ private class PromotedExpressCandidate extends Express::RouteHandler,
HTTP::Servers::StandardRouteHandler { HTTP::Servers::StandardRouteHandler {
PromotedExpressCandidate() { this instanceof ConnectExpressShared::RouteHandlerCandidate } PromotedExpressCandidate() { this instanceof ConnectExpressShared::RouteHandlerCandidate }
override Parameter getRouteHandlerParameter(string kind) { override DataFlow::ParameterNode getRouteHandlerParameter(string kind) {
result = ConnectExpressShared::getRouteHandlerParameter(getAstNode(), kind) result = ConnectExpressShared::getRouteHandlerParameter(this, kind)
} }
} }
@@ -41,7 +41,7 @@ private class PromotedConnectCandidate extends Connect::RouteHandler,
HTTP::Servers::StandardRouteHandler { HTTP::Servers::StandardRouteHandler {
PromotedConnectCandidate() { this instanceof ConnectExpressShared::RouteHandlerCandidate } PromotedConnectCandidate() { this instanceof ConnectExpressShared::RouteHandlerCandidate }
override Parameter getRouteHandlerParameter(string kind) { override DataFlow::ParameterNode getRouteHandlerParameter(string kind) {
result = ConnectExpressShared::getRouteHandlerParameter(getAstNode(), kind) result = ConnectExpressShared::getRouteHandlerParameter(this, kind)
} }
} }

View File

@@ -13,9 +13,25 @@ import javascript
import semmle.javascript.security.internal.SensitiveDataHeuristics import semmle.javascript.security.internal.SensitiveDataHeuristics
private import HeuristicNames 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. */ /** An expression that might contain sensitive data. */
cached 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. */ /** Gets a human-readable description of this expression for use in alert messages. */
cached cached
abstract string describe(); abstract string describe();
@@ -26,33 +42,33 @@ abstract class SensitiveExpr extends Expr {
} }
/** A function call that might produce sensitive data. */ /** A function call that might produce sensitive data. */
class SensitiveCall extends SensitiveExpr, InvokeExpr { class SensitiveCall extends SensitiveNode instanceof DataFlow::InvokeNode {
SensitiveDataClassification classification; SensitiveDataClassification classification;
SensitiveCall() { SensitiveCall() {
classification = this.getCalleeName().(SensitiveDataFunctionName).getClassification() classification = super.getCalleeName().(SensitiveDataFunctionName).getClassification()
or or
// This is particularly to pick up methods with an argument like "password", which // This is particularly to pick up methods with an argument like "password", which
// may indicate a lookup. // may indicate a lookup.
exists(string s | this.getAnArgument().mayHaveStringValue(s) | exists(string s | super.getAnArgument().mayHaveStringValue(s) |
nameIndicatesSensitiveData(s, classification) 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 } override SensitiveDataClassification getClassification() { result = classification }
} }
/** An access to a variable or property that might contain sensitive data. */ /** An access to a variable or property that might contain sensitive data. */
abstract class SensitiveVariableAccess extends SensitiveExpr { abstract class SensitiveVariableAccess extends SensitiveNode {
string name; string name;
SensitiveVariableAccess() { SensitiveVariableAccess() {
this.(VarAccess).getName() = name this.asExpr().(VarAccess).getName() = name
or or
exists(DataFlow::PropRead pr | exists(DataFlow::PropRead pr |
this = pr.asExpr() and this = pr and
pr.getPropertyName() = name pr.getPropertyName() = name
) )
} }
@@ -173,10 +189,8 @@ class ProtectCall extends DataFlow::CallNode {
} }
/** An expression that might contain a clear-text password. */ /** An expression that might contain a clear-text password. */
class CleartextPasswordExpr extends SensitiveExpr { class CleartextPasswordExpr extends SensitiveNode {
CleartextPasswordExpr() { CleartextPasswordExpr() { this.getClassification() = SensitiveDataClassification::password() }
this.(SensitiveExpr).getClassification() = SensitiveDataClassification::password()
}
override string describe() { none() } override string describe() { none() }

View File

@@ -30,10 +30,8 @@ module BrokenCryptoAlgorithm {
* A sensitive expression, viewed as a data flow source for sensitive information * A sensitive expression, viewed as a data flow source for sensitive information
* in broken or weak cryptographic algorithms. * in broken or weak cryptographic algorithms.
*/ */
class SensitiveExprSource extends Source, DataFlow::ValueNode { class SensitiveExprSource extends Source instanceof SensitiveNode {
override SensitiveExpr astNode; override string describe() { result = SensitiveNode.super.describe() }
override string describe() { result = astNode.describe() }
} }
/** /**
@@ -43,7 +41,7 @@ module BrokenCryptoAlgorithm {
WeakCryptographicOperationSink() { WeakCryptographicOperationSink() {
exists(CryptographicOperation application | exists(CryptographicOperation application |
application.getAlgorithm().isWeak() and application.getAlgorithm().isWeak() and
this.asExpr() = application.getInput() this = application.getInput()
) )
} }
} }

View File

@@ -30,15 +30,13 @@ module CleartextStorage {
* A sensitive expression, viewed as a data flow source for cleartext storage * A sensitive expression, viewed as a data flow source for cleartext storage
* of sensitive information. * of sensitive information.
*/ */
class SensitiveExprSource extends Source, DataFlow::ValueNode { class SensitiveExprSource extends Source instanceof SensitiveNode {
override SensitiveExpr astNode;
SensitiveExprSource() { SensitiveExprSource() {
// storing user names or account names in plaintext isn't usually a problem // 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. */ /** A call to any function whose name suggests that it encodes or encrypts its arguments. */
@@ -52,8 +50,8 @@ module CleartextStorage {
class CookieStorageSink extends Sink { class CookieStorageSink extends Sink {
CookieStorageSink() { CookieStorageSink() {
exists(HTTP::CookieDefinition cookieDef | exists(HTTP::CookieDefinition cookieDef |
this.asExpr() = cookieDef.getValueArgument() or this = cookieDef.getValueArgument() or
this.asExpr() = cookieDef.getHeaderArgument() this = cookieDef.getHeaderArgument()
) )
} }
} }
@@ -61,16 +59,12 @@ module CleartextStorage {
/** /**
* An expression set as a value of localStorage or sessionStorage. * An expression set as a value of localStorage or sessionStorage.
*/ */
class WebStorageSink extends Sink { class WebStorageSink extends Sink instanceof WebStorageWrite { }
WebStorageSink() { this.asExpr() instanceof WebStorageWrite }
}
/** /**
* An expression stored by AngularJS. * An expression stored by AngularJS.
*/ */
class AngularJSStorageSink extends Sink { class AngularJSStorageSink extends Sink {
AngularJSStorageSink() { AngularJSStorageSink() { any(AngularJS::AngularJSCallNode call).storesArgumentGlobally(this) }
any(AngularJS::AngularJSCall call).storesArgumentGlobally(this.asExpr())
}
} }
} }

View File

@@ -57,23 +57,23 @@ module ClientSideUrlRedirect {
* when `base` is the current URL. * when `base` is the current URL.
*/ */
predicate untrustedUrlSubstring(DataFlow::Node base, DataFlow::Node substring) { predicate untrustedUrlSubstring(DataFlow::Node base, DataFlow::Node substring) {
exists(MethodCallExpr mce, string methodName | exists(DataFlow::MethodCallNode mcn, string methodName |
mce = substring.asExpr() and mce.calls(base.asExpr(), methodName) mcn = substring and mcn.calls(base, methodName)
| |
methodName = "split" and methodName = "split" and
// exclude all splits where only the prefix is accessed, which is safe for url-redirects. // 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 or
methodName = StringOps::substringMethodName() and methodName = StringOps::substringMethodName() and
// exclude `location.href.substring(0, ...)` and similar, which can // exclude `location.href.substring(0, ...)` and similar, which can
// never refer to the query string // never refer to the query string
not mce.getArgument(0).(NumberLiteral).getIntValue() = 0 not mcn.getArgument(0).getIntValue() = 0
) )
or or
exists(MethodCallExpr mce | exists(DataFlow::MethodCallNode mcn |
substring.asExpr() = mce and substring = mcn and
mce = any(DataFlow::RegExpCreationNode re).getAMethodCall("exec").asExpr() and mcn = any(DataFlow::RegExpCreationNode re).getAMethodCall("exec") and
base.asExpr() = mce.getArgument(0) base = mcn.getArgument(0)
) )
} }
@@ -104,7 +104,9 @@ module ClientSideUrlRedirect {
xss = true xss = true
or or
// An assignment to `location` // 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 xss = true
or or
// An assignment to `location.href`, `location.protocol` or `location.hostname` // An assignment to `location.href`, `location.protocol` or `location.hostname`
@@ -119,7 +121,7 @@ module ClientSideUrlRedirect {
// A redirection using the AngularJS `$location` service // A redirection using the AngularJS `$location` service
exists(AngularJS::ServiceReference service | exists(AngularJS::ServiceReference service |
service.getName() = "$location" and service.getName() = "$location" and
this.asExpr() = service.getAMethodCall("url").getArgument(0) this = service.getAMethodCall("url").getArgument(0)
) and ) and
xss = false xss = false
} }
@@ -177,7 +179,7 @@ module ClientSideUrlRedirect {
) )
or or
// e.g. node.setAttribute("href", sink) // e.g. node.setAttribute("href", sink)
any(DomMethodCallExpr call).interpretsArgumentsAsUrl(this.asExpr()) any(DomMethodCallNode call).interpretsArgumentsAsUrl(this)
} }
override predicate isXssSink() { any() } override predicate isXssSink() { any() }
@@ -189,9 +191,9 @@ module ClientSideUrlRedirect {
*/ */
class AttributeWriteUrlSink extends ScriptUrlSink, DataFlow::ValueNode { class AttributeWriteUrlSink extends ScriptUrlSink, DataFlow::ValueNode {
AttributeWriteUrlSink() { AttributeWriteUrlSink() {
exists(DomPropWriteNode pw | exists(DomPropertyWrite pw |
pw.interpretsValueAsJavaScriptUrl() and pw.interpretsValueAsJavaScriptUrl() and
this = DataFlow::valueNode(pw.getRhs()) this = pw.getRhs()
) )
} }

View File

@@ -37,7 +37,7 @@ module CodeInjection {
*/ */
class AngularJSExpressionSink extends Sink, DataFlow::ValueNode { class AngularJSExpressionSink extends Sink, DataFlow::ValueNode {
AngularJSExpressionSink() { AngularJSExpressionSink() {
any(AngularJS::AngularJSCall call).interpretsArgumentAsCode(this.asExpr()) any(AngularJS::AngularJSCallNode call).interpretsArgumentAsCode(this)
} }
} }

View File

@@ -46,12 +46,12 @@ module CorsMisconfigurationForCredentials {
CorsOriginHeaderWithAssociatedCredentialHeader() { CorsOriginHeaderWithAssociatedCredentialHeader() {
exists( exists(
HTTP::RouteHandler routeHandler, HTTP::ExplicitHeaderDefinition origin, HTTP::RouteHandler routeHandler, HTTP::ExplicitHeaderDefinition origin,
Expr credentialsValue DataFlow::Node credentialsValue
| |
routeHandler.getAResponseHeader(_) = origin and routeHandler.getAResponseHeader(_) = origin and
routeHandler.getAResponseHeader(_) = credentials and routeHandler.getAResponseHeader(_) = credentials and
origin.definesExplicitly("access-control-allow-origin", this.asExpr()) and origin.definesHeaderValue("access-control-allow-origin", this) and
credentials.definesExplicitly("access-control-allow-credentials", credentialsValue) credentials.definesHeaderValue("access-control-allow-credentials", credentialsValue)
| |
credentialsValue.mayHaveBooleanValue(true) or credentialsValue.mayHaveBooleanValue(true) or
credentialsValue.mayHaveStringValue("true") credentialsValue.mayHaveStringValue("true")

View File

@@ -21,14 +21,28 @@ class DomGlobalVariable extends GlobalVariable {
/** DEPRECATED: Alias for DomGlobalVariable */ /** DEPRECATED: Alias for DomGlobalVariable */
deprecated class DOMGlobalVariable = 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. */ /** Holds if `e` could refer to the `location` property of a DOM node. */
predicate isLocation(Expr e) { predicate isLocationNode(DataFlow::Node e) {
e = DOM::domValueRef().getAPropertyReference("location").asExpr() e = DOM::domValueRef().getAPropertyReference("location")
or 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 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. * A call to a DOM method.
*/ */
class DomMethodCallExpr extends MethodCallExpr { deprecated class DomMethodCallExpr extends MethodCallExpr {
DomMethodCallExpr() { isDomValue(this.getReceiver()) } 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. * 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 | exists(int argPos, string name |
arg = this.getArgument(argPos) and arg = this.getArgument(argPos) and
name = this.getMethodName() name = this.getMethodName()
@@ -86,7 +137,7 @@ class DomMethodCallExpr extends MethodCallExpr {
/** /**
* Holds if `arg` is an argument that is used as an URL. * 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 | exists(int argPos, string name |
arg = this.getArgument(argPos) and arg = this.getArgument(argPos) and
name = this.getMethodName() name = this.getMethodName()
@@ -104,56 +155,84 @@ class DomMethodCallExpr extends MethodCallExpr {
} }
/** DEPRECATED: Alias for interpretsArgumentsAsUrl */ /** 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: 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. * An assignment to a property of a DOM object.
*/ */
class DomPropWriteNode extends Assignment { deprecated class DomPropWriteNode extends Assignment {
PropAccess lhs; DomPropertyWrite node;
DomPropWriteNode() { DomPropWriteNode() { this.flow() = node }
lhs = this.getLhs() and
isDomValue(lhs.getBase())
}
/** /**
* Holds if the assigned value is interpreted as HTML. * Holds if the assigned value is interpreted as HTML.
*/ */
predicate interpretsValueAsHtml() { predicate interpretsValueAsHtml() { node.interpretsValueAsHtml() }
lhs.getPropertyName() = "innerHTML" or
lhs.getPropertyName() = "outerHTML"
}
/** DEPRECATED: Alias for interpretsValueAsHtml */ /** DEPRECATED: Alias for interpretsValueAsHtml */
deprecated predicate interpretsValueAsHTML() { this.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. * Holds if the assigned value is interpreted as JavaScript via javascript: protocol.
*/ */
predicate interpretsValueAsJavaScriptUrl() { 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()
or
result = super.getWriteNode().(AssignAddExpr).getRhs().flow()
} }
} }
/** /**
* A value written to web storage, like `localStorage` or `sessionStorage`. * A value written to web storage, like `localStorage` or `sessionStorage`.
*/ */
class WebStorageWrite extends Expr { class WebStorageWrite extends DataFlow::Node {
WebStorageWrite() { WebStorageWrite() {
exists(DataFlow::SourceNode webStorage | exists(DataFlow::SourceNode webStorage |
webStorage = DataFlow::globalVarRef("localStorage") or webStorage = DataFlow::globalVarRef("localStorage") or
webStorage = DataFlow::globalVarRef("sessionStorage") webStorage = DataFlow::globalVarRef("sessionStorage")
| |
// an assignment to `window.localStorage[someProp]` // an assignment to `window.localStorage[someProp]`
this = webStorage.getAPropertyWrite().getRhs().asExpr() this = webStorage.getAPropertyWrite().getRhs()
or or
// an invocation of `window.localStorage.setItem` // an invocation of `window.localStorage.setItem`
this = webStorage.getAMethodCall("setItem").getArgument(1).asExpr() this = webStorage.getAMethodCall("setItem").getArgument(1)
) )
} }
} }

View File

@@ -31,7 +31,7 @@ module DomBasedXss {
) )
or or
// call to an Angular method that interprets its argument as HTML // 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 or
// call to a WinJS function that interprets its argument as HTML // call to a WinJS function that interprets its argument as HTML
exists(DataFlow::MethodCallNode mcn, string m | exists(DataFlow::MethodCallNode mcn, string m |
@@ -130,12 +130,12 @@ module DomBasedXss {
class DomSink extends Sink { class DomSink extends Sink {
DomSink() { DomSink() {
// Call to a DOM function that inserts its argument into the DOM // Call to a DOM function that inserts its argument into the DOM
any(DomMethodCallExpr call).interpretsArgumentsAsHtml(this.asExpr()) any(DomMethodCallNode call).interpretsArgumentsAsHtml(this)
or or
// Assignment to a dangerous DOM property // Assignment to a dangerous DOM property
exists(DomPropWriteNode pw | exists(DomPropertyWrite pw |
pw.interpretsValueAsHtml() and pw.interpretsValueAsHtml() and
this = DataFlow::valueNode(pw.getRhs()) this = pw.getRhs()
) )
or or
// `html` or `source.html` properties of React Native `WebView` // `html` or `source.html` properties of React Native `WebView`
@@ -159,7 +159,7 @@ module DomBasedXss {
) )
or or
exists(DataFlow::MethodCallNode ccf | exists(DataFlow::MethodCallNode ccf |
isDomValue(ccf.getReceiver().asExpr()) and isDomNode(ccf.getReceiver()) and
ccf.getMethodName() = "createContextualFragment" and ccf.getMethodName() = "createContextualFragment" and
this = ccf.getArgument(0) this = ccf.getArgument(0)
) )

View File

@@ -165,7 +165,7 @@ module ExternalApiUsedWithUntrustedData {
not param = base.getReceiver() not param = base.getReceiver()
| |
result = param and result = param and
name = param.asSource().asExpr().(Parameter).getName() name = param.asSource().(DataFlow::ParameterNode).getName()
or or
param.asSource().asExpr() instanceof DestructuringPattern and param.asSource().asExpr() instanceof DestructuringPattern and
result = param.getMember(name) result = param.getMember(name)

View File

@@ -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. * as a credentials sink.
*/ */
class DefaultCredentialsSink extends Sink, DataFlow::ValueNode { class DefaultCredentialsSink extends Sink instanceof CredentialsNode {
override CredentialsExpr astNode; override string getKind() { result = super.getCredentialsKind() }
override string getKind() { result = astNode.getCredentialsKind() }
} }
} }

View File

@@ -30,14 +30,12 @@ module InsufficientPasswordHash {
* A potential clear-text password, considered as a source for password hashing * A potential clear-text password, considered as a source for password hashing
* with insufficient computational effort. * with insufficient computational effort.
*/ */
class CleartextPasswordSource extends Source, DataFlow::ValueNode { class CleartextPasswordSource extends Source instanceof SensitiveNode {
override SensitiveExpr astNode;
CleartextPasswordSource() { CleartextPasswordSource() {
astNode.getClassification() = SensitiveDataClassification::password() super.getClassification() = SensitiveDataClassification::password()
} }
override string describe() { result = astNode.describe() } override string describe() { result = SensitiveNode.super.describe() }
} }
/** /**
@@ -49,7 +47,7 @@ module InsufficientPasswordHash {
application.getAlgorithm().isWeak() or application.getAlgorithm().isWeak() or
not application.getAlgorithm() instanceof PasswordHashingAlgorithm not application.getAlgorithm() instanceof PasswordHashingAlgorithm
| |
this.asExpr() = application.getInput() this = application.getInput()
) )
} }
} }

View File

@@ -199,7 +199,7 @@ class RateLimiterFlexibleRateLimiter extends DataFlow::FunctionNode {
rateLimiterClassName.matches("RateLimiter%") and rateLimiterClassName.matches("RateLimiter%") and
rateLimiterClass = API::moduleImport("rate-limiter-flexible").getMember(rateLimiterClassName) and rateLimiterClass = API::moduleImport("rate-limiter-flexible").getMember(rateLimiterClassName) and
rateLimiterConsume = rateLimiterClass.getInstance().getMember("consume") 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()) request.getAPropertyRead().flowsTo(rateLimiterConsume.getAParameter().asSink())
) )
} }

View File

@@ -36,7 +36,5 @@ module NosqlInjection {
} }
/** An expression interpreted as a NoSql query, viewed as a sink. */ /** An expression interpreted as a NoSql query, viewed as a sink. */
class NosqlQuerySink extends Sink, DataFlow::ValueNode { class NosqlQuerySink extends Sink instanceof NoSql::Query { }
override NoSql::Query astNode;
}
} }

View File

@@ -45,7 +45,7 @@ class Configuration extends TaintTracking::Configuration {
inlbl = TaintedObject::label() and inlbl = TaintedObject::label() and
outlbl = TaintedObject::label() and outlbl = TaintedObject::label() and
exists(NoSql::Query query, DataFlow::SourceNode queryObj | exists(NoSql::Query query, DataFlow::SourceNode queryObj |
queryObj.flowsToExpr(query) and queryObj.flowsTo(query) and
queryObj.flowsTo(trg) and queryObj.flowsTo(trg) and
src = queryObj.getAPropertyWrite().getRhs() src = queryObj.getAPropertyWrite().getRhs()
) )

View File

@@ -41,9 +41,7 @@ module PostMessageStar {
* A sensitive expression, viewed as a data flow source for cross-window communication * A sensitive expression, viewed as a data flow source for cross-window communication
* with unrestricted origin. * with unrestricted origin.
*/ */
class SensitiveExprSource extends Source, DataFlow::ValueNode { class SensitiveExprSource extends Source instanceof SensitiveNode { }
override SensitiveExpr astNode;
}
/** A call to any function whose name suggests that it encodes or encrypts its arguments. */ /** A call to any function whose name suggests that it encodes or encrypts its arguments. */
class ProtectSanitizer extends Sanitizer { class ProtectSanitizer extends Sanitizer {

View File

@@ -24,10 +24,8 @@ module ReflectedXss {
* a content type that does not (case-insensitively) contain the string "html". This * 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. * is to prevent us from flagging plain-text or JSON responses as vulnerable.
*/ */
class HttpResponseSink extends Sink, DataFlow::ValueNode { class HttpResponseSink extends Sink instanceof HTTP::ResponseSendArgument {
override HTTP::ResponseSendArgument astNode; HttpResponseSink() { not exists(getANonHtmlHeaderDefinition(this)) }
HttpResponseSink() { not exists(getANonHtmlHeaderDefinition(astNode)) }
} }
/** /**

View File

@@ -57,11 +57,11 @@ module RemotePropertyInjection {
* header names as properties. This case is already handled by * header names as properties. This case is already handled by
* `PropertyWriteSink`. * `PropertyWriteSink`.
*/ */
class HeaderNameSink extends Sink, DataFlow::ValueNode { class HeaderNameSink extends Sink {
HeaderNameSink() { HeaderNameSink() {
exists(HTTP::ExplicitHeaderDefinition hd | exists(HTTP::ExplicitHeaderDefinition hd |
not hd instanceof Express::SetMultipleHeaders and not hd instanceof Express::SetMultipleHeaders and
astNode = hd.getNameExpr() this = hd.getNameNode()
) )
} }

View File

@@ -33,17 +33,17 @@ module ServerSideUrlRedirect {
/** /**
* An HTTP redirect, considered as a sink for `Configuration`. * An HTTP redirect, considered as a sink for `Configuration`.
*/ */
class RedirectSink extends Sink, DataFlow::ValueNode { class RedirectSink extends Sink {
RedirectSink() { astNode = any(HTTP::RedirectInvocation redir).getUrlArgument() } RedirectSink() { this = any(HTTP::RedirectInvocation redir).getUrlArgument() }
} }
/** /**
* A definition of the HTTP "Location" header, considered as a sink for * A definition of the HTTP "Location" header, considered as a sink for
* `Configuration`. * `Configuration`.
*/ */
class LocationHeaderSink extends Sink, DataFlow::ValueNode { class LocationHeaderSink extends Sink {
LocationHeaderSink() { LocationHeaderSink() {
any(HTTP::ExplicitHeaderDefinition def).definesExplicitly("location", astNode) any(HTTP::ExplicitHeaderDefinition def).definesHeaderValue("location", this)
} }
} }

View File

@@ -28,13 +28,11 @@ module SqlInjection {
} }
/** An SQL expression passed to an API call that executes SQL. */ /** An SQL expression passed to an API call that executes SQL. */
class SqlInjectionExprSink extends Sink, DataFlow::ValueNode { class SqlInjectionExprSink extends Sink instanceof SQL::SqlString { }
override SQL::SqlString astNode;
}
/** An expression that sanitizes a value for the purposes of string based query injection. */ /** An expression that sanitizes a value for the purposes of string based query injection. */
class SanitizerExpr extends Sanitizer, DataFlow::ValueNode { class SanitizerExpr extends Sanitizer {
SanitizerExpr() { astNode = any(SQL::SqlSanitizer ss).getOutput() } SanitizerExpr() { this = any(SQL::SqlSanitizer ss).getOutput() }
} }
/** An GraphQL expression passed to an API call that executes GraphQL. */ /** An GraphQL expression passed to an API call that executes GraphQL. */

View File

@@ -32,7 +32,5 @@ module StackTraceExposure {
* An expression that can become part of an HTTP response body, viewed * An expression that can become part of an HTTP response body, viewed
* as a data flow sink for stack trace exposure vulnerabilities. * as a data flow sink for stack trace exposure vulnerabilities.
*/ */
class DefaultSink extends Sink, DataFlow::ValueNode { class DefaultSink extends Sink instanceof HTTP::ResponseBody { }
override HTTP::ResponseBody astNode;
}
} }

View File

@@ -647,12 +647,12 @@ module TaintedPath {
/** /**
* A path argument to the Express `res.render` method. * A path argument to the Express `res.render` method.
*/ */
class ExpressRenderSink extends Sink, DataFlow::ValueNode { class ExpressRenderSink extends Sink {
ExpressRenderSink() { ExpressRenderSink() {
exists(MethodCallExpr mce | exists(DataFlow::MethodCallNode mce |
Express::isResponse(mce.getReceiver()) and Express::isResponse(mce.getReceiver()) and
mce.getMethodName() = "render" and mce.getMethodName() = "render" and
astNode = mce.getArgument(0) this = mce.getArgument(0)
) )
} }
} }

View File

@@ -76,8 +76,8 @@ module TemplateObjectInjection {
predicate usesVulnerableTemplateEngine(Express::RouterDefinition router) { predicate usesVulnerableTemplateEngine(Express::RouterDefinition router) {
// option 1: `app.set("view engine", "theEngine")`. // option 1: `app.set("view engine", "theEngine")`.
// Express will load the engine automatically. // Express will load the engine automatically.
exists(MethodCallExpr call | exists(DataFlow::MethodCallNode call |
router.flowsTo(call.getReceiver()) and router.ref().getAMethodCall() = call and
call.getMethodName() = "set" and call.getMethodName() = "set" and
call.getArgument(0).getStringValue() = "view engine" and call.getArgument(0).getStringValue() = "view engine" and
call.getArgument(1).getStringValue() = getAVulnerableTemplateEngine() call.getArgument(1).getStringValue() = getAVulnerableTemplateEngine()
@@ -91,11 +91,11 @@ module TemplateObjectInjection {
DataFlow::MethodCallNode viewEngineCall DataFlow::MethodCallNode viewEngineCall
| |
// `app.engine("name", engine) // `app.engine("name", engine)
router.flowsTo(registerCall.getReceiver().asExpr()) and router.ref().getAMethodCall() = registerCall and
registerCall.getMethodName() = ["engine", "register"] and registerCall.getMethodName() = ["engine", "register"] and
engine = registerCall.getArgument(1).getALocalSource() and engine = registerCall.getArgument(1).getALocalSource() and
// app.set("view engine", "name") // app.set("view engine", "name")
router.flowsTo(viewEngineCall.getReceiver().asExpr()) and router.ref().getAMethodCall() = viewEngineCall and
viewEngineCall.getMethodName() = "set" and viewEngineCall.getMethodName() = "set" and
viewEngineCall.getArgument(0).getStringValue() = "view engine" and viewEngineCall.getArgument(0).getStringValue() = "view engine" and
// The name set by the `app.engine("name")` call matches `app.set("view engine", "name")`. // The name set by the `app.engine("name")` call matches `app.set("view engine", "name")`.

View File

@@ -31,8 +31,8 @@ module XmlBomb {
/** /**
* An access to `document.location`, considered as a flow source for XML bomb vulnerabilities. * An access to `document.location`, considered as a flow source for XML bomb vulnerabilities.
*/ */
class LocationAsSource extends Source, DataFlow::ValueNode { class LocationAsSource extends Source {
LocationAsSource() { isLocation(astNode) } LocationAsSource() { isLocationNode(this) }
} }
/** /**

View File

@@ -31,8 +31,8 @@ module Xxe {
/** /**
* An access to `document.location`, considered as a flow source for XXE vulnerabilities. * An access to `document.location`, considered as a flow source for XXE vulnerabilities.
*/ */
class LocationAsSource extends Source, DataFlow::ValueNode { class LocationAsSource extends Source {
LocationAsSource() { isLocation(astNode) } LocationAsSource() { isLocationNode(this) }
} }
/** /**

View File

@@ -42,17 +42,19 @@ predicate isABuiltinEventName(string name) {
* Holds if user code emits or broadcasts an event named `name`. * Holds if user code emits or broadcasts an event named `name`.
*/ */
predicate isAUserDefinedEventName(string name) { predicate isAUserDefinedEventName(string name) {
exists(string methodName, MethodCallExpr mce | methodName = "$emit" or methodName = "$broadcast" | exists(string methodName, DataFlow::MethodCallNode mcn |
mce.getArgument(0).mayHaveStringValue(name) and methodName = "$emit" or methodName = "$broadcast"
|
mcn.getArgument(0).mayHaveStringValue(name) and
( (
// dataflow based scope resolution // dataflow based scope resolution
mce = any(AngularJS::ScopeServiceReference scope).getAMethodCall(methodName) mcn = any(AngularJS::ScopeServiceReference scope).getAMethodCall(methodName)
or or
// heuristic scope resolution: assume parameters like `$scope` or `$rootScope` are AngularJS scope objects // 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 param.getName() = any(AngularJS::ScopeServiceReference scope).getName() and
mce.getReceiver().mayReferToParameter(param) and param.getAMethodCall() = mcn and
mce.getMethodName() = methodName mcn.getMethodName() = methodName
) )
or or
// a call in an AngularJS expression // 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 where
mce = scope.getAMethodCall("$on") and mce = scope.getAMethodCall("$on") and
mce.getArgument(0).mayHaveStringValue(eventName) and mce.getArgument(0).mayHaveStringValue(eventName) and

View File

@@ -14,7 +14,7 @@
import javascript import javascript
from AngularJS::InjectableFunction f, SimpleParameter p, string msg from AngularJS::InjectableFunction f, DataFlow::ParameterNode p, string msg
where where
p = f.asFunction().getAParameter() and p = f.asFunction().getAParameter() and
( (

View File

@@ -14,7 +14,7 @@
import javascript import javascript
from MethodCallExpr mce, AngularJS::BuiltinServiceReference service from DataFlow::MethodCallNode mce, AngularJS::BuiltinServiceReference service
where where
service.getName() = "$sceProvider" and service.getName() = "$sceProvider" and
mce = service.getAMethodCall("enabled") and mce = service.getAMethodCall("enabled") and

View File

@@ -15,7 +15,7 @@
import javascript import javascript
from AngularJS::ServiceReference compile, SimpleParameter elem, CallExpr c from AngularJS::ServiceReference compile, DataFlow::ParameterNode elem, DataFlow::CallNode c
where where
compile.getName() = "$compile" and compile.getName() = "$compile" and
elem = elem =
@@ -24,7 +24,7 @@ where
.(AngularJS::LinkFunction) .(AngularJS::LinkFunction)
.getElementParameter() and .getElementParameter() and
c = compile.getACall() 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` // don't flag $compile calls that specify a `maxPriority`
c.getNumArgument() < 3 c.getNumArgument() < 3
select c, "This call to $compile may cause double compilation of '" + elem + "'." select c, "This call to $compile may cause double compilation of '" + elem + "'."

View File

@@ -12,16 +12,17 @@
import javascript import javascript
import semmle.javascript.RestrictedLocations 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 | exists(int i, int j |
i < j and i < j and
exists(f.getDependencyDeclaration(i, name)) 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 where
isRepeatedDependency(f, name, node) and isRepeatedDependency(f, name, node) and
not count(f.asFunction().getParameterByName(name)) > 1 // avoid duplicating reports from js/duplicate-parameter-name 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

View File

@@ -23,7 +23,7 @@ predicate isResourceUrlWhitelist(
) { ) {
exists(AngularJS::ServiceReference service | exists(AngularJS::ServiceReference service |
service.getName() = "$sceDelegateProvider" and service.getName() = "$sceDelegateProvider" and
setupCall.asExpr() = service.getAMethodCall("resourceUrlWhitelist") and setupCall = service.getAMethodCall("resourceUrlWhitelist") and
list.flowsTo(setupCall.getArgument(0)) list.flowsTo(setupCall.getArgument(0))
) )
} }

View File

@@ -12,9 +12,9 @@
import javascript import javascript
import semmle.javascript.RestrictedLocations import semmle.javascript.RestrictedLocations
from AngularJS::InjectableFunction f, AstNode explicitInjection from AngularJS::InjectableFunction f, DataFlow::Node explicitInjection
where where
count(f.getAnExplicitDependencyInjection()) > 1 and count(f.getAnExplicitDependencyInjection()) > 1 and
explicitInjection = f.getAnExplicitDependencyInjection() explicitInjection = f.getAnExplicitDependencyInjection()
select f.asFunction().(FirstLineOf), "This function has $@ defined in multiple places.", select f.asFunction().getFunction().(FirstLineOf),
explicitInjection, "dependency injections" "This function has $@ defined in multiple places.", explicitInjection, "dependency injections"

View File

@@ -13,9 +13,9 @@ import javascript
import Declarations.UnusedParameter import Declarations.UnusedParameter
import semmle.javascript.RestrictedLocations import semmle.javascript.RestrictedLocations
predicate isUnusedParameter(Function f, string msg, Parameter parameter) { predicate isUnusedParameter(DataFlow::FunctionNode f, string msg, Parameter parameter) {
exists(Variable pv | exists(Variable pv |
isUnused(f, parameter, pv, _) and isUnused(f.getFunction(), parameter, pv, _) and
not isAnAccidentallyUnusedParameter(parameter) and // avoid double alerts not isAnAccidentallyUnusedParameter(parameter) and // avoid double alerts
msg = "Unused dependency " + pv.getName() + "." msg = "Unused dependency " + pv.getName() + "."
) )

View File

@@ -135,7 +135,7 @@ DataFlow::CallNode servesAPrivateFolder(string description) {
*/ */
Express::RouteSetup getAnExposingExpressSetup(string path) { Express::RouteSetup getAnExposingExpressSetup(string path) {
result.isUseCall() and 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 from DataFlow::Node node, string path
where where
node = getAnExposingExpressSetup(path).flow() node = getAnExposingExpressSetup(path)
or or
node = getAnExposingServeSetup(path) node = getAnExposingServeSetup(path)
select node, "Serves " + path + ", which can contain private information." select node, "Serves " + path + ", which can contain private information."

View File

@@ -19,7 +19,7 @@ import DataFlow::PathGraph
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where where
cfg.hasFlowPath(source, sink) and 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, select sink.getNode(), source, sink,
"Sensitive data from $@ is used in a broken or weak cryptographic algorithm.", source.getNode(), "Sensitive data from $@ is used in a broken or weak cryptographic algorithm.", source.getNode(),
source.getNode().(Source).describe() source.getNode().(Source).describe()

View File

@@ -15,13 +15,13 @@ import javascript
from from
Routing::RouteSetup setup, Routing::RouteHandler handler, HTTP::RequestInputAccess input, Routing::RouteSetup setup, Routing::RouteHandler handler, HTTP::RequestInputAccess input,
SensitiveExpr sensitive SensitiveNode sensitive
where where
setup.getOwnHttpMethod() = "GET" and setup.getOwnHttpMethod() = "GET" and
setup.getAChild+() = handler and setup.getAChild+() = handler and
input.getRouteHandler() = handler.getFunction() and input.getRouteHandler() = handler.getFunction() and
input.getKind() = "parameter" and input.getKind() = "parameter" and
input.(DataFlow::SourceNode).flowsToExpr(sensitive) and input.(DataFlow::SourceNode).flowsTo(sensitive) and
not sensitive.getClassification() = SensitiveDataClassification::id() not sensitive.getClassification() = SensitiveDataClassification::id()
select input, "$@ for GET requests uses query parameter as sensitive data.", handler, select input, "$@ for GET requests uses query parameter as sensitive data.", handler,
"Route handler" "Route handler"

View File

@@ -77,7 +77,7 @@ private module StandardPoIs {
UnpromotedRouteSetupPoI() { this = "UnpromotedRouteSetupPoI" } UnpromotedRouteSetupPoI() { this = "UnpromotedRouteSetupPoI" }
override predicate is(Node l0) { 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
} }
} }

View File

@@ -13,7 +13,7 @@ import CandidateTracking
from HTTP::RouteSetupCandidate setup from HTTP::RouteSetupCandidate setup
where where
not setup.asExpr() instanceof HTTP::RouteSetup and not setup instanceof HTTP::RouteSetup and
exists(HTTP::RouteHandlerCandidate rh | exists(HTTP::RouteHandlerCandidate rh |
track(rh, DataFlow::TypeTracker::end()).flowsTo(setup.getARouteHandlerArg()) track(rh, DataFlow::TypeTracker::end()).flowsTo(setup.getARouteHandlerArg())
) )

View File

@@ -16,7 +16,7 @@ class RouteHandlerAndSetupPoI extends ActivePoI {
RouteHandlerAndSetupPoI() { this = "RouteHandlerAndSetupPoI" } RouteHandlerAndSetupPoI() { this = "RouteHandlerAndSetupPoI" }
override predicate is(Node l0, Node l1, string t1) { 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" } RouteSetupAndRouterAndRouteHandlerPoI() { this = "RouteSetupAndRouterAndRouteHandlerPoI" }
override predicate is(Node l0, Node l1, string t1, Node l2, string t2) { 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() = l1 and
t1 = "router" and t1 = "router" and
l0.asExpr().(Express::RouteSetup).getARouteHandler() = l2 and l0.(Express::RouteSetup).getARouteHandler() = l2 and
t2 = "routehandler" t2 = "routehandler"
} }
} }

View File

@@ -20,4 +20,4 @@ query predicate processTermination(NodeJSLib::ProcessTermination term) { any() }
query predicate sensitiveAction(SensitiveAction ac) { any() } query predicate sensitiveAction(SensitiveAction ac) { any() }
query predicate sensitiveExpr(SensitiveExpr e) { any() } query predicate sensitiveExpr(SensitiveNode e) { any() }

View File

@@ -1,5 +1,5 @@
import javascript import javascript
from AngularJS::ScopeServiceReference s, MethodCallExpr mce from AngularJS::ScopeServiceReference s, DataFlow::MethodCallNode mce
where mce = s.getAMethodCall(_) where mce = s.getAMethodCall(_)
select mce select mce

View File

@@ -1,6 +1,6 @@
import javascript import javascript
private import AngularJS 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) where nd = f.getCustomServiceDependency(p)
select p.getName(), nd select p.getName(), nd

View File

@@ -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:4:41:4:45 | scope |
| isolate scope for directive1 | scope-access.js:5:17:5:21 | 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 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:12:34:12:39 | $scope |
| isolate scope for directive2 | scope-access.js:13:17:13:22 | $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 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:20:39:20:44 | $scope |
| isolate scope for directive3 | scope-access.js:21:17:21:22 | $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 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:28:45:28:45 | a |
| isolate scope for directive4 | scope-access.js:29:17:29:17 | 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 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:37:17:37:20 | this |
| isolate scope for directive5 | scope-access.js:39:20:39:21 | {} | | 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:46:23:46:26 | this |
| isolate scope for directive6 | scope-access.js:48:20:48:21 | {} | | 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-5.js:11:12:13:5 | { // Sc ... y\\n } |
| isolate scope for myCustomer | dev-guide-6.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 <directive7>...</> | scope-access.js:54:34:54:39 | $scope | | scope for <directive7>...</> | scope-access.js:54:34:54:39 | $scope |
| scope for <directive7>...</> | scope-access.js:54:34:54:39 | $scope |
| scope for <directive7>...</> | scope-access.js:55:17:55:22 | $scope | | scope for <directive7>...</> | scope-access.js:55:17:55:22 | $scope |
| scope for <div>...</> | dev-guide-1.js:4:49:4:54 | $scope | | scope for <div>...</> | dev-guide-1.js:4:49:4:54 | $scope |
| scope for <div>...</> | dev-guide-1.js:4:49:4:54 | $scope |
| scope for <div>...</> | dev-guide-1.js:4:49:4:54 | $scope |
| scope for <div>...</> | dev-guide-1.js:5:3:5:8 | $scope | | scope for <div>...</> | dev-guide-1.js:5:3:5:8 | $scope |
| scope for <div>...</> | dev-guide-1.js:7:3:7:8 | $scope | | scope for <div>...</> | dev-guide-1.js:7:3:7:8 | $scope |
| scope for <div>...</> | dev-guide-1.js:7:21:7:20 | $scope |
| scope for <div>...</> | dev-guide-1.js:8:5:8:10 | $scope | | scope for <div>...</> | dev-guide-1.js:8:5:8:10 | $scope |
| scope for <div>...</> | dev-guide-1.js:8:34:8:39 | $scope | | scope for <div>...</> | dev-guide-1.js:8:34:8:39 | $scope |
| scope for <div>...</> | dev-guide-2.js:4:66:4:71 | $scope | | scope for <div>...</> | dev-guide-2.js:4:66:4:71 | $scope |
| scope for <div>...</> | dev-guide-2.js:4:66:4:71 | $scope |
| scope for <div>...</> | dev-guide-2.js:5:3:5:8 | $scope | | scope for <div>...</> | dev-guide-2.js:5:3:5:8 | $scope |
| scope for <div>...</> | dev-guide-2.js:8:51:8:56 | $scope | | scope for <div>...</> | dev-guide-2.js:8:51:8:56 | $scope |
| scope for <div>...</> | dev-guide-2.js:8:51:8:56 | $scope |
| scope for <div>...</> | dev-guide-2.js:9:3:9:8 | $scope | | scope for <div>...</> | dev-guide-2.js:9:3:9:8 | $scope |
| scope for <div>...</> | dev-guide-3.js:4:52:4:57 | $scope | | scope for <div>...</> | dev-guide-3.js:4:52:4:57 | $scope |
| scope for <div>...</> | dev-guide-3.js:4:52:4:57 | $scope |
| scope for <div>...</> | dev-guide-3.js:4:52:4:57 | $scope |
| scope for <div>...</> | dev-guide-3.js:5:3:5:8 | $scope | | scope for <div>...</> | dev-guide-3.js:5:3:5:8 | $scope |
| scope for <div>...</> | dev-guide-3.js:6:3:6:8 | $scope | | scope for <div>...</> | dev-guide-3.js:6:3:6:8 | $scope |
| scope for <div>...</> | dev-guide-3.js:6:25:6:24 | $scope |
| scope for <div>...</> | dev-guide-3.js:7:5:7:10 | $scope | | scope for <div>...</> | dev-guide-3.js:7:5:7:10 | $scope |
| scope for <div>...</> | dev-guide-4.js:4:52:4:57 | $scope | | scope for <div>...</> | dev-guide-4.js:4:52:4:57 | $scope |
| scope for <div>...</> | dev-guide-4.js:4:52:4:57 | $scope |
| scope for <div>...</> | dev-guide-4.js:5:3:5:8 | $scope | | scope for <div>...</> | dev-guide-4.js:5:3:5:8 | $scope |
| scope for <div>...</> | dev-guide-4.js:10:51:10:56 | $scope | | scope for <div>...</> | dev-guide-4.js:10:51:10:56 | $scope |
| scope for <div>...</> | dev-guide-4.js:10:51:10:56 | $scope |
| scope for <div>...</> | dev-guide-4.js:11:3:11:8 | $scope | | scope for <div>...</> | dev-guide-4.js:11:3:11:8 | $scope |
| scope for <div>...</> | dev-guide-5.js:4:47:4:52 | $scope | | scope for <div>...</> | dev-guide-5.js:4:47:4:52 | $scope |
| scope for <div>...</> | dev-guide-5.js:4:47:4:52 | $scope | | scope for <div>...</> | dev-guide-5.js:4:47:4:52 | $scope |
| scope for <div>...</> | dev-guide-5.js:4:47:4:52 | $scope |
| scope for <div>...</> | dev-guide-5.js:4:47:4:52 | $scope |
| scope for <div>...</> | dev-guide-5.js:5:3:5:8 | $scope | | scope for <div>...</> | dev-guide-5.js:5:3:5:8 | $scope |
| scope for <div>...</> | dev-guide-5.js:5:3:5:8 | $scope | | scope for <div>...</> | dev-guide-5.js:5:3:5:8 | $scope |
| scope for <div>...</> | dev-guide-5.js:6:3:6:8 | $scope | | scope for <div>...</> | dev-guide-5.js:6:3:6:8 | $scope |
| scope for <div>...</> | dev-guide-5.js:6:3:6:8 | $scope | | scope for <div>...</> | dev-guide-5.js:6:3:6:8 | $scope |
| scope for <div>...</> | dev-guide-6.js:4:47:4:52 | $scope | | scope for <div>...</> | dev-guide-6.js:4:47:4:52 | $scope |
| scope for <div>...</> | dev-guide-6.js:4:47:4:52 | $scope | | scope for <div>...</> | dev-guide-6.js:4:47:4:52 | $scope |
| scope for <div>...</> | dev-guide-6.js:4:47:4:52 | $scope |
| scope for <div>...</> | dev-guide-6.js:4:47:4:52 | $scope |
| scope for <div>...</> | dev-guide-6.js:5:3:5:8 | $scope | | scope for <div>...</> | dev-guide-6.js:5:3:5:8 | $scope |
| scope for <div>...</> | dev-guide-6.js:5:3:5:8 | $scope | | scope for <div>...</> | dev-guide-6.js:5:3:5:8 | $scope |
| scope for <div>...</> | dev-guide-6.js:6:3:6:8 | $scope | | scope for <div>...</> | dev-guide-6.js:6:3:6:8 | $scope |
| scope for <div>...</> | dev-guide-6.js:6:3:6:8 | $scope | | scope for <div>...</> | dev-guide-6.js:6:3:6:8 | $scope |
| scope for <elementthatusescontroller1>...</> | scope-access.js:59:52:59:57 | $scope | | scope for <elementthatusescontroller1>...</> | scope-access.js:59:52:59:57 | $scope |
| scope for <elementthatusescontroller1>...</> | scope-access.js:59:52:59:57 | $scope |
| scope for <elementthatusescontroller1>...</> | scope-access.js:60:9:60:14 | $scope | | scope for <elementthatusescontroller1>...</> | scope-access.js:60:9:60:14 | $scope |
| scope for <li>...</> | dev-guide-3.js:4:52:4:57 | $scope | | scope for <li>...</> | dev-guide-3.js:4:52:4:57 | $scope |
| scope for <li>...</> | dev-guide-3.js:4:52:4:57 | $scope | | scope for <li>...</> | dev-guide-3.js:4:52:4:57 | $scope |
| scope for <li>...</> | dev-guide-3.js:4:52:4:57 | $scope |
| scope for <li>...</> | dev-guide-3.js:4:52:4:57 | $scope |
| scope for <li>...</> | dev-guide-3.js:4:52:4:57 | $scope |
| scope for <li>...</> | dev-guide-3.js:4:52:4:57 | $scope |
| scope for <li>...</> | dev-guide-3.js:5:3:5:8 | $scope | | scope for <li>...</> | dev-guide-3.js:5:3:5:8 | $scope |
| scope for <li>...</> | dev-guide-3.js:5:3:5:8 | $scope | | scope for <li>...</> | dev-guide-3.js:5:3:5:8 | $scope |
| scope for <li>...</> | dev-guide-3.js:6:3:6:8 | $scope | | scope for <li>...</> | dev-guide-3.js:6:3:6:8 | $scope |
| scope for <li>...</> | dev-guide-3.js:6:3:6:8 | $scope | | scope for <li>...</> | dev-guide-3.js:6:3:6:8 | $scope |
| scope for <li>...</> | dev-guide-3.js:6:25:6:24 | $scope |
| scope for <li>...</> | dev-guide-3.js:6:25:6:24 | $scope |
| scope for <li>...</> | dev-guide-3.js:7:5:7:10 | $scope | | scope for <li>...</> | dev-guide-3.js:7:5:7:10 | $scope |
| scope for <li>...</> | dev-guide-3.js:7:5:7:10 | $scope | | scope for <li>...</> | 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: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: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: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:5:8:10 | $scope |
| scope in dev-guide-1.html | dev-guide-1.js:8:34:8:39 | $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: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: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:8:51:8:56 | $scope |
| scope in dev-guide-2.html | dev-guide-2.js:9:3:9:8 | $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: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: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: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-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: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: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:10:51:10:56 | $scope |
| scope in dev-guide-4.html | dev-guide-4.js:11:3:11:8 | $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: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: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-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: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:5:3:5:8 | $scope |
| scope in dev-guide-5.html | dev-guide-6.js:6:3:6: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: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: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-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: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:5:3:5:8 | $scope |
| scope in dev-guide-6.html | dev-guide-6.js:6:3:6: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: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: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:59:52:59:57 | $scope |
| scope in scope-access.html | scope-access.js:60:9:60:14 | $scope | | scope in scope-access.html | scope-access.js:60:9:60:14 | $scope |

View File

@@ -1,5 +1,7 @@
import javascript import javascript
query predicate test_HeaderDefinition_getNameExpr(HTTP::ExplicitHeaderDefinition hd, Expr res) { query predicate test_HeaderDefinition_getNameExpr(
hd.getRouteHandler() instanceof Express::RouteHandler and res = hd.getNameExpr() HTTP::ExplicitHeaderDefinition hd, DataFlow::Node res
) {
hd.getRouteHandler() instanceof Express::RouteHandler and res = hd.getNameNode()
} }

View File

@@ -1,9 +1,9 @@
import javascript 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() res = e.getRouteHandler()
} }
query predicate test_RequestExprStandalone(Express::RequestExpr e) { query predicate test_RequestExprStandalone(Express::RequestNode e) {
not exists(e.getRouteHandler()) not exists(e.getRouteHandler())
} }

View File

@@ -1,5 +1,5 @@
import javascript 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() res = e.getRouteHandler()
} }

View File

@@ -1,5 +0,0 @@
import javascript
query predicate test_RouteExpr(Express::RouteExpr e, Express::RouterDefinition res) {
res = e.getRouter()
}

View File

@@ -1,5 +1,7 @@
import javascript 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() res0 = rh.getRequestParameter() and res1 = rh.getResponseParameter()
} }

View File

@@ -1,7 +1,7 @@
import javascript import javascript
query predicate test_RouteHandlerExpr( 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 (if rhe.isLastHandler() then isLast = true else isLast = false) and
res0 = rhe.getSetup() res0 = rhe.getSetup()

View File

@@ -1,7 +1,7 @@
import javascript import javascript
query predicate test_RouteHandlerExpr_getAMatchingAncestor( query predicate test_RouteHandlerExpr_getAMatchingAncestor(
Express::RouteHandlerExpr expr, Express::RouteHandlerExpr res Express::RouteHandlerNode expr, Express::RouteHandlerNode res
) { ) {
res = expr.getAMatchingAncestor() res = expr.getAMatchingAncestor()
} }

View File

@@ -1,7 +1,7 @@
import javascript import javascript
query predicate test_RouteHandlerExpr_getAsSubRouter( query predicate test_RouteHandlerExpr_getAsSubRouter(
Express::RouteHandlerExpr expr, Express::RouterDefinition res Express::RouteHandlerNode expr, Express::RouterDefinition res
) { ) {
res = expr.getAsSubRouter() res = expr.getAsSubRouter()
} }

View File

@@ -1,7 +1,7 @@
import javascript import javascript
query predicate test_RouteHandlerExpr_getBody( query predicate test_RouteHandlerExpr_getBody(
Express::RouteHandlerExpr rhe, Express::RouteHandler res Express::RouteHandlerNode rhe, Express::RouteHandler res
) { ) {
res = rhe.getBody() res = rhe.getBody()
} }

View File

@@ -1,7 +1,7 @@
import javascript import javascript
query predicate test_RouteHandlerExpr_getNextMiddleware( query predicate test_RouteHandlerExpr_getNextMiddleware(
Express::RouteHandlerExpr expr, Express::RouteHandlerExpr res Express::RouteHandlerNode expr, Express::RouteHandlerNode res
) { ) {
res = expr.getNextMiddleware() res = expr.getNextMiddleware()
} }

View File

@@ -1,7 +1,7 @@
import javascript import javascript
query predicate test_RouteHandlerExpr_getPreviousMiddleware( query predicate test_RouteHandlerExpr_getPreviousMiddleware(
Express::RouteHandlerExpr expr, Express::RouteHandlerExpr res Express::RouteHandlerNode expr, Express::RouteHandlerNode res
) { ) {
res = expr.getPreviousMiddleware() res = expr.getPreviousMiddleware()
} }

View File

@@ -1,5 +1,5 @@
import javascript 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() res = rh.getARequestBodyAccess()
} }

View File

@@ -1,5 +1,5 @@
import javascript import javascript
query predicate test_RouteHandler_getARequestExpr(Express::RouteHandler rh, HTTP::RequestExpr res) { query predicate test_RouteHandler_getARequestExpr(Express::RouteHandler rh, HTTP::RequestNode res) {
res = rh.getARequestExpr() res = rh.getARequestNode()
} }

View File

@@ -1,5 +1,5 @@
import javascript import javascript
query predicate test_RouteHandler_getAResponseExpr(Express::RouteHandler rh, HTTP::ResponseExpr res) { query predicate test_RouteHandler_getAResponseExpr(Express::RouteHandler rh, HTTP::ResponseNode res) {
res = rh.getAResponseExpr() res = rh.getAResponseNode()
} }

View File

@@ -1,6 +1,6 @@
import javascript 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 (if rs.isUseCall() then isUseCall = true else isUseCall = false) and
res0 = rs.getServer() res0 = rs.getServer()
} }

View File

@@ -1,5 +1,5 @@
import javascript import javascript
query predicate test_RouteSetup_getARouteHandlerExpr(Express::RouteSetup r, Expr res) { query predicate test_RouteSetup_getARouteHandlerExpr(Express::RouteSetup r, DataFlow::Node res) {
res = r.getARouteHandlerExpr() res = r.getARouteHandlerNode()
} }

View File

@@ -1,5 +1,5 @@
import javascript import javascript
query predicate test_RouteSetup_getLastRouteHandlerExpr(Express::RouteSetup r, Expr res) { query predicate test_RouteSetup_getLastRouteHandlerExpr(Express::RouteSetup r, DataFlow::Node res) {
res = r.getLastRouteHandlerExpr() res = r.getLastRouteHandlerNode()
} }

Some files were not shown because too many files have changed in this diff Show More