conductor-oss/conductor · critical · DocumentAccessDeniedException

Access denied: file name '{fileName}' is blocked

Error message

Access denied: file name '{fileName}' is blocked

What it means

Thrown by DocumentAccessPolicy.checkBlockedFileNames when the last path component exactly matches (case-insensitive) one of the built-in DEFAULT_BLOCKED_FILE_NAMES (e.g. .env, id_rsa, credentials.json, service-account.json, terraform.tfvars, private.key). DocumentAccessDeniedException (SecurityException). The check runs even when the directory is allowed, so a blocked filename inside an allowed dir is still denied.

Source

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

        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();

        for (String blocked : DEFAULT_BLOCKED_FILE_NAMES) {
            if (lowerFileName.equals(blocked.toLowerCase())) {
                throw new DocumentAccessDeniedException(
                        "Access denied: file name '" + fileName + "' is blocked");
            }
        }
        for (String blocked : blockedFileNames) {
            if (lowerFileName.equals(blocked.toLowerCase())) {
                throw new DocumentAccessDeniedException(
                        "Access denied: file name '" + fileName + "' is blocked");
            }
        }
    }

    private void checkBlockedHosts(String location) {
        String host = extractHost(location);
        if (host == null || host.isEmpty()) {
            return;
        }
        String lowerHost = host.toLowerCase();

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Rename the file you need to a basename that is not on the built-in denylist, or access its content through a non-file channel.
  2. Confirm the file is not a real secret — if it is, it should never be passed to a document loader.
  3. Sanitize any LLM/user-supplied filename so it cannot resolve to a protected basename.

Example fix

// before
loader.download("/data/imports/.env")
// after — rename the source file to a non-blocked name
loader.download("/data/imports/app-config.env.txt")
Defensive patterns

Strategy: validation

Validate before calling

// Reject protected filenames before the loader sees them
String name = path.substring(path.lastIndexOf('/') + 1).toLowerCase();
if (Set.of(".env","id_rsa","credentials.json","private.key","terraform.tfstate").contains(name)) {
    throw new IllegalArgumentException("Refusing protected filename: " + path);
}

Try / catch

try {
    loader.download(path);
} catch (SecurityException e) {
    // built-in filename denylist — do not weaken policy; rename the source file
    throw new IllegalArgumentException("Filename blocked by security policy: " + path, e);
}

Prevention

When it happens

Trigger: A loader/upload targets a file whose basename is a known credential/secret filename: .env, .npmrc, id_ed25519, keystore.jks, terraform.tfstate, application_default_credentials.json, etc.

Common situations: A workflow reads project files for an LLM and hits .env; an upload references a service-account.json; a path computed from user input ends in a protected filename.

Understand the failure class

Related errors


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