@@ -352,3 +352,73 @@ private class FileGetNameSanitizer extends PathInjectionSanitizer {
352
352
)
353
353
}
354
354
}
355
+
356
+ /**
357
+ * A complementary sanitizer that protects against path injection vulnerabilities
358
+ * by replacing all directory characters ('..', '/', and '\') with safe characters.
359
+ */
360
+ private class ReplaceDirectoryCharactersSanitizer extends MethodCall {
361
+ ReplaceDirectoryCharactersSanitizer ( ) {
362
+ exists ( MethodCall mc |
363
+ // TODO: "java.lang.String.replace" as well
364
+ mc .getMethod ( ) .hasQualifiedName ( "java.lang" , "String" , "replaceAll" ) and
365
+ // TODO: unhardcode all of the below to handle more valid replacements and several calls
366
+ (
367
+ mc .getArgument ( 0 ) .( CompileTimeConstantExpr ) .getStringValue ( ) = "\\.\\.|[/\\\\]"
368
+ or
369
+ exists ( MethodCall mc2 |
370
+ mc2 .getMethod ( ) .hasQualifiedName ( "java.lang" , "String" , "replaceAll" ) and
371
+ mc .getArgument ( 0 ) .( CompileTimeConstantExpr ) .getStringValue ( ) = "\\." and
372
+ mc2 .getArgument ( 0 ) .( CompileTimeConstantExpr ) .getStringValue ( ) = "/"
373
+ )
374
+ ) and
375
+ // TODO: accept more replacement characters?
376
+ mc .getArgument ( 1 ) .( CompileTimeConstantExpr ) .getStringValue ( ) = [ "" , "_" ] and
377
+ this = mc
378
+ )
379
+ }
380
+ }
381
+
382
+ /**
383
+ * A complementary guard that protects against path traversal by looking
384
+ * for patterns that exclude directory characters: `..`, '/', and '\'.
385
+ */
386
+ private class DirectoryCharactersGuard extends PathGuard {
387
+ Expr checkedExpr ;
388
+
389
+ DirectoryCharactersGuard ( ) {
390
+ exists ( MethodCall mc , Method m | m = mc .getMethod ( ) |
391
+ m .getDeclaringType ( ) instanceof TypeString and
392
+ m .hasName ( "matches" ) and
393
+ // TODO: unhardcode to handle more valid matches
394
+ mc .getAnArgument ( ) .( CompileTimeConstantExpr ) .getStringValue ( ) = "[0-9a-fA-F]{20,}" and
395
+ checkedExpr = mc .getQualifier ( ) and
396
+ this = mc
397
+ )
398
+ }
399
+
400
+ override Expr getCheckedExpr ( ) { result = checkedExpr }
401
+ }
402
+
403
+ /**
404
+ * Holds if `g` is a guard that considers a path safe because it is checked to make
405
+ * sure it does not contain any directory characters: '..', '/', and '\'.
406
+ */
407
+ private predicate directoryCharactersGuard ( Guard g , Expr e , boolean branch ) {
408
+ branch = true and
409
+ g instanceof DirectoryCharactersGuard and
410
+ localTaintFlowToPathGuard ( e , g )
411
+ }
412
+
413
+ /**
414
+ * A sanitizer that protects against path injection vulnerabilities
415
+ * by ensuring that the path does not contain any directory characters:
416
+ * '..', '/', and '\'.
417
+ */
418
+ private class DirectoryCharactersSanitizer extends PathInjectionSanitizer {
419
+ DirectoryCharactersSanitizer ( ) {
420
+ this .asExpr ( ) instanceof ReplaceDirectoryCharactersSanitizer or
421
+ this = DataFlow:: BarrierGuard< directoryCharactersGuard / 3 > :: getABarrierNode ( ) or
422
+ this = ValidationMethod< directoryCharactersGuard / 3 > :: getAValidatedNode ( )
423
+ }
424
+ }
0 commit comments