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
n instanceof CryptographicKey and reason instanceof CryptographicKeyReason
or
any(CryptographicOperation op).getInput().flow() = n and
any(CryptographicOperation op).getInput() = n and
reason instanceof CryptographicOperationFlowReason
or
exists(DataFlow::CallNode call | n = call.getAnArgument() |

View File

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

View File

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

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`.
*/
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.

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`.
*/
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.

View File

@@ -472,6 +472,12 @@ class FunctionNode extends DataFlow::ValueNode, DataFlow::SourceNode {
/** Gets a parameter of this function. */
ParameterNode getAParameter() { result = this.getParameter(_) }
/** Gets the parameter named `name` of this function, if any. */
DataFlow::ParameterNode getParameterByName(string name) {
result = this.getAParameter() and
result.getName() = name
}
/** Gets the number of parameters declared on this function. */
int getNumParameter() { result = count(astNode.getAParameter()) }
@@ -556,6 +562,14 @@ class ObjectLiteralNode extends DataFlow::ValueNode, DataFlow::SourceNode {
DataFlow::FunctionNode getPropertySetter(string name) {
result = astNode.getPropertyByName(name).(PropertySetter).getInit().flow()
}
/** Gets the value of a computed property name of this object literal, such as `x` in `{[x]: 1}` */
DataFlow::Node getAComputedPropertyName() {
exists(Property prop | prop = astNode.getAProperty() |
prop.isComputed() and
result = prop.getNameExpr().flow()
)
}
}
/**

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -10,10 +10,10 @@ module Connect {
/**
* An expression that creates a new Connect server.
*/
class ServerDefinition extends HTTP::Servers::StandardServerDefinition, CallExpr {
class ServerDefinition extends HTTP::Servers::StandardServerDefinition, DataFlow::CallNode {
ServerDefinition() {
// `app = connect()`
this = DataFlow::moduleImport("connect").getAnInvocation().asExpr()
this = DataFlow::moduleImport("connect").getAnInvocation()
}
}
@@ -30,43 +30,45 @@ module Connect {
*
* `kind` is one of: "error", "request", "response", "next".
*/
abstract Parameter getRouteHandlerParameter(string kind);
abstract DataFlow::ParameterNode getRouteHandlerParameter(string kind);
/**
* Gets the parameter of the route handler that contains the request object.
*/
override Parameter getRequestParameter() { result = getRouteHandlerParameter("request") }
override DataFlow::ParameterNode getRequestParameter() {
result = getRouteHandlerParameter("request")
}
/**
* Gets the parameter of the route handler that contains the response object.
*/
override Parameter getResponseParameter() { result = getRouteHandlerParameter("response") }
override DataFlow::ParameterNode getResponseParameter() {
result = getRouteHandlerParameter("response")
}
}
/**
* A Connect route handler installed by a route setup.
*/
class StandardRouteHandler extends RouteHandler {
override Function astNode;
class StandardRouteHandler extends RouteHandler, DataFlow::FunctionNode {
StandardRouteHandler() { this = any(RouteSetup setup).getARouteHandler() }
override Parameter getRouteHandlerParameter(string kind) {
result = getRouteHandlerParameter(astNode, kind)
override DataFlow::ParameterNode getRouteHandlerParameter(string kind) {
result = getRouteHandlerParameter(this, kind)
}
}
/**
* A call to a Connect method that sets up a route.
*/
class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup {
class RouteSetup extends DataFlow::MethodCallNode, HTTP::Servers::StandardRouteSetup {
ServerDefinition server;
RouteSetup() {
getMethodName() = "use" and
(
// app.use(fun)
server.flowsTo(getReceiver())
server.ref().getAMethodCall() = this
or
// app.use(...).use(fun)
this.getReceiver().(RouteSetup).getServer() = server
@@ -79,24 +81,32 @@ module Connect {
private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) {
t.start() and
result = getARouteHandlerExpr().flow().getALocalSource()
result = getARouteHandlerNode().getALocalSource()
or
exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t))
}
override 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>)`. */
class Credentials extends CredentialsExpr {
class Credentials extends CredentialsNode {
string kind;
Credentials() {
exists(CallExpr call |
call = DataFlow::moduleImport("basic-auth-connect").getAnInvocation().asExpr() and
exists(DataFlow::CallNode call |
call = DataFlow::moduleImport("basic-auth-connect").getAnInvocation() and
call.getNumArgument() = 2
|
this = call.getArgument(0) and kind = "user name"
@@ -108,22 +118,24 @@ module Connect {
override string getCredentialsKind() { result = kind }
}
class RequestExpr = NodeJSLib::RequestExpr;
deprecated class RequestExpr = NodeJSLib::RequestExpr;
class RequestNode = NodeJSLib::RequestNode;
/**
* An access to a user-controlled Connect request input.
*/
private class RequestInputAccess extends HTTP::RequestInputAccess {
RequestExpr request;
private class RequestInputAccess extends HTTP::RequestInputAccess instanceof DataFlow::MethodCallNode {
RequestNode request;
string kind;
RequestInputAccess() {
request.getRouteHandler() instanceof StandardRouteHandler and
exists(PropAccess cookies |
exists(DataFlow::PropRead cookies |
// `req.cookies.get(<name>)`
kind = "cookie" 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.
*/
private predicate matchesSignature(Function function, RouteHandlerSignature sig) {
private predicate matchesSignature(DataFlow::FunctionNode function, RouteHandlerSignature sig) {
function.getNumParameter() = sig.getArity() and
function.getParameter(sig.getParameterIndex("request")).getName() = ["req", "request"] and
function.getParameter(sig.getParameterIndex("response")).getName() = ["res", "response"] and
@@ -71,8 +71,8 @@ module ConnectExpressShared {
* so the caller should restrict the function accordingly.
*/
pragma[inline]
private Parameter getRouteHandlerParameter(
Function routeHandler, RouteHandlerSignature sig, string kind
private DataFlow::ParameterNode getRouteHandlerParameter(
DataFlow::FunctionNode routeHandler, RouteHandlerSignature sig, string kind
) {
result = routeHandler.getParameter(sig.getParameterIndex(kind))
}
@@ -83,7 +83,9 @@ module ConnectExpressShared {
* `kind` is one of: "error", "request", "response", "next".
*/
pragma[inline]
Parameter getRouteParameterHandlerParameter(Function routeHandler, string kind) {
DataFlow::ParameterNode getRouteParameterHandlerParameter(
DataFlow::FunctionNode routeHandler, string kind
) {
result =
getRouteHandlerParameter(routeHandler, RouteHandlerSignature::requestResponseNextParameter(),
kind)
@@ -95,7 +97,7 @@ module ConnectExpressShared {
* `kind` is one of: "error", "request", "response", "next".
*/
pragma[inline]
Parameter getRouteHandlerParameter(Function routeHandler, string kind) {
DataFlow::ParameterNode getRouteHandlerParameter(DataFlow::FunctionNode routeHandler, string kind) {
if routeHandler.getNumParameter() = 4
then
// For arity 4 there is ambiguity between (err, req, res, next) and (req, res, next, param)
@@ -115,7 +117,7 @@ module ConnectExpressShared {
*/
class RouteHandlerCandidate extends HTTP::RouteHandlerCandidate {
RouteHandlerCandidate() {
matchesSignature(astNode, _) and
matchesSignature(this, _) and
not (
// heuristic: not a class method (the server invokes this with a function call)
astNode = any(MethodDefinition def).getBody()

View File

@@ -76,7 +76,7 @@ private predicate canHaveSensitiveCookie(DataFlow::Node node) {
HeuristicNames::nameIndicatesSensitiveData([s, getCookieName(s)], _)
)
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).
*/
private class InsecureExpressCookieResponse extends CookieWrites::CookieWrite,
DataFlow::MethodCallNode {
InsecureExpressCookieResponse() { this.asExpr() instanceof Express::SetCookie }
private class InsecureExpressCookieResponse extends CookieWrites::CookieWrite instanceof Express::SetCookie {
override predicate isSecure() {
// A cookie is secure if there are cookie options with the `secure` flag set to `true`.
// The default is `false`.
exists(DataFlow::Node value | value = this.getOptionArgument(2, CookieWrites::secure()) |
exists(DataFlow::Node value | value = super.getOptionArgument(2, CookieWrites::secure()) |
not value.mayHaveBooleanValue(false) // anything but `false` is accepted as being maybe true
)
}
override predicate isSensitive() { canHaveSensitiveCookie(this.getArgument(0)) }
override predicate isSensitive() { canHaveSensitiveCookie(super.getArgument(0)) }
override predicate isHttpOnly() {
// A cookie is httpOnly if there are cookie options with the `httpOnly` flag set to `true`.
// The default is `false`.
exists(DataFlow::Node value | value = this.getOptionArgument(2, CookieWrites::httpOnly()) |
exists(DataFlow::Node value | value = super.getOptionArgument(2, CookieWrites::httpOnly()) |
not value.mayHaveBooleanValue(false) // anything but `false` is accepted as being maybe true
)
}
override string getSameSite() {
result = getSameSiteValue(this.getOptionArgument(2, "sameSite"))
result = getSameSiteValue(super.getOptionArgument(2, "sameSite"))
}
}
@@ -372,10 +369,10 @@ private class HttpCookieWrite extends CookieWrites::CookieWrite {
HttpCookieWrite() {
exists(HTTP::CookieDefinition setCookie |
this.asExpr() = setCookie.getHeaderArgument() and
this = setCookie.getHeaderArgument() and
not this instanceof DataFlow::ArrayCreationNode
or
this = setCookie.getHeaderArgument().flow().(DataFlow::ArrayCreationNode).getAnElement()
this = setCookie.getHeaderArgument().(DataFlow::ArrayCreationNode).getAnElement()
) and
header =
[

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@@ -43,7 +43,7 @@ module Knex {
/** A SQL string passed to a raw Knex method. */
private class RawKnexSqlString extends SQL::SqlString {
RawKnexSqlString() { this = any(RawKnexCall call).getArgument(0).asExpr() }
RawKnexSqlString() { this = any(RawKnexCall call).getArgument(0) }
}
/** A call that triggers a SQL query submission by calling then/stream/asCallback. */

View File

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

View File

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

View File

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

View File

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

View File

@@ -56,7 +56,7 @@ module NestJS {
*/
predicate isReturnValueReflected() {
getAFunctionDecorator(this) = nestjs().getMember(["Get", "Post"]).getACall() and
not hasRedirectDecorator() and
not this.hasRedirectDecorator() and
not getAFunctionDecorator(this) = nestjs().getMember("Render").getACall()
}
@@ -93,7 +93,7 @@ module NestJS {
NestJSRequestInput() {
decoratorName =
["Query", "Param", "Headers", "Body", "HostParam", "UploadedFile", "UploadedFiles"] and
decorator = getADecorator() and
decorator = this.getADecorator() and
decorator = nestjs().getMember(decoratorName).getACall()
}
@@ -105,7 +105,7 @@ module NestJS {
/** Gets a pipe applied to this parameter, not including global pipes. */
DataFlow::Node getAPipe() {
result = getNestRouteHandler().getAPipe()
result = this.getNestRouteHandler().getAPipe()
or
result = decorator.getArgument(1)
or
@@ -132,7 +132,7 @@ module NestJS {
hasSanitizingPipe(this, false)
or
hasSanitizingPipe(this, true) and
isSanitizingType(getParameter().getType().unfold())
isSanitizingType(this.getParameter().getType().unfold())
}
}
@@ -240,14 +240,14 @@ module NestJS {
)
}
DataFlow::FunctionNode getTransformFunction() { result = getInstanceMethod("transform") }
DataFlow::FunctionNode getTransformFunction() { result = this.getInstanceMethod("transform") }
DataFlow::ParameterNode getInputData() { result = getTransformFunction().getParameter(0) }
DataFlow::ParameterNode getInputData() { result = this.getTransformFunction().getParameter(0) }
DataFlow::Node getOutputData() { result = getTransformFunction().getReturnNode() }
DataFlow::Node getOutputData() { result = this.getTransformFunction().getReturnNode() }
NestJSRequestInput getAnAffectedParameter() {
[getAnInstanceReference(), getAClassReference()].flowsTo(result.getAPipe())
[this.getAnInstanceReference(), this.getAClassReference()].flowsTo(result.getAPipe())
}
}
@@ -297,16 +297,16 @@ module NestJS {
private class NestJSRequestInputAsRequestInputAccess extends NestJSRequestInput,
HTTP::RequestInputAccess {
NestJSRequestInputAsRequestInputAccess() {
not isSanitizedByPipe() and
not this.isSanitizedByPipe() and
not this = any(CustomPipeClass cls).getAnAffectedParameter()
}
override HTTP::RouteHandler getRouteHandler() { result = getNestRouteHandler() }
override HTTP::RouteHandler getRouteHandler() { result = this.getNestRouteHandler() }
override string getKind() { result = getInputKind() }
override string getKind() { result = this.getInputKind() }
override predicate isUserControlledObject() {
not exists(getAPipe()) and // value is not transformed by a pipe
not exists(this.getAPipe()) and // value is not transformed by a pipe
(
decorator.getNumArgument() = 0
or
@@ -349,10 +349,10 @@ module NestJS {
ReturnValueAsResponseSend() {
handler.isReturnValueReflected() and
this = handler.getAReturn().asExpr() and
this = handler.getAReturn() and
// Only returned strings are sinks
not exists(Type type |
type = getType() and
type = this.asExpr().getType() and
not isStringType(type.unfold())
)
}
@@ -389,15 +389,15 @@ module NestJS {
CustomParameterDecorator() { this = nestjs().getMember("createParamDecorator").getACall() }
/** Gets the `context` parameter. */
API::Node getExecutionContext() { result = getParameter(0).getParameter(1) }
API::Node getExecutionContext() { result = this.getParameter(0).getParameter(1) }
/** Gets a parameter with this decorator applied. */
DataFlow::ParameterNode getADecoratedParameter() {
result.getADecorator() = getReturn().getReturn().getAValueReachableFromSource()
result.getADecorator() = this.getReturn().getReturn().getAValueReachableFromSource()
}
/** Gets a value returned by the decorator's callback, which becomes the value of the decorated parameter. */
DataFlow::Node getResult() { result = getParameter(0).getReturn().asSink() }
DataFlow::Node getResult() { result = this.getParameter(0).getReturn().asSink() }
}
/**

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -21,14 +21,28 @@ class DomGlobalVariable extends GlobalVariable {
/** DEPRECATED: Alias for DomGlobalVariable */
deprecated class DOMGlobalVariable = DomGlobalVariable;
/** Holds if `e` could hold a value that comes from the DOM. */
predicate isDomValue(Expr e) { DOM::domValueRef().flowsToExpr(e) }
/**
* DEPRECATED: Use `isDomNode` instead.
* Holds if `e` could hold a value that comes from the DOM.
*/
deprecated predicate isDomValue(Expr e) { isDomNode(e.flow()) }
/**
* Holds if `e` could hold a value that comes from the DOM.
*/
predicate isDomNode(DataFlow::Node e) { DOM::domValueRef().flowsTo(e) }
/**
* DEPRECATED: Use `isLocationNode` instead.
* Holds if `e` could refer to the `location` property of a DOM node.
*/
deprecated predicate isLocation(Expr e) { isLocationNode(e.flow()) }
/** Holds if `e` could refer to the `location` property of a DOM node. */
predicate isLocation(Expr e) {
e = DOM::domValueRef().getAPropertyReference("location").asExpr()
predicate isLocationNode(DataFlow::Node e) {
e = DOM::domValueRef().getAPropertyReference("location")
or
e.accessesGlobal("location")
e = DataFlow::globalVarRef("location")
}
/**
@@ -53,15 +67,52 @@ deprecated predicate isDocumentUrl(Expr e) { e.flow() = DOM::locationSource() }
deprecated predicate isDocumentURL = isDocumentUrl/1;
/**
* DEPRECATED. In most cases, a sanitizer based on this predicate can be removed, as
* taint tracking no longer step through the properties of the location object by default.
*
* Holds if `pacc` accesses a part of `document.location` that is
* not considered user-controlled, that is, anything except
* `href`, `hash` and `search`.
*/
deprecated predicate isSafeLocationProperty(PropAccess pacc) {
exists(string prop | pacc = DOM::locationRef().getAPropertyRead(prop).asExpr() |
prop != "href" and prop != "hash" and prop != "search"
)
}
/**
* DEPRECATED: Use `DomMethodCallNode` instead.
* A call to a DOM method.
*/
class DomMethodCallExpr extends MethodCallExpr {
DomMethodCallExpr() { isDomValue(this.getReceiver()) }
deprecated class DomMethodCallExpr extends MethodCallExpr {
DomMethodCallNode node;
DomMethodCallExpr() { this.flow() = node }
/** Holds if `arg` is an argument that is interpreted as HTML. */
deprecated predicate interpretsArgumentsAsHtml(Expr arg) {
node.interpretsArgumentsAsHtml(arg.flow())
}
/** Holds if `arg` is an argument that is used as an URL. */
deprecated predicate interpretsArgumentsAsURL(Expr arg) {
node.interpretsArgumentsAsURL(arg.flow())
}
/** DEPRECATED: Alias for interpretsArgumentsAsHtml */
deprecated predicate interpretsArgumentsAsHTML(Expr arg) { this.interpretsArgumentsAsHtml(arg) }
}
/**
* A call to a DOM method.
*/
class DomMethodCallNode extends DataFlow::MethodCallNode {
DomMethodCallNode() { isDomNode(this.getReceiver()) }
/**
* Holds if `arg` is an argument that is interpreted as HTML.
*/
predicate interpretsArgumentsAsHtml(Expr arg) {
predicate interpretsArgumentsAsHtml(DataFlow::Node arg) {
exists(int argPos, string name |
arg = this.getArgument(argPos) and
name = this.getMethodName()
@@ -86,7 +137,7 @@ class DomMethodCallExpr extends MethodCallExpr {
/**
* Holds if `arg` is an argument that is used as an URL.
*/
predicate interpretsArgumentsAsUrl(Expr arg) {
predicate interpretsArgumentsAsUrl(DataFlow::Node arg) {
exists(int argPos, string name |
arg = this.getArgument(argPos) and
name = this.getMethodName()
@@ -104,56 +155,84 @@ class DomMethodCallExpr extends MethodCallExpr {
}
/** DEPRECATED: Alias for interpretsArgumentsAsUrl */
deprecated predicate interpretsArgumentsAsURL(Expr arg) { this.interpretsArgumentsAsUrl(arg) }
deprecated predicate interpretsArgumentsAsURL(DataFlow::Node arg) {
this.interpretsArgumentsAsUrl(arg)
}
/** DEPRECATED: Alias for interpretsArgumentsAsHtml */
deprecated predicate interpretsArgumentsAsHTML(Expr arg) { this.interpretsArgumentsAsHtml(arg) }
deprecated predicate interpretsArgumentsAsHTML(DataFlow::Node arg) {
this.interpretsArgumentsAsHtml(arg)
}
}
/**
* DEPRECATED: Use `DomPropertyWrite` instead.
* An assignment to a property of a DOM object.
*/
class DomPropWriteNode extends Assignment {
PropAccess lhs;
deprecated class DomPropWriteNode extends Assignment {
DomPropertyWrite node;
DomPropWriteNode() {
lhs = this.getLhs() and
isDomValue(lhs.getBase())
}
DomPropWriteNode() { this.flow() = node }
/**
* Holds if the assigned value is interpreted as HTML.
*/
predicate interpretsValueAsHtml() {
lhs.getPropertyName() = "innerHTML" or
lhs.getPropertyName() = "outerHTML"
}
predicate interpretsValueAsHtml() { node.interpretsValueAsHtml() }
/** DEPRECATED: Alias for interpretsValueAsHtml */
deprecated predicate interpretsValueAsHTML() { this.interpretsValueAsHtml() }
/**
* Holds if the assigned value is interpreted as JavaScript via javascript: protocol.
*/
predicate interpretsValueAsJavaScriptUrl() { node.interpretsValueAsJavaScriptUrl() }
}
/**
* An assignment to a property of a DOM object.
*/
class DomPropertyWrite extends DataFlow::Node instanceof DataFlow::PropWrite {
DomPropertyWrite() { isDomNode(super.getBase()) }
/**
* Holds if the assigned value is interpreted as HTML.
*/
predicate interpretsValueAsHtml() {
super.getPropertyName() = "innerHTML" or
super.getPropertyName() = "outerHTML"
}
/**
* Holds if the assigned value is interpreted as JavaScript via javascript: protocol.
*/
predicate interpretsValueAsJavaScriptUrl() {
lhs.getPropertyName() = DOM::getAPropertyNameInterpretedAsJavaScriptUrl()
super.getPropertyName() = DOM::getAPropertyNameInterpretedAsJavaScriptUrl()
}
/**
* Gets the data flow node corresponding to the value being written.
*/
DataFlow::Node getRhs() {
result = super.getRhs()
or
result = super.getWriteNode().(AssignAddExpr).getRhs().flow()
}
}
/**
* A value written to web storage, like `localStorage` or `sessionStorage`.
*/
class WebStorageWrite extends Expr {
class WebStorageWrite extends DataFlow::Node {
WebStorageWrite() {
exists(DataFlow::SourceNode webStorage |
webStorage = DataFlow::globalVarRef("localStorage") or
webStorage = DataFlow::globalVarRef("sessionStorage")
|
// an assignment to `window.localStorage[someProp]`
this = webStorage.getAPropertyWrite().getRhs().asExpr()
this = webStorage.getAPropertyWrite().getRhs()
or
// an invocation of `window.localStorage.setItem`
this = webStorage.getAMethodCall("setItem").getArgument(1).asExpr()
this = webStorage.getAMethodCall("setItem").getArgument(1)
)
}
}

View File

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

View File

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

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

View File

@@ -30,14 +30,12 @@ module InsufficientPasswordHash {
* A potential clear-text password, considered as a source for password hashing
* with insufficient computational effort.
*/
class CleartextPasswordSource extends Source, DataFlow::ValueNode {
override SensitiveExpr astNode;
class CleartextPasswordSource extends Source instanceof SensitiveNode {
CleartextPasswordSource() {
astNode.getClassification() = SensitiveDataClassification::password()
super.getClassification() = SensitiveDataClassification::password()
}
override string describe() { result = astNode.describe() }
override string describe() { result = SensitiveNode.super.describe() }
}
/**
@@ -49,7 +47,7 @@ module InsufficientPasswordHash {
application.getAlgorithm().isWeak() or
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
rateLimiterClass = API::moduleImport("rate-limiter-flexible").getMember(rateLimiterClassName) and
rateLimiterConsume = rateLimiterClass.getInstance().getMember("consume") and
request.getParameter() = getRouteHandlerParameter(this.getFunction(), "request") and
request = getRouteHandlerParameter(this, "request") and
request.getAPropertyRead().flowsTo(rateLimiterConsume.getAParameter().asSink())
)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -12,16 +12,17 @@
import javascript
import semmle.javascript.RestrictedLocations
predicate isRepeatedDependency(AngularJS::InjectableFunction f, string name, AstNode location) {
predicate isRepeatedDependency(AngularJS::InjectableFunction f, string name, DataFlow::Node node) {
exists(int i, int j |
i < j and
exists(f.getDependencyDeclaration(i, name)) and
location = f.getDependencyDeclaration(j, name)
node = f.getDependencyDeclaration(j, name)
)
}
from AngularJS::InjectableFunction f, AstNode node, string name
from AngularJS::InjectableFunction f, DataFlow::Node node, string name
where
isRepeatedDependency(f, name, node) and
not count(f.asFunction().getParameterByName(name)) > 1 // avoid duplicating reports from js/duplicate-parameter-name
select f.asFunction().(FirstLineOf), "This function has a duplicate dependency '$@'.", node, name
select f.asFunction().getFunction().(FirstLineOf), "This function has a duplicate dependency '$@'.",
node, name

View File

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

View File

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

View File

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

View File

@@ -135,7 +135,7 @@ DataFlow::CallNode servesAPrivateFolder(string description) {
*/
Express::RouteSetup getAnExposingExpressSetup(string path) {
result.isUseCall() and
result.getArgument([0 .. 1]) = servesAPrivateFolder(path).getEnclosingExpr()
result.getArgument([0 .. 1]) = servesAPrivateFolder(path)
}
/**
@@ -149,7 +149,7 @@ DataFlow::CallNode getAnExposingServeSetup(string path) {
from DataFlow::Node node, string path
where
node = getAnExposingExpressSetup(path).flow()
node = getAnExposingExpressSetup(path)
or
node = getAnExposingServeSetup(path)
select node, "Serves " + path + ", which can contain private information."

View File

@@ -19,7 +19,7 @@ import DataFlow::PathGraph
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where
cfg.hasFlowPath(source, sink) and
not source.getNode().asExpr() instanceof CleartextPasswordExpr // flagged by js/insufficient-password-hash
not source.getNode() instanceof CleartextPasswordExpr // flagged by js/insufficient-password-hash
select sink.getNode(), source, sink,
"Sensitive data from $@ is used in a broken or weak cryptographic algorithm.", source.getNode(),
source.getNode().(Source).describe()

View File

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

View File

@@ -77,7 +77,7 @@ private module StandardPoIs {
UnpromotedRouteSetupPoI() { this = "UnpromotedRouteSetupPoI" }
override predicate is(Node l0) {
l0 instanceof HTTP::RouteSetupCandidate and not l0.asExpr() instanceof HTTP::RouteSetup
l0 instanceof HTTP::RouteSetupCandidate and not l0 instanceof HTTP::RouteSetup
}
}

View File

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

View File

@@ -16,7 +16,7 @@ class RouteHandlerAndSetupPoI extends ActivePoI {
RouteHandlerAndSetupPoI() { this = "RouteHandlerAndSetupPoI" }
override predicate is(Node l0, Node l1, string t1) {
l1.asExpr().(Express::RouteSetup).getARouteHandler() = l0 and t1 = "setup"
l1.(Express::RouteSetup).getARouteHandler() = l0 and t1 = "setup"
}
}
@@ -24,9 +24,9 @@ class RouteSetupAndRouterAndRouteHandlerPoI extends ActivePoI {
RouteSetupAndRouterAndRouteHandlerPoI() { this = "RouteSetupAndRouterAndRouteHandlerPoI" }
override predicate is(Node l0, Node l1, string t1, Node l2, string t2) {
l0.asExpr().(Express::RouteSetup).getRouter().flow() = l1 and
l0.(Express::RouteSetup).getRouter() = l1 and
t1 = "router" and
l0.asExpr().(Express::RouteSetup).getARouteHandler() = l2 and
l0.(Express::RouteSetup).getARouteHandler() = l2 and
t2 = "routehandler"
}
}

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
import javascript
private import AngularJS
from InjectableFunction f, SimpleParameter p, DataFlow::Node nd
from InjectableFunction f, DataFlow::ParameterNode p, DataFlow::Node nd
where nd = f.getCustomServiceDependency(p)
select p.getName(), nd

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

View File

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

View File

@@ -1,9 +1,9 @@
import javascript
query predicate test_RequestExpr(Express::RequestExpr e, HTTP::RouteHandler res) {
query predicate test_RequestExpr(Express::RequestNode e, HTTP::RouteHandler res) {
res = e.getRouteHandler()
}
query predicate test_RequestExprStandalone(Express::RequestExpr e) {
query predicate test_RequestExprStandalone(Express::RequestNode e) {
not exists(e.getRouteHandler())
}

View File

@@ -1,5 +1,5 @@
import javascript
query predicate test_ResponseExpr(Express::ResponseExpr e, HTTP::RouteHandler res) {
query predicate test_ResponseExpr(Express::ResponseNode e, HTTP::RouteHandler res) {
res = e.getRouteHandler()
}

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
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()
}

View File

@@ -1,7 +1,7 @@
import javascript
query predicate test_RouteHandlerExpr(
Express::RouteHandlerExpr rhe, Express::RouteSetup res0, boolean isLast
Express::RouteHandlerNode rhe, Express::RouteSetup res0, boolean isLast
) {
(if rhe.isLastHandler() then isLast = true else isLast = false) and
res0 = rhe.getSetup()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
import javascript
query predicate test_RouteHandler_getARequestBodyAccess(Express::RouteHandler rh, Expr res) {
query predicate test_RouteHandler_getARequestBodyAccess(Express::RouteHandler rh, DataFlow::Node res) {
res = rh.getARequestBodyAccess()
}

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
import javascript
query predicate test_RouteSetup(Express::RouteSetup rs, Expr res0, boolean isUseCall) {
query predicate test_RouteSetup(Express::RouteSetup rs, DataFlow::Node res0, boolean isUseCall) {
(if rs.isUseCall() then isUseCall = true else isUseCall = false) and
res0 = rs.getServer()
}

View File

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

View File

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

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