diff --git a/java/ql/lib/semmle/code/java/security/PathSanitizer.qll b/java/ql/lib/semmle/code/java/security/PathSanitizer.qll index 77803e3e27dc2..6b81f7cc9df01 100644 --- a/java/ql/lib/semmle/code/java/security/PathSanitizer.qll +++ b/java/ql/lib/semmle/code/java/security/PathSanitizer.qll @@ -333,3 +333,18 @@ private Method getSourceMethod(Method m) { not exists(Method src | m = src.getKotlinParameterDefaultsProxy()) and result = m } + +/** + * A sanitizer that protects against path injection vulnerabilities + * by extracting the final component of the user provided path. + * + * TODO: convert this class to models-as-data if sanitizer support is added + */ +private class FileGetNameSanitizer extends PathInjectionSanitizer { + FileGetNameSanitizer() { + exists(MethodCall mc | + mc.getMethod().hasQualifiedName("java.io", "File", "getName") and + this.asExpr() = mc.getQualifier() + ) + } +} diff --git a/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.java b/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.java index 8bfc35c1d969b..00447364bb386 100644 --- a/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.java +++ b/java/ql/test/query-tests/security/CWE-022/semmle/tests/TaintedPath.java @@ -71,4 +71,19 @@ public void sendUserFileGood3(Socket sock, String user) throws Exception { fileLine = fileReader.readLine(); } } + + public void sendUserFileGood4(Socket sock, String user) throws IOException { + BufferedReader filenameReader = + new BufferedReader(new InputStreamReader(sock.getInputStream(), "UTF-8")); + String filename = filenameReader.readLine(); + File file = new File(filename); + String baseName = file.getName(); + // GOOD: only use the final component of the user provided path + BufferedReader fileReader = new BufferedReader(new FileReader(baseName)); + String fileLine = fileReader.readLine(); + while (fileLine != null) { + sock.getOutputStream().write(fileLine.getBytes()); + fileLine = fileReader.readLine(); + } + } }