Skip to content

Commit 2c1e80a

Browse files
committed
Merge branch 'remove-leading-slashes-path' into add-zen-qa
2 parents c80f5f8 + 3d4995f commit 2c1e80a

3 files changed

Lines changed: 83 additions & 9 deletions

File tree

agent_api/src/main/java/dev/aikido/agent_api/vulnerabilities/path_traversal/UnsafePathChecker.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,30 @@ private UnsafePathChecker() {}
3232
"c:\\"
3333
);
3434

35-
public static boolean startsWithUnsafePath(String filePath) {
36-
String lowerCasePath = filePath.toLowerCase();
35+
public static boolean startsWithUnsafePath(String filePathRaw) {
36+
String filePath = ensureOneLeadingSlash(filePathRaw.toLowerCase());
3737

3838
List<String> dangerousStartsList = new ArrayList<>(DANGEROUS_PATH_STARTS);
3939
dangerousStartsList.addAll(LINUX_ROOT_FOLDERS);
4040

4141
for (String dangerousStart : dangerousStartsList) {
42-
if (lowerCasePath.startsWith(dangerousStart)) {
42+
if (filePath.startsWith(dangerousStart)) {
4343
return true;
4444
}
4545
}
4646
return false;
4747
}
48-
public static boolean startsWithUnsafePath(String filePath, String userInput) {
49-
String filePathLowercase = filePath.toLowerCase();
50-
String userinputLowercase = userInput.toLowerCase();
51-
return startsWithUnsafePath(filePathLowercase) && filePathLowercase.startsWith(userinputLowercase);
48+
49+
public static boolean startsWithUnsafePath(String filePathRaw, String userInputRaw) {
50+
String filePath = ensureOneLeadingSlash(filePathRaw.toLowerCase());
51+
String userInput = ensureOneLeadingSlash(userInputRaw.toLowerCase());
52+
return startsWithUnsafePath(filePath) && filePath.startsWith(userInput);
53+
}
54+
55+
private static String ensureOneLeadingSlash(String path) {
56+
if (path.startsWith("/")) {
57+
return "/" + path.replaceAll("^/+", "");
58+
}
59+
return path;
5260
}
5361
}

agent_api/src/test/java/vulnerabilities/path_traversal/UnsafePathCheckerTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,15 @@ public void testEdgeCases() {
3737
assertTrue(UnsafePathChecker.startsWithUnsafePath("c:/", "c:/"));
3838
assertTrue(UnsafePathChecker.startsWithUnsafePath("c:/folder/file.txt", "c:/folder"));
3939
}
40+
41+
@Test
42+
public void testMultipleSlashes() {
43+
assertTrue(UnsafePathChecker.startsWithUnsafePath("///etc///passwd", "///etc//"));
44+
assertTrue(UnsafePathChecker.startsWithUnsafePath("///etc/passwd", "///etc"));
45+
assertFalse(UnsafePathChecker.startsWithUnsafePath("etc/passwd///../test.txt", "etc/passwd///../test.txt"));
46+
47+
assertTrue(UnsafePathChecker.startsWithUnsafePath("///etc///passwd"));
48+
assertTrue(UnsafePathChecker.startsWithUnsafePath("///etc/passwd"));
49+
assertFalse(UnsafePathChecker.startsWithUnsafePath("etc/passwd///../test.txt"));
50+
}
4051
}

agent_api/src/test/java/wrappers/FileWrapperTest.java

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
import java.io.File;
1212
import java.net.URI;
13+
import java.nio.file.Files;
14+
import java.nio.file.Path;
15+
import java.nio.file.Paths;
16+
import java.util.List;
1317

1418
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
1519
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -41,7 +45,7 @@ public void testPathTraversalString() throws Exception {
4145
assertThrows(RuntimeException.class, () -> {
4246
new File("/var/../file.txt");
4347
});
44-
48+
4549
cleanup();
4650
assertDoesNotThrow(() -> {
4751
new File("/var/../file.txt");
@@ -88,4 +92,55 @@ public void testPathTraversalMultiple() throws Exception {
8892
new File("/etc/", "/var/../file.txt");
8993
});
9094
}
91-
}
95+
96+
@Test
97+
public void testOsCreatePathWithMultipleSlashes() {
98+
String filePath = "/////etc/passwd";
99+
setContextAndLifecycle(filePath);
100+
assertThrows(RuntimeException.class, () -> {
101+
Path fullPath = Paths.get(filePath);
102+
List<String> lines = Files.readAllLines(fullPath);
103+
System.err.println(lines);
104+
});
105+
}
106+
107+
@Test
108+
public void testOsCreatePathWithMultipleSlashesNegative() {
109+
String filePath = "safe/relative/path";
110+
setContextAndLifecycle(filePath);
111+
assertDoesNotThrow(() -> {
112+
File fullPath = new File("flaskr/resources/blogs/", filePath);
113+
fullPath.exists(); // Simulate access
114+
});
115+
}
116+
117+
@Test
118+
public void testOsCreatePathWithMultipleDoubleSlashes() {
119+
String filePath = "////etc//passwd";
120+
setContextAndLifecycle(filePath);
121+
assertThrows(RuntimeException.class, () -> {
122+
File fullPath = new File("flaskr/resources/blogs/", filePath);
123+
fullPath.exists(); // Simulate access
124+
});
125+
}
126+
127+
@Test
128+
public void testOsCreatePathWithMultipleDoubleSlashesNegative() {
129+
String filePath = "safe//relative//path";
130+
setContextAndLifecycle(filePath);
131+
assertDoesNotThrow(() -> {
132+
File fullPath = new File("flaskr/resources/blogs/", filePath);
133+
fullPath.exists(); // Simulate access
134+
});
135+
}
136+
137+
@Test
138+
public void testOsPathTraversalWithMultipleSlashes() {
139+
String filePath = "home///..////..////my_secret.txt";
140+
setContextAndLifecycle(filePath);
141+
assertThrows(RuntimeException.class, () -> {
142+
File fullPath = new File("flaskr/resources/blogs/", filePath);
143+
fullPath.exists(); // Simulate access
144+
});
145+
}
146+
}

0 commit comments

Comments
 (0)