@@ -131,19 +131,31 @@ private class PathMatchGuard extends UnsafeUrlForwardBarrierGuard {
131131 isExactStringPathMatch ( this ) and
132132 branch = true
133133 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.
134137 isAllowListCheck ( this ) and
135138 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 )
139145 ) and
140146 branch = true
141147 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.
142151 isDisallowListCheck ( this ) and
143152 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 )
147159 ) and
148160 branch = false
149161 )
0 commit comments