Hmbown/CodeWhale · error
allowlisted read-only executable
Error message
allowlisted read-only executable {program:?} was not found at a canonical path outside the workspace What it means
The shell tool resolved an allowlisted read-only executable (e.g. grep, wc) to a canonical path, but none of the PATH candidates canonicalized to an absolute path outside the workspace. This guard exists because read-only allowlisted binaries must be resolved to their real system location, never a workspace copy that could be swapped for a malicious script. The lookup deliberately fails closed instead of executing an unverified binary.
Solutions
- Install the missing executable system-wide (e.g. `apt-get install coreutils/grep`) so it resolves outside the workspace
- Check `which <program>` — if it points inside the workspace, remove or rename the workspace-local copy/shim
- Verify PATH contains standard system dirs (/usr/bin, /bin) and isn't overridden to a workspace dir
- If the executable genuinely lives in the workspace, use the regular (non-allowlisted) shell tool with approval instead
Example fix
// before: workspace-local shim shadows system grep ./tools/grep ... // after: ensure system grep resolves PATH=/usr/bin:/bin grep -rn "pattern" .
Defensive patterns
Strategy: validation
Validate before calling
let resolved = which::which(program)?;
let canon = resolved.canonicalize()?;
if !canon.is_absolute() || canon.starts_with(&workspace) {
return Err(anyhow!("{program} resolves inside workspace; refusing"));
} Type guard
fn is_outside_workspace(p: &Path, workspace: &Path) -> bool {
p.is_absolute() && !p.starts_with(workspace)
} Prevention
- Install allowlisted tools in standard system locations
- Never place executables named like allowlisted tools inside the workspace
- Keep PATH free of workspace-relative entries in agent environments
- Run `which <tool>` in CI to confirm resolution before enabling read-only shell tools
When it happens
Trigger: Calling the read-only shell tool with a program name that is on the read-only allowlist but not installed on the host, or installed only inside the workspace directory (so canonicalize() yields a path under `workspace`), or PATH points at workspace-local shim scripts.
Common situations: Minimal Docker/CI images missing coreutils like `wc` or `grep`; a repo vendoring binaries named like allowlisted tools so PATH resolves to the workspace copy; a broken or overridden PATH env var; running the tool from a container where the expected system utilities were never installed.
Related errors
- classifier-approved Git read did not keep its subcommand in…
- classifier-approved Git read was missing its literal…
- no trusted executable search path remains outside the…
- pipeline contains a command outside the read-only policy
- read-only command must name a bare allowlisted executable
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/2fcaad2a8b75de58.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tools/shell.rs:4422
for name in &names {
let candidate = directory.join(name);
if !candidate.is_file() {
continue;
}
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt as _;
if candidate.metadata()?.permissions().mode() & 0o111 == 0 {
continue;
}
}
let resolved = candidate.canonicalize()?;
if resolved.is_absolute() && !resolved.starts_with(&workspace) {
return Ok(resolved);
}
}
}
Err(anyhow!(
"allowlisted read-only executable {program:?} was not found at a canonical path outside the workspace"
))
}
fn remove_readonly_redirect_env(cmd: &mut Command, env: &HashMap<String, String>) {
if env.get(READONLY_ENV_MARKER).map(String::as_str) != Some("1") {
return;
}
cmd.env_remove(READONLY_ENV_MARKER);
let removals = cmd
.get_envs()
.filter_map(|(key, _)| {
let upper = key.to_string_lossy().to_ascii_uppercase();
let guarded = upper.starts_with("GIT_")
|| upper.starts_with("GH_")
|| upper.starts_with("GITHUB_");
let safe = matches!(
upper.as_str(),View on GitHub (pinned to 73e0f67d83)