@@ -6,6 +6,7 @@ private import semmle.code.java.dataflow.FlowSources
66private import semmle.code.java.dataflow.SSA
77private import semmle.code.java.frameworks.kotlin.IO
88private import semmle.code.java.frameworks.kotlin.Text
9+ private import semmle.code.java.dataflow.Nullness
910
1011/** A sanitizer that protects against path injection vulnerabilities. */
1112abstract class PathInjectionSanitizer extends DataFlow:: Node { }
@@ -352,6 +353,16 @@ private class FileGetNameSanitizer extends PathInjectionSanitizer {
352353 }
353354}
354355
356+ /** Holds if `expr` may be null. */
357+ private predicate maybeNull ( Expr expr ) {
358+ exists ( DataFlow:: Node src , DataFlow:: Node sink |
359+ src .asExpr ( ) = nullExpr ( ) and
360+ sink .asExpr ( ) = expr
361+ |
362+ DataFlow:: localFlow ( src , sink )
363+ )
364+ }
365+
355366/** Holds if `g` is a guard that checks for `..` components. */
356367private predicate pathTraversalGuard ( Guard g , Expr e , boolean branch ) {
357368 branch = g .( PathTraversalGuard ) .getBranch ( ) and
@@ -367,6 +378,10 @@ private class FileConstructorSanitizer extends PathInjectionSanitizer {
367378 FileConstructorSanitizer ( ) {
368379 exists ( ConstructorCall constrCall , Argument arg |
369380 constrCall .getConstructedType ( ) instanceof TypeFile and
381+ // Exclude cases where the parent argument is null since the
382+ // `java.io.File` documentation states that such cases are
383+ // treated as if invoking the single-argument `File` constructor.
384+ not maybeNull ( constrCall .getArgument ( 0 ) ) and
370385 arg = constrCall .getArgument ( 1 ) and
371386 (
372387 arg = DataFlow:: BarrierGuard< pathTraversalGuard / 3 > :: getABarrierNode ( ) .asExpr ( ) or
0 commit comments