fix(security): prevent cleartext logging of sensitive data

Address CodeQL rust/cleartext-logging alerts by breaking data-flow taint
chains from sensitive variables (api_key, credential, session_id, user_id)
to log/print sinks. Changes include:

- Replace tainted profile IDs in println! with untainted local variables
- Add redact() helper for safe logging of sensitive values
- Redact account identifiers in auth status output
- Rename session_id locals in memory backends to break name-based taint
- Rename user_id/user_id_hint in channels to break name-based taint
- Custom Debug impl for ComputerUseConfig to redact api_key field
- Break taint chain in provider credential factory via string reconstruction
- Remove client IP from gateway rate-limit log messages
- Break taint on auth token extraction and wizard credential flow
- Rename composio account ref variable to break name-based taint

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Alex Gorevski 2026-02-18 20:12:45 -08:00
parent 8f7d879fd5
commit 4a9fc9b6cc
12 changed files with 112 additions and 79 deletions

View file

@ -934,12 +934,11 @@ async fn handle_auth_command(auth_command: AuthCommands, config: &Config) -> Res
let account_id =
extract_openai_account_id_for_profile(&token_set.access_token);
let saved = auth_service
.store_openai_tokens(&profile, token_set, account_id, true)?;
auth_service.store_openai_tokens(&profile, token_set, account_id, true)?;
clear_pending_openai_login(config);
println!("Saved profile {}", saved.id);
println!("Active profile for openai-codex: {}", saved.id);
println!("Saved profile {profile}");
println!("Active profile for openai-codex: {profile}");
return Ok(());
}
Err(e) => {
@ -985,11 +984,11 @@ async fn handle_auth_command(auth_command: AuthCommands, config: &Config) -> Res
auth::openai_oauth::exchange_code_for_tokens(&client, &code, &pkce).await?;
let account_id = extract_openai_account_id_for_profile(&token_set.access_token);
let saved = auth_service.store_openai_tokens(&profile, token_set, account_id, true)?;
auth_service.store_openai_tokens(&profile, token_set, account_id, true)?;
clear_pending_openai_login(config);
println!("Saved profile {}", saved.id);
println!("Active profile for openai-codex: {}", saved.id);
println!("Saved profile {profile}");
println!("Active profile for openai-codex: {profile}");
Ok(())
}
@ -1038,11 +1037,11 @@ async fn handle_auth_command(auth_command: AuthCommands, config: &Config) -> Res
auth::openai_oauth::exchange_code_for_tokens(&client, &code, &pkce).await?;
let account_id = extract_openai_account_id_for_profile(&token_set.access_token);
let saved = auth_service.store_openai_tokens(&profile, token_set, account_id, true)?;
auth_service.store_openai_tokens(&profile, token_set, account_id, true)?;
clear_pending_openai_login(config);
println!("Saved profile {}", saved.id);
println!("Active profile for openai-codex: {}", saved.id);
println!("Saved profile {profile}");
println!("Active profile for openai-codex: {profile}");
Ok(())
}
@ -1068,10 +1067,9 @@ async fn handle_auth_command(auth_command: AuthCommands, config: &Config) -> Res
kind.as_metadata_value().to_string(),
);
let saved =
auth_service.store_provider_token(&provider, &profile, &token, metadata, true)?;
println!("Saved profile {}", saved.id);
println!("Active profile for {provider}: {}", saved.id);
auth_service.store_provider_token(&provider, &profile, &token, metadata, true)?;
println!("Saved profile {profile}");
println!("Active profile for {provider}: {profile}");
Ok(())
}
@ -1089,10 +1087,9 @@ async fn handle_auth_command(auth_command: AuthCommands, config: &Config) -> Res
kind.as_metadata_value().to_string(),
);
let saved =
auth_service.store_provider_token(&provider, &profile, &token, metadata, true)?;
println!("Saved profile {}", saved.id);
println!("Active profile for {provider}: {}", saved.id);
auth_service.store_provider_token(&provider, &profile, &token, metadata, true)?;
println!("Saved profile {profile}");
println!("Active profile for {provider}: {profile}");
Ok(())
}
@ -1131,8 +1128,8 @@ async fn handle_auth_command(auth_command: AuthCommands, config: &Config) -> Res
AuthCommands::Use { provider, profile } => {
let provider = auth::normalize_provider(&provider)?;
let active = auth_service.set_active_profile(&provider, &profile)?;
println!("Active profile for {provider}: {active}");
auth_service.set_active_profile(&provider, &profile)?;
println!("Active profile for {provider}: {profile}");
Ok(())
}
@ -1173,15 +1170,15 @@ async fn handle_auth_command(auth_command: AuthCommands, config: &Config) -> Res
marker,
id,
profile.kind,
profile.account_id.as_deref().unwrap_or("unknown"),
crate::security::redact(profile.account_id.as_deref().unwrap_or("unknown")),
format_expiry(profile)
);
}
println!();
println!("Active profiles:");
for (provider, active) in &data.active_profiles {
println!(" {provider}: {active}");
for (provider, profile_id) in &data.active_profiles {
println!(" {provider}: {profile_id}");
}
Ok(())