Hmbown/CodeWhale · error
external credential path escapes its absolute root
Error message
external credential path escapes its absolute root: {} What it means
Thrown by resolve_external_credential_path while lexically normalizing an absolute credential path: a `..` component would climb above the root, meaning the path escapes its declared absolute root. The library refuses such paths without any filesystem I/O, closing a classic path-traversal hole in external credential lookup.
Solutions
- Rewrite the path so it stays under its absolute root, removing excess `..` segments
- Point the external credential source at the actual absolute file path
- If indirection is needed, move the root up so the relative portion stays inside it
- Reject or sanitize the path at configuration time before it reaches read_grant
Example fix
// before let path = "/secure/creds/../../etc/passwd"; resolve_external_credential_path(path)?; // after let path = "/secure/creds/token.txt"; resolve_external_credential_path(path)?;
Defensive patterns
Strategy: validation
Validate before calling
fn stays_under_root(path: &str, root: &str) -> bool {
std::path::Path::new(root).join(path)
.components()
.try_fold(0usize, |depth, c| match c {
std::path::Component::ParentDir => if depth == 0 { None } else { Some(depth - 1) },
std::path::Component::Normal(_) => Some(depth + 1),
_ => Some(depth),
}).is_some()
} Prevention
- Never compose credential paths from untrusted input
- Sanitize or reject `..` segments in user-supplied paths
- Pin external credential sources to explicit absolute files
When it happens
Trigger: An ExternalCredentialSource path like /safe/root/../../etc/passwd, or a symlink-free path string containing enough `..` segments to underflow the root (e.g. /../secret) passed to resolve_external_credential_path via validate_read_scope/read_grant.
Common situations: Config entries or tool-supplied paths that embed relative escapes; attackers or buggy scripts composing credential paths from untrusted fragments.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- external credential path must be lexically normalized
- Automation lock must not be a reparse point
- Automation lock must not have hard links
- built-in plugin path may not be a symbolic link or reparse…
- Codewhale-owned credential file must be singly linked
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/1d3cb44a3147b706.
Report an issue: GitHub.
Appendix: source
Thrown at crates/config/src/external_credentials.rs:129
} else {
std::env::current_dir()
.map_err(|err| anyhow::anyhow!("resolving external credential path: {err}"))?
.join(path)
};
// Normalize only lexical `.` / `..` components. Canonicalization would
// inspect a credential path before consent exists and would also silently
// bless a symlink target. The secure reader rejects symlink/reparse-point
// components when the granted capability is actually consumed.
let mut normalized = PathBuf::new();
for component in absolute.components() {
match component {
Component::Prefix(prefix) => normalized.push(prefix.as_os_str()),
Component::RootDir => normalized.push(component.as_os_str()),
Component::CurDir => {}
Component::ParentDir => {
if !normalized.pop() {
bail!(
"external credential path escapes its absolute root: {}",
quote_os_path(&absolute)
);
}
}
Component::Normal(part) => normalized.push(part),
}
}
if !normalized.is_absolute() {
bail!(
"external credential path must resolve to an absolute path: {}",
quote_os_path(&normalized)
);
}
Ok(normalized)
}
/// The side-effect envelope Codewhale may use for an external credential.View on GitHub (pinned to 73e0f67d83)