{"record":{"id":"378c8d9923a08a61","repo":"apple/pkl","slug":"resourcepastrootdir-modulepastrootdir","errorCode":"resourcePastRootDir|modulePastRootDir","errorMessage":"resourcePastRootDir|modulePastRootDir","messagePattern":"resourcePastRootDir\\|modulePastRootDir","errorType":"error_code","errorClass":"SecurityManagerException","httpStatus":null,"severity":"error","filePath":"pkl-core/src/main/java/org/pkl/core/SecurityManagers.java","lineNumber":189,"sourceCode":"        throw new SecurityManagerException(message);\n      }\n    }\n\n    @Override\n    public @Nullable Path resolveSecurePath(URI uri, boolean isResource)\n        throws SecurityManagerException, IOException {\n      if (rootDir == null\n          || !uri.isAbsolute()\n          || !uri.getScheme().equals(\"file\")\n          || (uri.getAuthority() != null && !uri.getAuthority().isEmpty())) {\n        return null;\n      }\n      var path = Path.of(uri);\n      var realPath = path.toRealPath();\n      if (!realPath.startsWith(rootDir)) {\n        var errorMessageKey = isResource ? \"resourcePastRootDir\" : \"modulePastRootDir\";\n        var message = ErrorMessages.create(errorMessageKey, uri, rootDir);\n        throw new SecurityManagerException(message);\n      }\n      return realPath;\n    }\n\n    private @Nullable Path normalizePath(@Nullable Path path) {\n      if (path == null) {\n        return null;\n      }\n      try {\n        if (Files.exists(path)) {\n          return path.toRealPath();\n        }\n        return path.toAbsolutePath();\n      } catch (IOException e) {\n        throw new UncheckedIOException(e);\n      }\n    }\n","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-core/src/main/java/org/pkl/core/SecurityManagers.java#L171-L207","documentation":"When resolving file/resource URIs, the security manager canonicalizes the target path with toRealPath (following symlinks) and rejects it if it escapes the configured root directory. The error key is `resourcePastRootDir` for resources and `modulePastRootDir` for modules, guarding against path-traversal outside the sandbox root.","triggerScenarios":"Calling resolveSecurePath with a URI whose real path does not start with rootDir — e.g. `../` traversal in a path, or a symlink pointing outside the root — during module or resource loading.","commonSituations":"Symlinked module files pointing to locations outside the project root; paths containing `..` segments that resolve outside root; moving/renaming the root directory so previously valid paths now resolve elsewhere.","solutions":["Keep modules/resources physically inside the configured root directory (copy or move them in)","Remove or re-point symlinks that escape the root","Correct the URI to a path within rootDir instead of using traversal segments"],"exampleFix":"// before\nimport \"../shared/config.pkl\"\n// after (within root)\nimport \"shared/config.pkl\"","handlingStrategy":"validation","validationCode":"java.nio.file.Path target = java.nio.file.Path.of(uri).toRealPath();\nif (!target.startsWith(rootDir)) throw new IllegalArgumentException(\"path escapes root: \" + uri);","typeGuard":null,"tryCatchPattern":"try {\n  Path real = resolveSecurePath(uri, isResource);\n} catch (SecurityManagerException e) {\n  // remap the URI to a path inside rootDir or copy the file into root\n}","preventionTips":["Avoid `..` segments and out-of-root symlinks in module/resource paths","Keep all modules and resources within the configured root directory","Re-check paths after restructuring directories or changing rootDir"],"tags":["security","path-traversal","pkl","filesystem"],"backgroundTag":"path-traversal-blocked","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}