Require approval for path-qualified safe commands

This commit is contained in:
Chris Bookholt
2026-06-22 11:05:55 -07:00
parent 87d89bec88
commit ffe6f9917f
2 changed files with 56 additions and 0 deletions

View File

@@ -1178,6 +1178,27 @@ fn git_branch_requires_approval_for_untrusted_projects() {
);
}
#[test]
fn path_qualified_safe_basename_requires_approval_for_untrusted_projects() {
let executable = if cfg!(windows) { r".\cat.exe" } else { "./cat" };
let command = vec![executable.to_string(), "Cargo.toml".to_string()];
assert_eq!(
Decision::Prompt,
render_decision_for_unmatched_command(
&command,
UnmatchedCommandContext {
approval_policy: AskForApproval::UnlessTrusted,
permission_profile: &PermissionProfile::workspace_write(),
windows_sandbox_level: WindowsSandboxLevel::Disabled,
sandbox_permissions: SandboxPermissions::UseDefault,
used_complex_parsing: false,
command_origin: ExecPolicyCommandOrigin::Generic,
},
)
);
}
#[test]
fn managed_cwd_write_profile_has_filesystem_restrictions() {
let file_system_sandbox_policy = FileSystemSandboxPolicy::restricted(vec![

View File

@@ -64,6 +64,12 @@ fn is_safe_to_call_with_exec(command: &[String]) -> bool {
let Some(cmd0) = command.first().map(String::as_str) else {
return false;
};
if std::path::Path::new(cmd0).components().count() != 1 {
// A workspace executable can impersonate an allowlisted utility by
// reusing its basename. Only bare names resolved through the trusted
// process PATH are eligible for generic safe-command classification.
return false;
}
match executable_name_lookup_key(cmd0).as_deref() {
Some(cmd) if cfg!(target_os = "linux") && matches!(cmd, "numfmt" | "tac") => true,
@@ -250,6 +256,35 @@ mod tests {
}
}
#[test]
fn path_qualified_safe_command_names_require_approval() {
let absolute_cat = if cfg!(windows) {
r"C:\workspace\cat.exe"
} else {
"/tmp/workspace/cat"
};
let parent_relative_cat = if cfg!(windows) {
r"..\cat.exe"
} else {
"../cat"
};
for args in [
vec_str(&["./cat", "Cargo.toml"]),
vec_str(&[parent_relative_cat, "Cargo.toml"]),
vec_str(&[absolute_cat, "Cargo.toml"]),
vec_str(&["bash", "-lc", "./cat Cargo.toml"]),
] {
assert!(
!is_known_safe_command(&args),
"expected path-qualified executable {args:?} to require approval",
);
}
let bare_cat = if cfg!(windows) { "cat.exe" } else { "cat" };
assert!(is_known_safe_command(&vec_str(&[bare_cat, "Cargo.toml"])));
}
#[test]
fn git_commands_require_approval() {
for args in [