diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 78c191966a20..39a2dcf5a62b 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -3823,11 +3823,14 @@ public Boolean invoke(@NonNull File parentFile, @NonNull VirtualChannel channel) return true; } - private @CheckForNull Path getDirectChild(Path parentPath, String childPath) { + private @NonNull Path getDirectChild(Path parentPath, String childPath) { Path current = parentPath.resolve(childPath); while (current != null && !parentPath.equals(current.getParent())) { current = current.getParent(); } + if (current == null) { + throw new IllegalStateException("Invalid path traversal: " + parentPath + " -> " + childPath); + } return current; } diff --git a/core/src/test/java/hudson/FilePathTest.java b/core/src/test/java/hudson/FilePathTest.java index 24ffe9b212d5..45968223d9c0 100644 --- a/core/src/test/java/hudson/FilePathTest.java +++ b/core/src/test/java/hudson/FilePathTest.java @@ -1297,4 +1297,11 @@ private static File newFolder(File root, String... subDirs) throws IOException { } return result; } + + @Test + public void testIsDescendantWithParentTraversal(@org.junit.jupiter.api.io.TempDir java.nio.file.Path tempDir) throws Exception { + FilePath parent = new FilePath(tempDir.toFile()); + // Confirms that '..' does not crash the system (proving getDirectChild is safe) + assertFalse(parent.isDescendant(".."), "Parent directory '..' should not be a descendant"); + } }