{"record":{"id":"595bea83765b9e50","repo":"quarkusio/quarkus","slug":"path-is-not-below-the-application-root-file","errorCode":null,"errorMessage":"Path is not below the application root: <file>","messagePattern":"Path is not below the application root: <file>","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java","lineNumber":465,"sourceCode":"\n    @Override\n    public void deleteFile(String file) {\n        Path resolve = resolveApplicationPath(file);\n        try {\n            Files.deleteIfExists(resolve);\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private Path resolveApplicationPath(String file) {\n        file = normalizeFile(file);\n        Path normalizedRoot = applicationRoot.toAbsolutePath().normalize();\n        Path relativePath = Path.of(file);\n        Path resolved = normalizedRoot.resolve(relativePath).normalize();\n        if (relativePath.isAbsolute() || resolved.equals(normalizedRoot) || !resolved.startsWith(normalizedRoot)\n                || file.length() >= 2 && file.charAt(1) == ':') {\n            throw new IllegalArgumentException(\"Path is not below the application root: \" + file);\n        }\n        validateExistingPathComponents(normalizedRoot, resolved, file);\n        return resolved;\n    }\n\n    private static void validateExistingPathComponents(Path normalizedRoot, Path resolved, String file) {\n        final Path realRoot;\n        try {\n            realRoot = normalizedRoot.toRealPath();\n        } catch (IOException e) {\n            throw new IllegalArgumentException(\"Unable to validate the application root for remote-dev path: \" + file, e);\n        }\n        Path current = normalizedRoot;\n        for (Path element : normalizedRoot.relativize(resolved)) {\n            current = current.resolve(element);\n            if (Files.isSymbolicLink(current)) {\n                throw new IllegalArgumentException(\"Symbolic links are not allowed in remote-dev paths: \" + file);\n            }","sourceCodeStart":447,"sourceCodeEnd":483,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java#L447-L483","documentation":"resolveApplicationPath validates that a file path sent by a remote dev client resolves strictly inside the application root. If the path is absolute, equals the root, escapes the root (e.g. via ..), or looks like a Windows drive path (second char ':'), it throws this IllegalArgumentException. This is a path-traversal guard for remote dev mode.","triggerScenarios":"Calling updateFile/deleteFile (via resolve) with a path that is absolute (/etc/passwd), contains ../ escaping the root, is exactly the application root, or has a form like C:\\foo.","commonSituations":"Misconfigured remote client sending absolute paths instead of root-relative ones; a buggy client normalizing to absolute paths; an attacker probing the sync endpoint (this error is the guard working).","solutions":["Send paths relative to the application root (e.g. com/example/Foo.class, not /full/path/com/example/Foo.class).","Normalize the client path against its own project root before sending.","Remove any drive-letter prefixes or leading slashes from the sync payload.","If you are not intentionally using remote-dev sync, check that quarkus.live-reload / remote-dev is not exposed unintentionally."],"exampleFix":"// client: before\nremoteClient.send(\"/home/me/app/target/classes/com/App.class\");\n// after\nremoteClient.send(\"com/App.class\"); // relative to application root","handlingStrategy":"validation","validationCode":"String safe(String file) {\n    Path p = Path.of(file);\n    if (p.isAbsolute() || file.contains(\"..\") || (file.length() >= 2 && file.charAt(1) == ':'))\n        throw new IllegalArgumentException(\"must be root-relative: \" + file);\n    return file;\n}","typeGuard":"boolean isSafeRelativePath(String file) {\n    if (file == null || file.isEmpty()) return false;\n    Path p = Path.of(file);\n    return !p.isAbsolute() && !file.contains(\"..\")\n        && !(file.length() >= 2 && file.charAt(1) == ':');\n}","tryCatchPattern":"try {\n    client.sync(path);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Path is not below the application root\")) {\n        log.errorf(\"Client sent non-relative path %s — normalize against project root\", path);\n    } else throw e;\n}","preventionTips":["Always send root-relative paths in remote-dev sync payloads","Normalize client paths against the project root before sending","Never expose the dev-mode sync endpoint publicly"],"tags":["path-traversal","security","remote-dev","validation"],"backgroundTag":"path-escapes-application-root","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}