diff --git a/java/ql/lib/change-notes/2026-04-18-partial-path-traversal-fix.md b/java/ql/lib/change-notes/2026-04-18-partial-path-traversal-fix.md new file mode 100644 index 000000000000..8c15a346552e --- /dev/null +++ b/java/ql/lib/change-notes/2026-04-18-partial-path-traversal-fix.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The `java/partial-path-traversal` and `java/partial-path-traversal-from-remote` queries now correctly recognize file separator appends using `+=`. diff --git a/java/ql/lib/semmle/code/java/security/PartialPathTraversal.qll b/java/ql/lib/semmle/code/java/security/PartialPathTraversal.qll index 63ffb62ef63b..a7b0c50b0827 100644 --- a/java/ql/lib/semmle/code/java/security/PartialPathTraversal.qll +++ b/java/ql/lib/semmle/code/java/security/PartialPathTraversal.qll @@ -40,8 +40,11 @@ private class CharacterLiteralFileSeparatorExpr extends FileSeparatorExpr, Chara CharacterLiteralFileSeparatorExpr() { this.getValue() = "/" or this.getValue() = "\\" } } -private class FileSeparatorAppend extends AddExpr { - FileSeparatorAppend() { this.getRightOperand() instanceof FileSeparatorExpr } +private class FileSeparatorAppend extends BinaryExpr { + FileSeparatorAppend() { + this.(AddExpr).getRightOperand() instanceof FileSeparatorExpr or + this.(AssignAddExpr).getRightOperand() instanceof FileSeparatorExpr + } } private predicate isSafe(Expr expr) { diff --git a/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversal.qlref b/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversal.qlref index 431556c90afa..9d7e47fca707 100644 --- a/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversal.qlref +++ b/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversal.qlref @@ -1 +1,4 @@ -Security/CWE/CWE-023/PartialPathTraversal.ql \ No newline at end of file +query: Security/CWE/CWE-023/PartialPathTraversal.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversalFromRemoteTest.expected b/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversalFromRemoteTest.expected index f2af01542ee9..156adced6b08 100644 --- a/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversalFromRemoteTest.expected +++ b/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversalFromRemoteTest.expected @@ -1,19 +1,19 @@ #select -| PartialPathTraversalTest.java:13:14:13:37 | getCanonicalPath(...) | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:13:14:13:37 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | -| PartialPathTraversalTest.java:20:10:20:33 | getCanonicalPath(...) | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:20:10:20:33 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | -| PartialPathTraversalTest.java:32:14:32:37 | getCanonicalPath(...) | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:32:14:32:37 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | -| PartialPathTraversalTest.java:38:14:38:37 | getCanonicalPath(...) | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:38:14:38:37 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | -| PartialPathTraversalTest.java:45:14:45:26 | canonicalPath | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:45:14:45:26 | canonicalPath | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | -| PartialPathTraversalTest.java:52:14:52:26 | canonicalPath | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:52:14:52:26 | canonicalPath | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | -| PartialPathTraversalTest.java:56:14:56:27 | canonicalPath2 | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:56:14:56:27 | canonicalPath2 | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | -| PartialPathTraversalTest.java:64:14:64:26 | canonicalPath | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:64:14:64:26 | canonicalPath | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | -| PartialPathTraversalTest.java:67:14:67:27 | canonicalPath2 | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:67:14:67:27 | canonicalPath2 | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | -| PartialPathTraversalTest.java:97:14:97:37 | getCanonicalPath(...) | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:97:14:97:37 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | -| PartialPathTraversalTest.java:105:14:105:37 | getCanonicalPath(...) | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:105:14:105:37 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | -| PartialPathTraversalTest.java:108:14:108:37 | getCanonicalPath(...) | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:108:14:108:37 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | -| PartialPathTraversalTest.java:176:14:176:37 | getCanonicalPath(...) | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:176:14:176:37 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | -| PartialPathTraversalTest.java:194:18:194:47 | getCanonicalPath(...) | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:194:18:194:47 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | -| PartialPathTraversalTest.java:212:14:212:26 | canonicalPath | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:212:14:212:26 | canonicalPath | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:13:14:13:37 | getCanonicalPath(...) | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:13:14:13:37 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:20:10:20:33 | getCanonicalPath(...) | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:20:10:20:33 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:32:14:32:37 | getCanonicalPath(...) | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:32:14:32:37 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:38:14:38:37 | getCanonicalPath(...) | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:38:14:38:37 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:45:14:45:26 | canonicalPath | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:45:14:45:26 | canonicalPath | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:52:14:52:26 | canonicalPath | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:52:14:52:26 | canonicalPath | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:56:14:56:27 | canonicalPath2 | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:56:14:56:27 | canonicalPath2 | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:64:14:64:26 | canonicalPath | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:64:14:64:26 | canonicalPath | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:67:14:67:27 | canonicalPath2 | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:67:14:67:27 | canonicalPath2 | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:97:14:97:37 | getCanonicalPath(...) | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:97:14:97:37 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:105:14:105:37 | getCanonicalPath(...) | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:105:14:105:37 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:108:14:108:37 | getCanonicalPath(...) | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:108:14:108:37 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:176:14:176:37 | getCanonicalPath(...) | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:176:14:176:37 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:194:18:194:47 | getCanonicalPath(...) | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:194:18:194:47 | getCanonicalPath(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | +| PartialPathTraversalTest.java:212:14:212:26 | canonicalPath | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:212:14:212:26 | canonicalPath | Partial Path Traversal Vulnerability due to insufficient guard against path traversal from $@. | PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | user-supplied data | edges | PartialPathTraversalTest.java:13:14:13:18 | dir(...) : File | PartialPathTraversalTest.java:13:14:13:37 | getCanonicalPath(...) | provenance | MaD:6 | | PartialPathTraversalTest.java:20:10:20:14 | dir(...) : File | PartialPathTraversalTest.java:20:10:20:33 | getCanonicalPath(...) | provenance | MaD:6 | @@ -43,30 +43,30 @@ edges | PartialPathTraversalTest.java:194:18:194:28 | encodedFile : File | PartialPathTraversalTest.java:194:18:194:47 | getCanonicalPath(...) | provenance | MaD:6 | | PartialPathTraversalTest.java:211:46:211:50 | dir(...) : File | PartialPathTraversalTest.java:211:46:211:69 | getCanonicalPath(...) : String | provenance | MaD:6 | | PartialPathTraversalTest.java:211:46:211:69 | getCanonicalPath(...) : String | PartialPathTraversalTest.java:212:14:212:26 | canonicalPath | provenance | | -| PartialPathTraversalTest.java:252:45:252:117 | new BufferedReader(...) : BufferedReader | PartialPathTraversalTest.java:253:31:253:44 | filenameReader : BufferedReader | provenance | | -| PartialPathTraversalTest.java:252:64:252:116 | new InputStreamReader(...) : InputStreamReader | PartialPathTraversalTest.java:252:45:252:117 | new BufferedReader(...) : BufferedReader | provenance | MaD:2 | -| PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:252:64:252:116 | new InputStreamReader(...) : InputStreamReader | provenance | Src:MaD:1 MaD:7 | -| PartialPathTraversalTest.java:253:31:253:44 | filenameReader : BufferedReader | PartialPathTraversalTest.java:253:31:253:55 | readLine(...) : String | provenance | MaD:3 | -| PartialPathTraversalTest.java:253:31:253:55 | readLine(...) : String | PartialPathTraversalTest.java:254:29:254:36 | filename : String | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:13:14:13:18 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:20:10:20:14 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:32:14:32:18 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:38:14:38:18 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:44:32:44:36 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:51:32:51:36 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:55:33:55:37 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:62:32:62:36 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:63:33:63:37 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:97:14:97:18 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:105:14:105:18 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:108:14:108:18 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:176:14:176:18 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:211:46:211:50 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | PartialPathTraversalTest.java:261:16:261:20 | dir(...) : File | provenance | | -| PartialPathTraversalTest.java:254:29:254:36 | filename : String | PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | provenance | MaD:4 | -| PartialPathTraversalTest.java:261:16:261:20 | dir(...) : File | PartialPathTraversalTest.java:261:16:261:38 | getAbsolutePath(...) : String | provenance | MaD:5 | -| PartialPathTraversalTest.java:261:16:261:38 | getAbsolutePath(...) : String | PartialPathTraversalTest.java:261:16:261:60 | split(...) : String[] | provenance | MaD:10 | -| PartialPathTraversalTest.java:261:16:261:60 | split(...) : String[] | PartialPathTraversalTest.java:186:25:186:30 | path(...) : String[] | provenance | | +| PartialPathTraversalTest.java:260:45:260:117 | new BufferedReader(...) : BufferedReader | PartialPathTraversalTest.java:261:31:261:44 | filenameReader : BufferedReader | provenance | | +| PartialPathTraversalTest.java:260:64:260:116 | new InputStreamReader(...) : InputStreamReader | PartialPathTraversalTest.java:260:45:260:117 | new BufferedReader(...) : BufferedReader | provenance | MaD:2 | +| PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | PartialPathTraversalTest.java:260:64:260:116 | new InputStreamReader(...) : InputStreamReader | provenance | Src:MaD:1 MaD:7 | +| PartialPathTraversalTest.java:261:31:261:44 | filenameReader : BufferedReader | PartialPathTraversalTest.java:261:31:261:55 | readLine(...) : String | provenance | MaD:3 | +| PartialPathTraversalTest.java:261:31:261:55 | readLine(...) : String | PartialPathTraversalTest.java:262:29:262:36 | filename : String | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:13:14:13:18 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:20:10:20:14 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:32:14:32:18 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:38:14:38:18 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:44:32:44:36 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:51:32:51:36 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:55:33:55:37 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:62:32:62:36 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:63:33:63:37 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:97:14:97:18 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:105:14:105:18 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:108:14:108:18 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:176:14:176:18 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:211:46:211:50 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | PartialPathTraversalTest.java:269:16:269:20 | dir(...) : File | provenance | | +| PartialPathTraversalTest.java:262:29:262:36 | filename : String | PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | provenance | MaD:4 | +| PartialPathTraversalTest.java:269:16:269:20 | dir(...) : File | PartialPathTraversalTest.java:269:16:269:38 | getAbsolutePath(...) : String | provenance | MaD:5 | +| PartialPathTraversalTest.java:269:16:269:38 | getAbsolutePath(...) : String | PartialPathTraversalTest.java:269:16:269:60 | split(...) : String[] | provenance | MaD:10 | +| PartialPathTraversalTest.java:269:16:269:60 | split(...) : String[] | PartialPathTraversalTest.java:186:25:186:30 | path(...) : String[] | provenance | | models | 1 | Source: java.net; Socket; false; getInputStream; (); ; ReturnValue; remote; manual | | 2 | Summary: java.io; BufferedReader; false; BufferedReader; ; ; Argument[0]; Argument[this]; taint; manual | @@ -122,14 +122,14 @@ nodes | PartialPathTraversalTest.java:211:46:211:50 | dir(...) : File | semmle.label | dir(...) : File | | PartialPathTraversalTest.java:211:46:211:69 | getCanonicalPath(...) : String | semmle.label | getCanonicalPath(...) : String | | PartialPathTraversalTest.java:212:14:212:26 | canonicalPath | semmle.label | canonicalPath | -| PartialPathTraversalTest.java:252:45:252:117 | new BufferedReader(...) : BufferedReader | semmle.label | new BufferedReader(...) : BufferedReader | -| PartialPathTraversalTest.java:252:64:252:116 | new InputStreamReader(...) : InputStreamReader | semmle.label | new InputStreamReader(...) : InputStreamReader | -| PartialPathTraversalTest.java:252:86:252:106 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| PartialPathTraversalTest.java:253:31:253:44 | filenameReader : BufferedReader | semmle.label | filenameReader : BufferedReader | -| PartialPathTraversalTest.java:253:31:253:55 | readLine(...) : String | semmle.label | readLine(...) : String | -| PartialPathTraversalTest.java:254:20:254:37 | new File(...) : File | semmle.label | new File(...) : File | -| PartialPathTraversalTest.java:254:29:254:36 | filename : String | semmle.label | filename : String | -| PartialPathTraversalTest.java:261:16:261:20 | dir(...) : File | semmle.label | dir(...) : File | -| PartialPathTraversalTest.java:261:16:261:38 | getAbsolutePath(...) : String | semmle.label | getAbsolutePath(...) : String | -| PartialPathTraversalTest.java:261:16:261:60 | split(...) : String[] | semmle.label | split(...) : String[] | +| PartialPathTraversalTest.java:260:45:260:117 | new BufferedReader(...) : BufferedReader | semmle.label | new BufferedReader(...) : BufferedReader | +| PartialPathTraversalTest.java:260:64:260:116 | new InputStreamReader(...) : InputStreamReader | semmle.label | new InputStreamReader(...) : InputStreamReader | +| PartialPathTraversalTest.java:260:86:260:106 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| PartialPathTraversalTest.java:261:31:261:44 | filenameReader : BufferedReader | semmle.label | filenameReader : BufferedReader | +| PartialPathTraversalTest.java:261:31:261:55 | readLine(...) : String | semmle.label | readLine(...) : String | +| PartialPathTraversalTest.java:262:20:262:37 | new File(...) : File | semmle.label | new File(...) : File | +| PartialPathTraversalTest.java:262:29:262:36 | filename : String | semmle.label | filename : String | +| PartialPathTraversalTest.java:269:16:269:20 | dir(...) : File | semmle.label | dir(...) : File | +| PartialPathTraversalTest.java:269:16:269:38 | getAbsolutePath(...) : String | semmle.label | getAbsolutePath(...) : String | +| PartialPathTraversalTest.java:269:16:269:60 | split(...) : String[] | semmle.label | split(...) : String[] | subpaths diff --git a/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversalTest.java b/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversalTest.java index b1986c1b6694..42e70b2c53d3 100644 --- a/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversalTest.java +++ b/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversalTest.java @@ -10,14 +10,14 @@ public class PartialPathTraversalTest { public void esapiExample(File parent) throws IOException { - if (!dir().getCanonicalPath().startsWith(parent.getCanonicalPath())) { // $ Alert + if (!dir().getCanonicalPath().startsWith(parent.getCanonicalPath())) { // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] throw new IOException("Invalid directory: " + dir().getCanonicalPath()); } } @SuppressWarnings("ResultOfMethodCallIgnored") void foo1(File parent) throws IOException { - (dir().getCanonicalPath()).startsWith((parent.getCanonicalPath())); // $ Alert + (dir().getCanonicalPath()).startsWith((parent.getCanonicalPath())); // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] } void foo2(File parent) throws IOException { @@ -29,31 +29,31 @@ void foo2(File parent) throws IOException { void foo3(File parent) throws IOException { String parentPath = parent.getCanonicalPath(); - if (!dir().getCanonicalPath().startsWith(parentPath)) { // $ Alert + if (!dir().getCanonicalPath().startsWith(parentPath)) { // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] throw new IOException("Invalid directory: " + dir().getCanonicalPath()); } } void foo4() throws IOException { - if (!dir().getCanonicalPath().startsWith("/usr" + "/dir")) { // $ Alert + if (!dir().getCanonicalPath().startsWith("/usr" + "/dir")) { // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] throw new IOException("Invalid directory: " + dir().getCanonicalPath()); } } void foo5(File parent) throws IOException { String canonicalPath = dir().getCanonicalPath(); - if (!canonicalPath.startsWith(parent.getCanonicalPath())) { // $ Alert + if (!canonicalPath.startsWith(parent.getCanonicalPath())) { // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] throw new IOException("Invalid directory: " + dir().getCanonicalPath()); } } void foo6(File parent) throws IOException { String canonicalPath = dir().getCanonicalPath(); - if (!canonicalPath.startsWith(parent.getCanonicalPath())) { // $ Alert + if (!canonicalPath.startsWith(parent.getCanonicalPath())) { // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] throw new IOException("Invalid directory: " + dir().getCanonicalPath()); } String canonicalPath2 = dir().getCanonicalPath(); - if (!canonicalPath2.startsWith(parent.getCanonicalPath())) { // $ Alert + if (!canonicalPath2.startsWith(parent.getCanonicalPath())) { // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] throw new IOException("Invalid directory: " + dir().getCanonicalPath()); } } @@ -61,10 +61,10 @@ void foo6(File parent) throws IOException { void foo7(File dir, File parent) throws IOException { String canonicalPath = dir().getCanonicalPath(); String canonicalPath2 = dir().getCanonicalPath(); - if (!canonicalPath.startsWith(parent.getCanonicalPath())) { // $ Alert + if (!canonicalPath.startsWith(parent.getCanonicalPath())) { // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] throw new IOException("Invalid directory: " + dir().getCanonicalPath()); } - if (!canonicalPath2.startsWith(parent.getCanonicalPath())) { // $ Alert + if (!canonicalPath2.startsWith(parent.getCanonicalPath())) { // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] throw new IOException("Invalid directory: " + dir().getCanonicalPath()); } } @@ -75,7 +75,7 @@ File getChild() { void foo8(File parent) throws IOException { String canonicalPath = getChild().getCanonicalPath(); - if (!canonicalPath.startsWith(parent.getCanonicalPath())) { + if (!canonicalPath.startsWith(parent.getCanonicalPath())) { // $ Alert[java/partial-path-traversal] throw new IOException("Invalid directory: " + getChild().getCanonicalPath()); } } @@ -94,7 +94,7 @@ void foo10(File parent) throws IOException { void foo11(File parent) throws IOException { String parentCanonical = parent.getCanonicalPath(); - if (!dir().getCanonicalPath().startsWith(parentCanonical)) { // $ Alert + if (!dir().getCanonicalPath().startsWith(parentCanonical)) { // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] throw new IOException("Invalid directory: " + dir().getCanonicalPath()); } } @@ -102,10 +102,10 @@ void foo11(File parent) throws IOException { void foo12(File parent) throws IOException { String parentCanonical = parent.getCanonicalPath(); String parentCanonical2 = parent.getCanonicalPath(); - if (!dir().getCanonicalPath().startsWith(parentCanonical)) { // $ Alert + if (!dir().getCanonicalPath().startsWith(parentCanonical)) { // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] throw new IOException("Invalid directory: " + dir().getCanonicalPath()); } - if (!dir().getCanonicalPath().startsWith(parentCanonical2)) { // $ Alert + if (!dir().getCanonicalPath().startsWith(parentCanonical2)) { // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] throw new IOException("Invalid directory: " + dir().getCanonicalPath()); } } @@ -173,7 +173,7 @@ void foo18(File dir, File parent, boolean branch) throws IOException { void foo19(File parent) throws IOException { String parentCanonical = parent.getCanonicalPath() + "/potato"; - if (!dir().getCanonicalPath().startsWith(parentCanonical)) { // $ Alert + if (!dir().getCanonicalPath().startsWith(parentCanonical)) { // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] throw new IOException("Invalid directory: " + dir().getCanonicalPath()); } } @@ -191,7 +191,7 @@ InputStream foo20() { String filePath = sb.toString(); File encodedFile = new File(filePath); try { - if (!encodedFile.getCanonicalPath().startsWith(cacheDir.getCanonicalPath())) { // $ Alert + if (!encodedFile.getCanonicalPath().startsWith(cacheDir.getCanonicalPath())) { // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] return null; } return Files.newInputStream(encodedFile.toPath()); @@ -209,7 +209,7 @@ void foo21(File parent) throws IOException { void foo22(File dir2, File parent, boolean conditional) throws IOException { String canonicalPath = conditional ? dir().getCanonicalPath() : dir2.getCanonicalPath(); - if (!canonicalPath.startsWith(parent.getCanonicalPath())) { // $ Alert + if (!canonicalPath.startsWith(parent.getCanonicalPath())) { // $ Alert[java/partial-path-traversal-from-remote] Alert[java/partial-path-traversal] throw new IOException("Invalid directory: " + dir().getCanonicalPath()); } } @@ -228,6 +228,14 @@ void foo24(File parent) throws IOException { } } + void foo25(File parent) throws IOException { + String path = parent.getCanonicalPath(); + path += File.separator; + if (!dir().getCanonicalPath().startsWith(path)) { + throw new IOException("Invalid directory: " + dir().getCanonicalPath()); + } + } + public void doesNotFlagOptimalSafeVersion(File parent) throws IOException { if (!dir().toPath().normalize().startsWith(parent.toPath())) { // Safe throw new IOException("Path traversal attempt: " + dir().getCanonicalPath());