conductor-oss/conductor · critical · DocumentAccessDeniedException

Access denied: path traversal sequences are not allowed

Error message

Access denied: path traversal sequences are not allowed

What it means

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).

Source

Thrown at ai/src/main/java/org/conductoross/conductor/ai/document/DocumentAccessPolicy.java:384

                                + addr.getHostAddress()
                                + ")");
            }
        } catch (DocumentAccessDeniedException e) {
            throw e;
        } catch (Exception e) {
            // DNS resolution failure — allow the request to proceed and fail naturally
            log.debug(
                    "Could not resolve host '{}' for access policy check: {}",
                    host,
                    e.getMessage());
        }
    }

    private void checkPathTraversal(String normalizedPath) {
        if (normalizedPath.contains("/../")
                || normalizedPath.endsWith("/..")
                || normalizedPath.startsWith("../")) {
            throw new DocumentAccessDeniedException(
                    "Access denied: path traversal sequences are not allowed");
        }
    }

    /**
     * Only local filesystem paths under the effective allowed directories (file-storage parentDir +
     * any additional configured directories) are permitted. HTTP/HTTPS URLs are not subject to this
     * check.
     */
    private void checkAllowedDirectories(String originalLocation, String normalizedPath) {
        List<String> dirs = effectiveAllowedDirectories;
        if (dirs == null || dirs.isEmpty()) {
            return;
        }
        // Only apply to local filesystem paths, not HTTP URLs
        if (originalLocation.startsWith("http://") || originalLocation.startsWith("https://")) {
            return;
        }

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Sanitize/reject '..' in any path component before passing it to the loader.
  2. Construct paths with Path.resolve against an allowed root and verify the result still startsWith the root after normalization.
  3. Never concatenate untrusted input directly into a filesystem path.

Example fix

// before
Path p = Path.of(baseDir, userInput); // userInput may contain ..
// after
Path root = Path.of(baseDir).normalize();
Path p = root.resolve(userInput).normalize();
if (!p.startsWith(root)) throw new IllegalArgumentException("outside allowed root");
Defensive patterns

Strategy: validation

Validate before calling

// Build paths safely: resolve under a root and confirm containment after normalization
java.nio.file.Path root = java.nio.file.Path.of(baseDir).normalize();
java.nio.file.Path resolved = root.resolve(userInput).normalize();
if (!resolved.startsWith(root) || resolved.toString().contains("/../")) {
    throw new IllegalArgumentException("Refusing path outside allowed root: " + userInput);
}

Try / catch

try {
    loader.download(path);
} catch (SecurityException e) {
    // traversal attempt — do not relax; reject and log the input as hostile
    throw new SecurityException("Path traversal blocked: " + path, e);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/01864e01ced69795. Report an issue: GitHub.