You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by cs...@apache.org on 2026/08/31 10:22:56 UTC
(maven-resolver) branch master updated: FileTransporter: contain resolved resource paths under the repository base (#2088)
This is an automated email from the ASF dual-hosted git repository.
cstamas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
The following commit(s) were added to refs/heads/master by this push:
new 68caebfd0 FileTransporter: contain resolved resource paths under the repository base (#2088)
68caebfd0 is described below
commit 68caebfd0f1d9900b7421454d549d99c005366b7
Author: Sylwester Lachiewicz <sl...@apache.org>
AuthorDate: Mon Aug 31 12:22:50 2026 +0200
FileTransporter: contain resolved resource paths under the repository base (#2088)
`FileTransporter.getPath` tested the raw location string with `path.contains("../")` before resolving
it against the repository base directory. A substring test on an unparsed string is a fragile way to
decide whether a resolved path stays where it should, and it does not consider an absolute location
at all.
This replaces it with file system path operations:
- reject a null location,
- reject a location that parses as an absolute path,
- reject any location with a `..` segment,
- resolve against the base directory, normalize, and require the result to remain under it.
The tests run against both a real file system and an in-memory one (Jimfs), including on Windows,
where an absolute location has a different shape. `absoluteLocation` in the test builds that URI in a
platform-neutral way rather than hard-coding a separator.
---
.../aether/transport/file/FileTransporter.java | 16 ++++-
.../aether/transport/file/FileTransporterTest.java | 83 ++++++++++++++++++++++
2 files changed, 97 insertions(+), 2 deletions(-)
diff --git a/maven-resolver-transport-file/src/main/java/org/eclipse/aether/transport/file/FileTransporter.java b/maven-resolver-transport-file/src/main/java/org/eclipse/aether/transport/file/FileTransporter.java
index a5db75623..1dbc4fd56 100644
--- a/maven-resolver-transport-file/src/main/java/org/eclipse/aether/transport/file/FileTransporter.java
+++ b/maven-resolver-transport-file/src/main/java/org/eclipse/aether/transport/file/FileTransporter.java
@@ -163,10 +163,22 @@ final class FileTransporter extends AbstractTransporter {
private Path getPath(TransportTask task, boolean required) throws Exception {
String path = task.getLocation().getPath();
- if (path.contains("../")) {
+ if (path == null) {
+ throw new IllegalArgumentException("illegal resource path: null");
+ }
+ Path relative = fileSystem.getPath(path);
+ if (relative.isAbsolute()) {
+ throw new IllegalArgumentException("illegal resource path: " + path);
+ }
+ for (Path segment : relative) {
+ if ("..".equals(segment.toString())) {
+ throw new IllegalArgumentException("illegal resource path: " + path);
+ }
+ }
+ Path file = basePath.resolve(relative).normalize();
+ if (!file.startsWith(basePath.normalize())) {
throw new IllegalArgumentException("illegal resource path: " + path);
}
- Path file = basePath.resolve(path);
if (required && !Files.isRegularFile(file)) {
throw new ResourceNotFoundException("Could not locate " + file);
}
diff --git a/maven-resolver-transport-file/src/test/java/org/eclipse/aether/transport/file/FileTransporterTest.java b/maven-resolver-transport-file/src/test/java/org/eclipse/aether/transport/file/FileTransporterTest.java
index 0a24bce75..dd54d65ed 100644
--- a/maven-resolver-transport-file/src/test/java/org/eclipse/aether/transport/file/FileTransporterTest.java
+++ b/maven-resolver-transport-file/src/test/java/org/eclipse/aether/transport/file/FileTransporterTest.java
@@ -106,6 +106,20 @@ public class FileTransporterTest {
transporter = factory.newInstance(session, newRepo(url));
}
+ /**
+ * Builds a task location URI carrying the absolute path of the given resource within the repository base
+ * directory, in a platform and file system neutral way (e.g. {@code /C:/repo/file.txt} on Windows).
+ */
+ private URI absoluteLocation(String resource) throws Exception {
+ Path absolute =
+ ((FileTransporter) transporter).getBasePath().resolve(resource).toAbsolutePath();
+ String rawPath = absolute.toString().replace('\\', '/');
+ if (!rawPath.startsWith("/")) {
+ rawPath = "/" + rawPath;
+ }
+ return new URI(null, null, rawPath, null);
+ }
+
void setUp(FS fs) {
try {
fileSystem = fs.name().startsWith("JIMFS") ? Jimfs.newFileSystem() : null;
@@ -300,6 +314,43 @@ public class FileTransporterTest {
}
}
+ @ParameterizedTest
+ @EnumSource(FS.class)
+ void testGet_AbsoluteResourcePathRejected(FS fs) throws Exception {
+ setUp(fs);
+ GetTask task = new GetTask(absoluteLocation("file.txt"));
+ assertThrows(IllegalArgumentException.class, () -> transporter.get(task));
+ }
+
+ @ParameterizedTest
+ @EnumSource(FS.class)
+ void testGet_ParentReferenceRejected(FS fs) {
+ setUp(fs);
+ assertThrows(IllegalArgumentException.class, () -> transporter.get(new GetTask(URI.create("../file.txt"))));
+ }
+
+ @ParameterizedTest
+ @EnumSource(FS.class)
+ void testGet_BareParentDirRejected(FS fs) {
+ setUp(fs);
+ assertThrows(IllegalArgumentException.class, () -> transporter.get(new GetTask(URI.create(".."))));
+ }
+
+ @ParameterizedTest
+ @EnumSource(FS.class)
+ void testGet_NestedParentReferenceRejected(FS fs) {
+ setUp(fs);
+ assertThrows(
+ IllegalArgumentException.class, () -> transporter.get(new GetTask(URI.create("a/../../file.txt"))));
+ }
+
+ @ParameterizedTest
+ @EnumSource(FS.class)
+ void testPeek_ParentReferenceRejected(FS fs) {
+ setUp(fs);
+ assertThrows(IllegalArgumentException.class, () -> transporter.peek(new PeekTask(URI.create("../file.txt"))));
+ }
+
@ParameterizedTest
@EnumSource(FS.class)
void testGet_Closed(FS fs) throws Exception {
@@ -449,6 +500,38 @@ public class FileTransporterTest {
}
}
+ @ParameterizedTest
+ @EnumSource(FS.class)
+ void testPut_AbsoluteResourcePathRejected(FS fs) throws Exception {
+ assumeTrue(fs.writable);
+ setUp(fs);
+ PutTask task = new PutTask(absoluteLocation("absolute-upload.txt")).setDataString("upload");
+ assertThrows(IllegalArgumentException.class, () -> transporter.put(task));
+ assertFalse(Files.exists(repoDir.resolve("absolute-upload.txt")));
+ }
+
+ @ParameterizedTest
+ @EnumSource(FS.class)
+ void testPut_ParentReferenceRejected(FS fs) throws Exception {
+ assumeTrue(fs.writable);
+ setUp(fs);
+ PutTask task = new PutTask(URI.create("../sibling.txt")).setDataString("upload");
+ assertThrows(IllegalArgumentException.class, () -> transporter.put(task));
+ Path base = ((FileTransporter) transporter).getBasePath();
+ assertFalse(Files.exists(base.getParent().resolve("sibling.txt")));
+ }
+
+ @ParameterizedTest
+ @EnumSource(FS.class)
+ void testPut_NestedParentReferenceRejected(FS fs) throws Exception {
+ assumeTrue(fs.writable);
+ setUp(fs);
+ PutTask task = new PutTask(URI.create("a/../../sibling.txt")).setDataString("upload");
+ assertThrows(IllegalArgumentException.class, () -> transporter.put(task));
+ Path base = ((FileTransporter) transporter).getBasePath();
+ assertFalse(Files.exists(base.getParent().resolve("sibling.txt")));
+ }
+
@ParameterizedTest
@EnumSource(FS.class)
void testPut_Closed(FS fs) throws Exception {