quarkusio/quarkus · error · SecurityException
Path is outside the project root: ${resolved}
Error message
Path is outside the project root: ${resolved} What it means
After successfully parsing and canonicalizing the client-supplied URI, resolveWorkspacePath verifies the resolved path stays inside the canonical project root using resolved.startsWith(root). If the path escapes the root (including via .. segments or symlinks that resolve elsewhere), a SecurityException is thrown. This prevents Dev UI workspace actions from touching files outside the user's project.
Source
Thrown at extensions/devui/deployment/src/main/java/io/quarkus/devui/deployment/menu/WorkspaceProcessor.java:367
* path (including ones using {@code ..} or symlinks) that resolves outside the root is rejected.
*/
private static Path resolveWorkspacePath(Path rootPath, String uriString) {
if (uriString == null) {
throw new SecurityException("No workspace path provided");
}
Path root;
Path resolved;
try {
root = toCanonicalPath(rootPath);
resolved = toCanonicalPath(Paths.get(URI.create(uriString)));
} catch (IllegalArgumentException | FileSystemNotFoundException | IOException e) {
// Malformed URI, a non-file scheme or a path we cannot safely canonicalize: reject it.
throw new SecurityException("Invalid workspace path: " + uriString);
}
if (!resolved.startsWith(root)) {
throw new SecurityException("Path is outside the project root: " + resolved);
}
return resolved;
}
/**
* Normalize a path to an absolute form with symlinks resolved. The file itself may not exist
* yet (e.g. when creating a new workspace item), so symlinks are only resolved on the nearest
* existing ancestor to prevent a symlinked directory from escaping the root. If the real path
* cannot be determined the {@link IOException} is propagated so the caller can fail closed
* rather than fall back to an unresolved (potentially escaping) path.
*/
private static Path toCanonicalPath(Path path) throws IOException {
Path absolute = path.toAbsolutePath().normalize();
Path existing = absolute;
while (existing != null && !Files.exists(existing)) {
existing = existing.getParent();
}
if (existing == null) {View on GitHub (pinned to e1c734241f)
Solutions
- Use paths that physically reside under the project root directory dev mode was started in.
- Start dev mode from the canonical project directory so rootPath matches where files actually live.
- Replace symlinks that point outside the project with real files, or point the URI at the real in-project location.
- Normalize the URI first (resolve .. segments against the project root) client-side before sending.
Example fix
// before String uri = "file:///etc/application.properties"; // outside project // after String uri = "file:///home/user/project/src/main/resources/application.properties";
Defensive patterns
Strategy: validation
Validate before calling
Path root = Paths.get(projectDir).toRealPath();
Path resolved = Paths.get(URI.create(uriString)).toRealPath();
if (!resolved.startsWith(root)) {
throw new IllegalArgumentException("Refusing: path escapes project root");
} Try / catch
try { Path p = resolveWorkspacePath(root, uriString); ... }
catch (SecurityException e) {
if (e.getMessage().startsWith("Path is outside the project root")) {
ui.showError("Choose a file inside the project directory");
} else throw e;
} Prevention
- Start dev mode from the canonical (non-symlinked) project directory
- Resolve '..' segments against the project root client-side
- Avoid symlinks that point outside the project tree
When it happens
Trigger: Passing a file: URI that resolves outside the project directory — absolute paths elsewhere on disk, '..' traversal after resolution, or a symlink inside the project pointing to a location outside the root.
Common situations: Project checked out via a symlinked directory (IDE workspace path differs from canonical root); sending home-directory paths instead of project-relative ones; symlinks in src/ pointing to shared folders; attempting to edit config files outside the project.
Related errors
- No workspace path provided
- Invalid workspace path: ${uriString}
- Path is not below the application root: <file>
- Path leaves the application root: <file>
- Invalid static resource path '<path>'. Paths must not contai
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/fdfc5d78f15d25ad.
Report an issue: GitHub.