Skip to content

Commit e3a9906

Browse files
author
Max Schaefer
committed
JavaScript: Switch MissingRateLimiting.qll to API graphs.
The added test shows how this helps us avoid false positives.
1 parent e34a821 commit e3a9906

3 files changed

Lines changed: 24 additions & 14 deletions

File tree

javascript/ql/src/semmle/javascript/security/dataflow/MissingRateLimiting.qll

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import javascript
2626
private import semmle.javascript.frameworks.ConnectExpressShared::ConnectExpressShared
27+
private import ApiGraphs
2728

2829
// main concepts
2930
/**
@@ -126,7 +127,7 @@ abstract class RateLimiter extends Express::RouteHandlerExpr { }
126127
*/
127128
class ExpressRateLimit extends RateLimiter {
128129
ExpressRateLimit() {
129-
DataFlow::moduleImport("express-rate-limit").getAnInvocation().flowsToExpr(this)
130+
this = API::moduleImport("express-rate-limit").getReturn().getAUse().asExpr()
130131
}
131132
}
132133

@@ -135,11 +136,7 @@ class ExpressRateLimit extends RateLimiter {
135136
*/
136137
class BruteForceRateLimit extends RateLimiter {
137138
BruteForceRateLimit() {
138-
exists(DataFlow::ModuleImportNode expressBrute, DataFlow::SourceNode prevent |
139-
expressBrute.getPath() = "express-brute" and
140-
prevent = expressBrute.getAnInstantiation().getAPropertyRead("prevent") and
141-
prevent.flowsToExpr(this)
142-
)
139+
this = API::moduleImport("express-brute").getInstance().getMember("prevent").getAUse().asExpr()
143140
}
144141
}
145142

@@ -148,9 +145,9 @@ class BruteForceRateLimit extends RateLimiter {
148145
*/
149146
class RouteHandlerLimitedByExpressLimiter extends RateLimitedRouteHandlerExpr {
150147
RouteHandlerLimitedByExpressLimiter() {
151-
exists(DataFlow::ModuleImportNode expressLimiter |
152-
expressLimiter.getPath() = "express-limiter" and
153-
expressLimiter.getACall().getArgument(0).getALocalSource().asExpr() =
148+
exists(API::Feature expressLimiter |
149+
expressLimiter = API::moduleImport("express-limiter") and
150+
expressLimiter.getParameter(0).getADefinition().getALocalSource().asExpr() =
154151
this.getSetup().getRouter()
155152
)
156153
}
@@ -175,14 +172,14 @@ class RouteHandlerLimitedByExpressLimiter extends RateLimitedRouteHandlerExpr {
175172
class RateLimiterFlexibleRateLimiter extends DataFlow::FunctionNode {
176173
RateLimiterFlexibleRateLimiter() {
177174
exists(
178-
string rateLimiterClassName, DataFlow::SourceNode rateLimiterClass,
179-
DataFlow::SourceNode rateLimiterInstance, DataFlow::ParameterNode request
175+
string rateLimiterClassName, API::Feature rateLimiterClass, API::Feature rateLimiterConsume,
176+
DataFlow::ParameterNode request
180177
|
181178
rateLimiterClassName.matches("RateLimiter%") and
182-
rateLimiterClass = DataFlow::moduleMember("rate-limiter-flexible", rateLimiterClassName) and
183-
rateLimiterInstance = rateLimiterClass.getAnInstantiation() and
179+
rateLimiterClass = API::moduleImport("rate-limiter-flexible").getMember(rateLimiterClassName) and
180+
rateLimiterConsume = rateLimiterClass.getInstance().getMember("consume") and
184181
request.getParameter() = getRouteHandlerParameter(getFunction(), "request") and
185-
request.getAPropertyRead() = rateLimiterInstance.getAMemberCall("consume").getAnArgument()
182+
request.getAPropertyRead().flowsTo(rateLimiterConsume.getAParameter().getADefinition())
186183
)
187184
}
188185
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import rateLimit from 'express-rate-limit';
2+
3+
const rateLimitMiddleware = rateLimit();
4+
5+
export default rateLimitMiddleware;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import express from 'express';
2+
import rateLimiter from './rateLimit';
3+
4+
const app = express();
5+
app.use(rateLimiter);
6+
app.get('/', (req, res) => {
7+
res.sendFile('index.html'); // OK
8+
});

0 commit comments

Comments
 (0)