This is an automated email from the ASF dual-hosted git repository.

slachiewicz pushed a commit to branch agent/pr308-on-master
in repository 
https://gitbox.apache.org/repos/asf/maven-remote-resources-plugin.git

commit ea0cc5be1b7ee8b5aaeb430e32656efb53612a0a
Author: Efe Gökdemir <[email protected]>
AuthorDate: Sat Sep 26 11:42:12 2026 +0300

    Fix remote resource path traversal
    
    Signed-off-by: Efe Gökdemir <[email protected]>
---
 .../remote/AbstractProcessRemoteResourcesMojo.java | 16 +++++++++++++++-
 .../resources/remote/RemoteResourcesMojoTest.java  | 22 ++++++++++++++++++++++
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git 
a/src/main/java/org/apache/maven/plugin/resources/remote/AbstractProcessRemoteResourcesMojo.java
 
b/src/main/java/org/apache/maven/plugin/resources/remote/AbstractProcessRemoteResourcesMojo.java
index 8367976..f274498 100644
--- 
a/src/main/java/org/apache/maven/plugin/resources/remote/AbstractProcessRemoteResourcesMojo.java
+++ 
b/src/main/java/org/apache/maven/plugin/resources/remote/AbstractProcessRemoteResourcesMojo.java
@@ -973,7 +973,7 @@ public abstract class AbstractProcessRemoteResourcesMojo 
extends AbstractMojo {
 
                 // Don't overwrite resource that are already being provided.
 
-                File outputFile = new File(outputDirectory, projectResource);
+                File outputFile = resolveOutputFile(outputDirectory, 
projectResource);
 
                 FileUtils.mkdir(outputFile.getParentFile().getAbsolutePath());
 
@@ -1031,6 +1031,20 @@ public abstract class AbstractProcessRemoteResourcesMojo 
extends AbstractMojo {
         }
     }
 
+    static File resolveOutputFile(File outputDirectory, String resourceName)
+            throws IOException, MojoExecutionException {
+        if (new File(resourceName).isAbsolute()) {
+            throw new MojoExecutionException("Remote resource is outside the 
output directory: " + resourceName);
+        }
+        File canonicalOutputDirectory = outputDirectory.getCanonicalFile();
+        File outputFile = new File(outputDirectory, 
resourceName).getCanonicalFile();
+        if (outputFile.equals(canonicalOutputDirectory)
+                || 
!outputFile.toPath().startsWith(canonicalOutputDirectory.toPath())) {
+            throw new MojoExecutionException("Remote resource is outside the 
output directory: " + resourceName);
+        }
+        return outputFile;
+    }
+
     private void verifyRequiredProperties(RemoteResourcesBundle bundle, URL 
url) throws MojoExecutionException {
         if (bundle.getRequiredProjectProperties() == null
                 || bundle.getRequiredProjectProperties().isEmpty()) {
diff --git 
a/src/test/java/org/apache/maven/plugin/resources/remote/RemoteResourcesMojoTest.java
 
b/src/test/java/org/apache/maven/plugin/resources/remote/RemoteResourcesMojoTest.java
index 78d895e..32d2cc1 100644
--- 
a/src/test/java/org/apache/maven/plugin/resources/remote/RemoteResourcesMojoTest.java
+++ 
b/src/test/java/org/apache/maven/plugin/resources/remote/RemoteResourcesMojoTest.java
@@ -89,6 +89,28 @@ public class RemoteResourcesMojoTest extends 
AbstractMojoTestCase {
         mojo.execute();
     }
 
+    public void testRemoteResourceCannotEscapeOutputDirectory() throws 
Exception {
+        File outputDirectory = new File("target/remote-resource-output");
+
+        try {
+            
AbstractProcessRemoteResourcesMojo.resolveOutputFile(outputDirectory, 
"../outside.txt");
+            fail("expected a resource outside the output directory to be 
rejected");
+        } catch (MojoExecutionException e) {
+            assertTrue(e.getMessage().contains("outside the output 
directory"));
+        }
+
+        try {
+            AbstractProcessRemoteResourcesMojo.resolveOutputFile(
+                    outputDirectory, new File(outputDirectory.getParentFile(), 
"absolute.txt").getAbsolutePath());
+            fail("expected an absolute resource path outside the output 
directory to be rejected");
+        } catch (MojoExecutionException e) {
+            assertTrue(e.getMessage().contains("outside the output 
directory"));
+        }
+
+        File outputFile = 
AbstractProcessRemoteResourcesMojo.resolveOutputFile(outputDirectory, 
"nested/resource.txt");
+        assertEquals(new File(outputDirectory, 
"nested/resource.txt").getCanonicalFile(), outputFile);
+    }
+
     public void testConfigureLocatorRequiresProjectFile() throws Exception {
         final MavenProjectResourcesStub project = 
createTestProject("default-null-pom");
         final ProcessRemoteResourcesMojo mojo = 
lookupProcessMojoWithDefaultSettings(project);

Reply via email to