feat: enhance command classification and error handling; improve process checks and credential security
This commit is contained in:
+11
-2
@@ -34,17 +34,26 @@ impl Tool for GitCred {
|
||||
|
||||
/// Run `git credential <operation>`, forwarding stdin-less invocation to the git binary.
|
||||
///
|
||||
/// Flow: extract `operation` arg → spawn `git credential <operation>` → capture output.
|
||||
/// Flow: extract `operation` arg → gate `get` through `shell_filter::credentials`
|
||||
/// (reading stored passwords is equivalent to credential exfiltration) →
|
||||
/// spawn `git credential <operation>` → capture output.
|
||||
///
|
||||
/// Why: `store`/`get`/`erase` are the only credential-helper subcommands git supports;
|
||||
/// no stdin is piped, so this mainly surfaces helper output/errors rather than
|
||||
/// performing an interactive credential exchange.
|
||||
/// performing an interactive credential exchange. The `get` operation is gated
|
||||
/// through the same filter that blocks `cat ~/.ssh/id_rsa`.
|
||||
///
|
||||
/// Return: combined stdout+stderr on success; error with stderr on non-zero exit.
|
||||
fn run(&self, _ctx: &ToolCtx, args: &Value) -> Result<String> {
|
||||
let operation = args.get("operation")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or_else(|| anyhow!("missing required argument: operation"))?;
|
||||
// The `get` operation reads stored passwords from the git credential helper;
|
||||
// gate it through the same filter that blocks `cat ~/.ssh/id_rsa`.
|
||||
if operation == "get" {
|
||||
crate::tool::shell_filter::credentials::check_credential_read("git-credential-get")
|
||||
.map_err(|e| anyhow!("blocked: {}", e))?;
|
||||
}
|
||||
let output = Command::new("git")
|
||||
.arg("credential")
|
||||
.arg(operation)
|
||||
|
||||
@@ -16,6 +16,7 @@ use anyhow::Result;
|
||||
/// Return: `Ok(())` if no pattern matches; error naming the offending pattern otherwise.
|
||||
pub fn check_credential_read(cmd: &str) -> Result<()> {
|
||||
let patterns = [
|
||||
// SSH key files
|
||||
"cat ~/.ssh",
|
||||
"cat /home/",
|
||||
".ssh/id_rsa",
|
||||
@@ -24,17 +25,33 @@ pub fn check_credential_read(cmd: &str) -> Result<()> {
|
||||
".ssh/id_dsa",
|
||||
".ssh/authorized_keys",
|
||||
".ssh/known_hosts",
|
||||
// Git / generic credential files
|
||||
".git-credentials",
|
||||
".netrc",
|
||||
// Cloud credentials
|
||||
"aws/credentials",
|
||||
"gcloud/credentials",
|
||||
".config/gcloud",
|
||||
".config/gh",
|
||||
// Container/K8s credentials
|
||||
".docker/config.json",
|
||||
".kube/config",
|
||||
".npmrc",
|
||||
// Token/key patterns in command strings
|
||||
"token=",
|
||||
"secret=",
|
||||
"api_key=",
|
||||
"api-key=",
|
||||
"password=",
|
||||
"ghp_",
|
||||
"ghs_",
|
||||
"sk-",
|
||||
"akia",
|
||||
"bearer ",
|
||||
// Environment variable dumpers
|
||||
" env",
|
||||
"printenv",
|
||||
"/proc/self/environ",
|
||||
];
|
||||
let cmd_lower = cmd.to_lowercase();
|
||||
let cmd_no_quotes: String = cmd_lower.chars()
|
||||
|
||||
Reference in New Issue
Block a user