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);
