kestra-io/kestra · error · SecurityException
The path {} is not authorized. Only files inside the working
Error message
The path {} is not authorized. Only files inside the working directory are allowed by default, other path must be allowed either globally inside the Kestra configuration using the `kestra.local-files.allowed-paths` property, or by plugin using the `allowed-paths` plugin configuration. What it means
Thrown by `RunContextLocalPath.checkPath` (the variant that has a `RunContext`) when a resolved real path is neither inside the task's working directory, nor in the globally-configured allowed paths, nor in the plugin's `allowed-paths` configuration. This is a security control preventing tasks from reading arbitrary host files. Thrown as `SecurityException`. `toRealPath()` is applied first, so symlink traversal is also caught.
Source
Thrown at core/src/main/java/io/kestra/core/runners/LocalPathFactory.java:118
private final List<Path> globalAllowedPaths;
private final RunContext runContext;
RunContextLocalPath(List<Path> globalAllowedPaths, RunContext runContext) {
this.globalAllowedPaths = globalAllowedPaths;
this.runContext = runContext;
}
@Override
@SuppressWarnings("unchecked")
protected Path checkPath(URI uri) throws IOException {
Path workingDirectory = runContext.workingDir().path(true);
Path path = Path.of(uri).toRealPath(); // toRealPath() will protect about path traversal issues
// We allow working directory or globally allowed path
if (!path.startsWith(workingDirectory) && globalAllowedPaths.stream().noneMatch(path::startsWith)) {
// if not globally allowed, we check if it's allowed for this specific plugin
List<String> pluginAllowedPaths = (List<String>) runContext.pluginConfiguration("allowed-paths").orElse(Collections.emptyList());
if (pluginAllowedPaths.stream().map(LocalPathFactory::resolveAllowedPath).noneMatch(path::startsWith)) {
throw new SecurityException(
"The path " + path + " is not authorized. " +
"Only files inside the working directory are allowed by default, other path must be allowed either globally inside the Kestra configuration using the `"
+ LocalPath.ALLOWED_PATHS_CONFIG + "` property, " +
"or by plugin using the `allowed-paths` plugin configuration."
);
}
}
return path;
}
}
static class DefaultLocalPath extends AbstractLocalPath {
private final List<Path> globalAllowedPaths;
DefaultLocalPath(List<Path> globalAllowedPaths) {
this.globalAllowedPaths = globalAllowedPaths;
}View on GitHub (pinned to 823fada927)
Solutions
- Copy the needed file into the task's working directory and reference it relatively.
- Add the directory to `kestra.local-files.allowed-paths` in the Kestra configuration (server-wide).
- Add the directory to the plugin's `allowed-paths` plugin configuration (task-scoped).
- Avoid absolute host paths; use internal storage (`kestra://`) for cross-task file passing.
Example fix
# before — task reads a host file outside the working dir
- id: read
type: io.kestra.plugin.core.log.Log
message: "{{ read('file:///etc/hosts') }}"
# after — allow the path via plugin config or copy into working dir
# option A: plugin-level allowed-paths
- id: read
type: io.kestra.plugin.scripts.shell.Commands
allowed-paths:
- /etc
commands:
- cat /etc/hosts Defensive patterns
Strategy: validation
Validate before calling
Path workingDir = runContext.workingDir().path(true);
Path real = Path.of(uri).toRealPath();
if (!real.startsWith(workingDir)
&& globalAllowedPaths.stream().noneMatch(real::startsWith)
&& pluginAllowedPaths.stream().map(LocalPathFactory::resolveAllowedPath).noneMatch(real::startsWith)) {
throw new SecurityException("Path not allowed: " + real);
} Try / catch
try {
return localPath.get(uri);
} catch (SecurityException e) {
runContext.logger().error("Access denied to {}: configure allowed-paths or use internal storage.", uri);
throw e;
} Prevention
- Keep task file IO inside the working directory; use `runContext.storage()` for cross-task files.
- Configure `kestra.local-files.allowed-paths` or plugin `allowed-paths` for genuine host-file needs.
- Never pass untrusted absolute paths into file-reading tasks.
When it happens
Trigger: A task attempts to read/write a host file outside its working directory via a `file://` URI, and neither `kestra.local-files.allowed-paths` nor the plugin's `allowed-paths` lists that directory. Common with the `LocalFiles` task or plugins that resolve `file://` URIs.
Common situations: Reading `/etc/...`, `/tmp/shared/...`, or an absolute host path from a task; deploying to a stricter environment where previously-allowed paths were removed; symlinking outside the working dir; a path that worked locally fails in a containerized worker with a different filesystem layout.
Related errors
- The path {} is not authorized. Path must be allowed either g
- The path to resolve must be a relative path inside the curre
- The file:// protocol has been disabled inside the Kestra con
- Path must not contain '../'
- The URI {} is not in the configured allowed list (kestra.tas
AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14).
Data as JSON: /api/errors/2e5747f94c2ed385.
Report an issue: GitHub.