Skip to content

fix(tools): FileExecutor does not expand ~ in allowed_paths, blocking all file access #2115

@bug-ops

Description

@bug-ops

Summary

FileExecutor::new does not expand ~ in path strings. When a user sets allowed_paths = ["~/Documents/git/zeph"] in config, the tilde is not resolved to the home directory by Rust's Path::canonicalize(). The unwrap_or(p) fallback retains the literal ~/ path, so starts_with never matches real absolute paths — silently blocking all file access.

Root Cause

crates/zeph-tools/src/file.rs:112:

.map(|p| p.canonicalize().unwrap_or(p))

Path::canonicalize("~/Documents/git/zeph") returns Err (no such file — tilde is not a shell metacharacter in Rust filesystem APIs). unwrap_or(p) keeps the broken path.

Then validate_path (line 126):

if !self.allowed_paths.iter().any(|a| canonical.starts_with(a)) {
    return Err(ToolError::SandboxViolation { ... });
}

/Users/rabax/Documents/git/zeph/Cargo.toml does not start with ~/Documents/git/zeph → SandboxViolation on every file access.

Effect

When allowed_paths contains any ~-prefixed entry and no other valid absolute paths, all file access is silently blocked. The agent starts without any error, but every read, write, edit, grep, etc. call returns a sandbox violation.

This was observed in the user's ~/.config/zeph/default.toml config:

allowed_paths = ["~/Documents/git/zeph", ".claude/rules"]

Only .claude/rules (relative, correctly canonicalized) was accessible. The entire project tree was blocked.

Fix

Expand ~ in FileExecutor::new before canonicalization:

.map(|p| {
    let expanded = if let Some(stripped) = p.strip_prefix("~") {
        dirs::home_dir().map(|h| h.join(stripped)).unwrap_or(p.clone())
    } else {
        p.clone()
    };
    expanded.canonicalize().unwrap_or(expanded)
})

Or use the shellexpand crate for full tilde + env var expansion.

Workaround

Set allowed_paths = [] to use CWD as the sandbox root (the default behavior when the list is empty). Applied to user config as immediate fix.

Filed

CI-76, 2026-03-22

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions