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

  1. Use paths that physically reside under the project root directory dev mode was started in.
  2. Start dev mode from the canonical project directory so rootPath matches where files actually live.
  3. Replace symlinks that point outside the project with real files, or point the URI at the real in-project location.
  4. 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

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


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/fdfc5d78f15d25ad. Report an issue: GitHub.