{"record":{"id":"2e5747f94c2ed385","repo":"kestra-io/kestra","slug":"the-path-is-not-authorized-only-files-inside-t","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"exception","errorClass":"SecurityException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/kestra/core/runners/LocalPathFactory.java","lineNumber":118,"sourceCode":"        private final List<Path> globalAllowedPaths;\n        private final RunContext runContext;\n\n        RunContextLocalPath(List<Path> globalAllowedPaths, RunContext runContext) {\n            this.globalAllowedPaths = globalAllowedPaths;\n            this.runContext = runContext;\n        }\n\n        @Override\n        @SuppressWarnings(\"unchecked\")\n        protected Path checkPath(URI uri) throws IOException {\n            Path workingDirectory = runContext.workingDir().path(true);\n            Path path = Path.of(uri).toRealPath(); // toRealPath() will protect about path traversal issues\n            // We allow working directory or globally allowed path\n            if (!path.startsWith(workingDirectory) && globalAllowedPaths.stream().noneMatch(path::startsWith)) {\n                // if not globally allowed, we check if it's allowed for this specific plugin\n                List<String> pluginAllowedPaths = (List<String>) runContext.pluginConfiguration(\"allowed-paths\").orElse(Collections.emptyList());\n                if (pluginAllowedPaths.stream().map(LocalPathFactory::resolveAllowedPath).noneMatch(path::startsWith)) {\n                    throw new SecurityException(\n                        \"The path \" + path + \" is not authorized. \" +\n                            \"Only files inside the working directory are allowed by default, other path must be allowed either globally inside the Kestra configuration using the `\"\n                            + LocalPath.ALLOWED_PATHS_CONFIG + \"` property, \" +\n                            \"or by plugin using the `allowed-paths` plugin configuration.\"\n                    );\n                }\n            }\n\n            return path;\n        }\n    }\n\n    static class DefaultLocalPath extends AbstractLocalPath {\n        private final List<Path> globalAllowedPaths;\n\n        DefaultLocalPath(List<Path> globalAllowedPaths) {\n            this.globalAllowedPaths = globalAllowedPaths;\n        }","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/kestra-io/kestra/blob/823fada9274c4f9c251ea0a516460a4f7d958032/core/src/main/java/io/kestra/core/runners/LocalPathFactory.java#L100-L136","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before — task reads a host file outside the working dir\n- id: read\n  type: io.kestra.plugin.core.log.Log\n  message: \"{{ read('file:///etc/hosts') }}\"\n\n# after — allow the path via plugin config or copy into working dir\n# option A: plugin-level allowed-paths\n- id: read\n  type: io.kestra.plugin.scripts.shell.Commands\n  allowed-paths:\n    - /etc\n  commands:\n    - cat /etc/hosts","handlingStrategy":"validation","validationCode":"Path workingDir = runContext.workingDir().path(true);\nPath real = Path.of(uri).toRealPath();\nif (!real.startsWith(workingDir)\n    && globalAllowedPaths.stream().noneMatch(real::startsWith)\n    && pluginAllowedPaths.stream().map(LocalPathFactory::resolveAllowedPath).noneMatch(real::startsWith)) {\n    throw new SecurityException(\"Path not allowed: \" + real);\n}","typeGuard":null,"tryCatchPattern":"try {\n    return localPath.get(uri);\n} catch (SecurityException e) {\n    runContext.logger().error(\"Access denied to {}: configure allowed-paths or use internal storage.\", uri);\n    throw e;\n}","preventionTips":["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."],"tags":["security","local-files","path-traversal","authorization"],"backgroundTag":null,"analyzedSha":"823fada9274c4f9c251ea0a516460a4f7d958032","analyzedAt":"2026-08-14T06:15:17.947Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}