From 3ef065b6b687f319b1cea67bdcd600a6545c1197 Mon Sep 17 00:00:00 2001 From: Jen Basch Date: Wed, 25 Feb 2026 10:57:01 -0800 Subject: [PATCH] Correct `--root-dir` check to also work for `jar:file:` URIs (#1442) --- .../java/org/pkl/core/SecurityManagers.java | 13 +++-- .../test/kotlin/org/pkl/core/EvaluatorTest.kt | 53 ++++++++++++++++++- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/pkl-core/src/main/java/org/pkl/core/SecurityManagers.java b/pkl-core/src/main/java/org/pkl/core/SecurityManagers.java index e069a6ee..ab631627 100644 --- a/pkl-core/src/main/java/org/pkl/core/SecurityManagers.java +++ b/pkl-core/src/main/java/org/pkl/core/SecurityManagers.java @@ -24,6 +24,7 @@ import java.util.*; import java.util.function.Function; import java.util.regex.Pattern; import org.pkl.core.util.ErrorMessages; +import org.pkl.core.util.IoUtils; import org.pkl.core.util.Nullable; /** A provider for {@link SecurityManager}s. */ @@ -213,13 +214,17 @@ public final class SecurityManagers { } private void checkIsUnderRootDir(URI uri, boolean isResource) throws SecurityManagerException { - if (!uri.isAbsolute()) { - throw new AssertionError("Expected absolute URI but got: " + uri); + // handle jar:file: URIs correctly: + var checkUri = + uri.getScheme().equals("jar") ? IoUtils.createUri(uri.getSchemeSpecificPart()) : uri; + + if (!checkUri.isAbsolute()) { + throw new AssertionError("Expected absolute URI but got: " + checkUri); } - if (rootDir == null || !uri.getScheme().equals("file")) return; + if (rootDir == null || !checkUri.getScheme().equals("file")) return; - var path = Path.of(uri); + var path = Path.of(checkUri); if (Files.exists(path)) { try { path = path.toRealPath(); diff --git a/pkl-core/src/test/kotlin/org/pkl/core/EvaluatorTest.kt b/pkl-core/src/test/kotlin/org/pkl/core/EvaluatorTest.kt index a94a8fe2..4e755ff1 100644 --- a/pkl-core/src/test/kotlin/org/pkl/core/EvaluatorTest.kt +++ b/pkl-core/src/test/kotlin/org/pkl/core/EvaluatorTest.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved. + * Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -283,6 +283,57 @@ class EvaluatorTest { ) } + @Test + fun `cannot import module from zip filesystem located outside root dir`( + @TempDir tempDir: Path, + @TempDir forbidden: Path, + ) { + val evaluator = + with(EvaluatorBuilder.preconfigured()) { + rootDir = tempDir + build() + } + + val zipFile = createModulesZip(forbidden) + + val module = + tempDir + .resolve("test.pkl") + .writeString("res = import(\"jar:${zipFile.toUri()}!/foo/var/module1.pkl\")") + + val e = assertThrows { evaluator.evaluate(path(module)) } + assertThat(e) + .hasMessageContaining( + "Refusing to load module `jar:${zipFile.toUri()}!/foo/var/module1.pkl` because it is not within the root directory (`--root-dir`)." + ) + } + + @Test + fun `cannot read resource from zip filesystem located outside root dir`( + @TempDir tempDir: Path, + @TempDir forbidden: Path, + ) { + val evaluator = + with(EvaluatorBuilder.preconfigured()) { + rootDir = tempDir + allowedResources.add(Pattern.compile("jar:file:")) + build() + } + + val zipFile = createModulesZip(forbidden) + + val module = + tempDir + .resolve("test.pkl") + .writeString("res = read(\"jar:${zipFile.toUri()}!/foo/var/module1.pkl\")") + + val e = assertThrows { evaluator.evaluate(path(module)) } + assertThat(e) + .hasMessageContaining( + "Refusing to read resource `jar:${zipFile.toUri()}!/foo/var/module1.pkl` because it is not within the root directory (`--root-dir`)." + ) + } + @Test fun `cannot read resource located outside root dir`(@TempDir tempDir: Path) { val evaluator =