@@ -131,19 +131,31 @@ private class PathMatchGuard extends UnsafeUrlForwardBarrierGuard {
131
131
isExactStringPathMatch ( this ) and
132
132
branch = true
133
133
or
134
+ // When using an allowlist, that is, checking for known safe paths
135
+ // (for example, `path.startsWith(BASE_PATH)`)
136
+ // the application needs to protect against path traversal bypasses.
134
137
isAllowListCheck ( this ) and
135
138
exists ( MethodAccess ma , Expr checked | isPathTraversalCheck ( ma , checked ) |
136
- DataFlow:: localExprFlow ( checked , e )
137
- or
138
- ma .getParent * ( ) .( BinaryExpr ) = this .( MethodAccess ) .getParent * ( )
139
+ // Either the path traversal check comes before the guard
140
+ DataFlow:: localExprFlow ( checked , e ) or
141
+ // or both checks are in the same condition
142
+ // (for example, `path.startsWith(BASE_PATH) && !path.contains("..")`)
143
+ ma .( Guard ) .controls ( this .getBasicBlock ( ) , _) or
144
+ this .controls ( ma .getBasicBlock ( ) , branch )
139
145
) and
140
146
branch = true
141
147
or
148
+ // When using a blocklist, that is, checking for known bad patterns in the path,
149
+ // (for example, `path.startsWith("/WEB-INF/")` or `path.contains("..")`)
150
+ // the application needs to protect against double URL encoding bypasses.
142
151
isDisallowListCheck ( this ) and
143
152
exists ( MethodAccess ma , Expr checked | isURLEncodingCheck ( ma , checked ) |
144
- DataFlow:: localExprFlow ( checked , e )
145
- or
146
- ma .getParent * ( ) .( BinaryExpr ) = this .( MethodAccess ) .getParent * ( )
153
+ // Either the URL encoding check comes before the guard
154
+ DataFlow:: localExprFlow ( checked , e ) or
155
+ // or both checks are in the same condition
156
+ // (for example, `!path.contains("..") && !path.contains("%")`)
157
+ ma .( Guard ) .controls ( this .getBasicBlock ( ) , _) or
158
+ this .controls ( ma .getBasicBlock ( ) , branch )
147
159
) and
148
160
branch = false
149
161
)
0 commit comments