Skip to content

Commit 406c6eb

Browse files
committed
JS: Sharpen missing CSRF middleware query
1 parent 53e10e4 commit 406c6eb

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

change-notes/1.24/analysis-javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
| Unbound event handler receiver (`js/unbound-event-handler-receiver`) | Fewer false positive results | This query now recognizes additional ways event handler receivers can be bound. |
3434
| Expression has no effect (`js/useless-expression`) | Fewer false positive results | The query now recognizes block-level flow type annotations and ignores the first statement of a try block. |
3535
| Use of call stack introspection in strict mode (`js/strict-mode-call-stack-introspection`) | Fewer false positive results | The query no longer flags expression statements. |
36+
| Missing CSRF middleware (`js/missing-token-validation`) | Fewer false positive results | The query reports fewer duplicates and only flags handlers that explicitly access cookie data. |
3637

3738
## Changes to libraries
3839

javascript/ql/src/Security/CWE-352/MissingCsrfMiddleware.ql

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,45 @@
1212

1313
import javascript
1414

15+
/** Gets a data flow node that flows to the base of an access to `cookies` or `session`. */
16+
private DataFlow::SourceNode nodeLeadingToCookieAccess(DataFlow::TypeBackTracker t) {
17+
t.start() and
18+
exists(string name | name = "session" or name = "cookies" |
19+
exists(result.getAPropertyRead(name))
20+
)
21+
or
22+
exists(DataFlow::TypeBackTracker t2 |
23+
result = nodeLeadingToCookieAccess(t2).backtrack(t2, t)
24+
)
25+
}
26+
27+
/** Gets a data flow node that flows to the base of an access to `cookies` or `session`. */
28+
DataFlow::SourceNode nodeLeadingToCookieAccess() {
29+
result = nodeLeadingToCookieAccess(DataFlow::TypeBackTracker::end())
30+
}
31+
32+
/**
33+
* Holds if `handler` uses cookies.
34+
*/
35+
predicate isRouteHandlerUsingCookies(Express::RouteHandler handler) {
36+
DataFlow::parameterNode(handler.getRequestParameter()) = nodeLeadingToCookieAccess()
37+
}
38+
39+
/** Gets a data flow node referring to a route handler that uses cookies. */
40+
private DataFlow::SourceNode getARouteUsingCookies(DataFlow::TypeTracker t) {
41+
t.start() and
42+
isRouteHandlerUsingCookies(result)
43+
or
44+
exists(DataFlow::TypeTracker t2 |
45+
result = getARouteUsingCookies(t2).track(t2, t)
46+
)
47+
}
48+
49+
/** Gets a data flow node referring to a route handler that uses cookies. */
50+
DataFlow::SourceNode getARouteUsingCookies() {
51+
result = getARouteUsingCookies(DataFlow::TypeTracker::end())
52+
}
53+
1554
/**
1655
* Checks if `expr` is preceded by the cookie middleware `cookie`.
1756
*
@@ -63,11 +102,23 @@ from
63102
where
64103
router = setup.getRouter() and
65104
handler = setup.getARouteHandlerExpr() and
105+
106+
// Require that the handler uses cookies and has cookie middleware.
107+
//
108+
// In practice, handlers that use cookies always have the cookie middleware or
109+
// the handler wouldn't work. However, if we can't find the cookie middleware, it
110+
// indicates that our middleware model is too incomplete, so in that case we
111+
// don't trust it to detect the presence of CSRF middleware either.
112+
getARouteUsingCookies().flowsToExpr(handler.getPreviousMiddleware*()) and
66113
hasCookieMiddleware(handler, cookie) and
114+
115+
// Only flag the first cookie parser registered first.
116+
not hasCookieMiddleware(cookie, _) and
117+
67118
not hasCsrfMiddleware(handler) and
68119
// Only warn for the last handler in a chain.
69120
handler.isLastHandler() and
70-
// Only warn for dangerous for handlers, such as for POST and PUT.
121+
// Only warn for dangerous handlers, such as for POST and PUT.
71122
not setup.getRequestMethod().isSafe()
72123
select cookie, "This cookie middleware is serving a request handler $@ without CSRF protection.",
73124
handler, "here"

0 commit comments

Comments
 (0)