{"record":{"id":"01864e01ced69795","repo":"conductor-oss/conductor","slug":"access-denied-path-traversal-sequences-are-not-al","errorCode":null,"errorMessage":"Access denied: path traversal sequences are not allowed","messagePattern":"Access denied: path traversal sequences are not allowed","errorType":"validation","errorClass":"DocumentAccessDeniedException","httpStatus":null,"severity":"critical","filePath":"ai/src/main/java/org/conductoross/conductor/ai/document/DocumentAccessPolicy.java","lineNumber":384,"sourceCode":"                                + addr.getHostAddress()\n                                + \")\");\n            }\n        } catch (DocumentAccessDeniedException e) {\n            throw e;\n        } catch (Exception e) {\n            // DNS resolution failure — allow the request to proceed and fail naturally\n            log.debug(\n                    \"Could not resolve host '{}' for access policy check: {}\",\n                    host,\n                    e.getMessage());\n        }\n    }\n\n    private void checkPathTraversal(String normalizedPath) {\n        if (normalizedPath.contains(\"/../\")\n                || normalizedPath.endsWith(\"/..\")\n                || normalizedPath.startsWith(\"../\")) {\n            throw new DocumentAccessDeniedException(\n                    \"Access denied: path traversal sequences are not allowed\");\n        }\n    }\n\n    /**\n     * Only local filesystem paths under the effective allowed directories (file-storage parentDir +\n     * any additional configured directories) are permitted. HTTP/HTTPS URLs are not subject to this\n     * check.\n     */\n    private void checkAllowedDirectories(String originalLocation, String normalizedPath) {\n        List<String> dirs = effectiveAllowedDirectories;\n        if (dirs == null || dirs.isEmpty()) {\n            return;\n        }\n        // Only apply to local filesystem paths, not HTTP URLs\n        if (originalLocation.startsWith(\"http://\") || originalLocation.startsWith(\"https://\")) {\n            return;\n        }","sourceCodeStart":366,"sourceCodeEnd":402,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/ai/src/main/java/org/conductoross/conductor/ai/document/DocumentAccessPolicy.java#L366-L402","documentation":"Thrown by DocumentAccessPolicy.checkPathTraversal when the normalized local path contains '/../' as a segment, ends with '/..', or starts with '../'. This blocks classic path-traversal attacks even when the base directory is allowed. DocumentAccessDeniedException (SecurityException).","triggerScenarios":"A file location like /data/allowed/../../etc/passwd, /data/allowed/foo/.., or ../../secret is passed to a document loader or upload. The check runs on the Path.of(...).normalize() result, so redundant segments collapse before the test.","commonSituations":"User/LLM-controlled filenames concatenated to a base directory without sanitization; a path built from query params that allows '..'; attempts to escape a sandboxed document root.","solutions":["Sanitize/reject '..' in any path component before passing it to the loader.","Construct paths with Path.resolve against an allowed root and verify the result still startsWith the root after normalization.","Never concatenate untrusted input directly into a filesystem path."],"exampleFix":"// before\nPath p = Path.of(baseDir, userInput); // userInput may contain ..\n// after\nPath root = Path.of(baseDir).normalize();\nPath p = root.resolve(userInput).normalize();\nif (!p.startsWith(root)) throw new IllegalArgumentException(\"outside allowed root\");","handlingStrategy":"validation","validationCode":"// Build paths safely: resolve under a root and confirm containment after normalization\njava.nio.file.Path root = java.nio.file.Path.of(baseDir).normalize();\njava.nio.file.Path resolved = root.resolve(userInput).normalize();\nif (!resolved.startsWith(root) || resolved.toString().contains(\"/../\")) {\n    throw new IllegalArgumentException(\"Refusing path outside allowed root: \" + userInput);\n}","typeGuard":null,"tryCatchPattern":"try {\n    loader.download(path);\n} catch (SecurityException e) {\n    // traversal attempt — do not relax; reject and log the input as hostile\n    throw new SecurityException(\"Path traversal blocked: \" + path, e);\n}","preventionTips":["Never concatenate untrusted input into a filesystem path.","Always resolve against a fixed root and verify startsWith after normalize().","Reject '..' segments in any user/LLM-supplied filename."],"tags":["security","path-traversal","access-control","document-loader","injection"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}