conductor-oss/conductor · critical · DocumentAccessDeniedException

Access denied: path matches blocked prefix '{prefix}'

Error message

Access denied: path matches blocked prefix '{prefix}'

What it means

Thrown by DocumentAccessPolicy.checkBlockedPaths when a normalized local path starts with one of the built-in DEFAULT_BLOCKED_PATH_PREFIXES (e.g. /etc/shadow, ~/.ssh/, ~/.aws/, /var/run/secrets/). This is a hardcoded security denylist protecting against prompt-injection-driven exfiltration of OS credentials, cloud keys, and secret mounts. It is a DocumentAccessDeniedException (extends SecurityException).

Source

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

    public void validateAccess(String location) {
        if (disabled) {
            return;
        }

        String normalized = normalizeLocation(location);

        checkBlockedPaths(normalized);
        checkBlockedFileNames(normalized);
        checkBlockedHosts(location);
        checkPathTraversal(normalized);
        checkAllowedDirectories(location, normalized);
    }

    private void checkBlockedPaths(String normalizedPath) {
        for (String prefix : DEFAULT_BLOCKED_PATH_PREFIXES) {
            String expandedPrefix = expandHome(prefix);
            if (normalizedPath.startsWith(expandedPrefix)) {
                throw new DocumentAccessDeniedException(
                        "Access denied: path matches blocked prefix '" + prefix + "'");
            }
        }
        for (String prefix : blockedPathPrefixes) {
            String expandedPrefix = expandHome(prefix);
            if (normalizedPath.startsWith(expandedPrefix)) {
                throw new DocumentAccessDeniedException(
                        "Access denied: path matches blocked prefix '" + prefix + "'");
            }
        }
    }

    private void checkBlockedFileNames(String normalizedPath) {
        String fileName = extractFileName(normalizedPath);
        if (fileName == null || fileName.isEmpty()) {
            return;
        }
        String lowerFileName = fileName.toLowerCase();

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Move the file you legitimately need into a directory under the allowed list (file-storage parentDir or an allowed-directories entry) and reference it there.
  2. If access is genuinely required and you accept the risk, the built-in list cannot be edited, so you must not place the file under a blocked prefix.
  3. Double-check the path is not being constructed from user/LLM-controlled input that should be sandboxed instead.

Example fix

// before
loader.download("/root/.aws/credentials")
// after — read from an allowed, non-sensitive location
loader.download("/data/imports/aws-config-copy.txt")
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check a path against the same policy before invoking the loader
try {
    accessPolicy.validateAccess(path);
} catch (SecurityException e) {
    log.warn("Rejecting blocked system path before loader call: {}", path);
    throw e;
}

Try / catch

try {
    loader.download(path);
} catch (SecurityException e) {
    // built-in denylist — do NOT disable policy; refuse the path
    throw new IllegalArgumentException("Path is blocked by security policy: " + path, e);
}

Prevention

When it happens

Trigger: A document/retriever worker or upload tries to access a file path that falls under a built-in sensitive prefix — e.g. reading /etc/passwd, ~/.aws/credentials, /var/run/secrets/token, or ~/.kube/config as a 'document' for an LLM.

Common situations: An LLM tool or workflow was given an absolute path that happens to land in a protected tree; a default file-storage path was changed to something under ~/.docker or /etc; tests that point loaders at /etc/hosts.

Understand the failure class

Related errors


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