{"id":"4d628fa377476957","repo":"apache/kafka","slug":"path-normalisedpath-is-not-absolute","errorCode":null,"errorMessage":"Path normalisedPath is not absolute","messagePattern":"Path normalisedPath is not absolute","errorType":"validation","errorClass":"ConfigException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/config/internals/AllowedPaths.java","lineNumber":49,"sourceCode":"\n    /**\n     * Constructs AllowedPaths with a list of Paths retrieved from {@code configValue}.\n     * @param configValue {@code allowed.paths} config value which is a string containing comma separated list of paths\n     * @throws ConfigException if any of the given paths is not absolute or does not exist.\n     */\n    public AllowedPaths(String configValue) {\n        this.allowedPaths = getAllowedPaths(configValue);\n    }\n\n    private List<Path> getAllowedPaths(String configValue) {\n        if (configValue != null && !configValue.isEmpty()) {\n            List<Path> allowedPaths = new ArrayList<>();\n\n            Arrays.stream(configValue.split(\",\")).forEach(b -> {\n                Path normalisedPath = Paths.get(b).normalize();\n\n                if (!normalisedPath.isAbsolute()) {\n                    throw new ConfigException(\"Path \" + normalisedPath + \" is not absolute\");\n                } else if (!Files.exists(normalisedPath)) {\n                    throw new ConfigException(\"Path \" + normalisedPath + \" does not exist\");\n                } else {\n                    try {\n                        allowedPaths.add(normalisedPath.toRealPath());\n                    } catch (IOException e) {\n                        throw new ConfigException(\"Path \" + normalisedPath + \" could not be resolved\", e);\n                    }\n                }\n            });\n\n            return allowedPaths;\n        }\n\n        return null;\n    }\n\n    /**","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/config/internals/AllowedPaths.java#L31-L67","documentation":"Thrown by AllowedPaths.getAllowedPaths() when parsing a comma-separated allowed.paths config value containing a relative path. The code calls Paths.get(b).normalize() then checks isAbsolute(); a non-absolute path is rejected with ConfigException. Kafka enforces absolute paths so that DirectoryConfigProvider/FileConfigProvider can safely resolve real paths and prevent traversal attacks.","triggerScenarios":"Constructing new AllowedPaths(configValue) (called from DirectoryConfigProvider.configure or FileConfigProvider.configure) with allowed.paths containing a relative path like \"config/secrets\" instead of \"/etc/kafka/secrets\".","commonSituations":"Running a connector or client that uses externalized config providers (DirectoryConfigProvider/FileConfigProvider) and supplying allowed.paths with a relative path. Porting a config from a dev environment where the working directory was implied. Mixing Windows-style or tilde-prefixed paths (~) which are not absolute to Paths.get.","solutions":["Change every entry in allowed.paths to an absolute path (e.g. /etc/kafka/secrets) and restart the client/broker.","Verify with Paths.get(value).isAbsolute() in a test or REPL before deploying.","Remove the offending entry from allowed.paths or unset the property entirely to allow all paths (only if your security posture permits)."],"exampleFix":"// before\nallowed.paths=config/secrets,../shared/secrets\n\n// after\nallowed.paths=/etc/kafka/secrets,/opt/kafka/shared/secrets","handlingStrategy":"validation","validationCode":"// Before constructing AllowedPaths or setting allowed.paths:\nfor (String raw : configValue.split(\",\")) {\n    Path p = Paths.get(raw.trim()).normalize();\n    if (!p.isAbsolute()) {\n        throw new IllegalArgumentException(\n            \"allowed.paths entry '\" + raw + \"' must be absolute, got \" + p);\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    AllowedPaths ap = new AllowedPaths(configValue);\n} catch (ConfigException e) {\n    if (e.getMessage().endsWith(\"is not absolute\")) {\n        // resolve against a known base dir, or fail config load\n    } else { throw e; }\n}","preventionTips":["Always pass absolute paths in the allowed.paths config; never rely on the JVM's current working directory.","Resolve user-supplied relative paths against an explicit base with base.resolve(raw).toAbsolutePath().normalize() before feeding to allowed.paths.","Add a startup self-test that parses allowed.paths so misconfiguration fails fast at boot, not at first external config lookup."],"tags":["config","allowed-paths","security","config-provider"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}