fix(rust): Remove sensitive information from logs and docs

Security improvements:
- Remove all debug logs that output tokens, keys, or credentials
- Remove email addresses from debug output
- Remove encrypted keys and nonces from logs
- Remove specific account references from documentation
- Add security guidelines to CLAUDE.md

No sensitive information (PII, credentials, tokens) should be logged
even in debug mode. Updated guidelines to prevent future occurrences.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Manav Rathi
2025-08-23 15:06:28 +05:30
parent f5347e7436
commit a00fc0b1be
6 changed files with 16 additions and 27 deletions

View File

@@ -107,6 +107,15 @@ cargo fmt --check
- Never commit to main branch
- All CI checks must pass - the above commands simulate CI locally
### Security Guidelines
**NEVER commit sensitive information:**
- No real email addresses, usernames, or account IDs in code or documentation
- No authentication tokens, API keys, or passwords (even for test accounts)
- No debug logs that output credentials, keys, or personal information
- Use generic examples like "user@example.com" in documentation
- Remove all `log::debug!` statements that print sensitive data before committing
- Avoid logging encrypted keys, nonces, or tokens even in encrypted form
## Environment Variables
- `ENTE_CLI_CONFIG_DIR`: Override default config directory

View File

@@ -111,7 +111,7 @@ The Rust CLI now has a **fully functional export capability** with proper file d
## Testing Status 🧪
### Successfully Tested ✅
- ✅ Export with real account (m@ente.io)
- ✅ Export with real account
- ✅ Small file decryption (JPEG images)
- ✅ Large file decryption (33MB RAW file)
- ✅ Metadata extraction for filenames

View File

@@ -82,12 +82,9 @@ impl<'a> AuthClient<'a> {
srp_attrs.mem_limit as u32,
srp_attrs.ops_limit as u32,
)?;
log::debug!("KEK (hex): {}", hex::encode(&key_enc_key));
// Step 3: Derive login key
let login_key = derive_login_key(&key_enc_key)?;
log::debug!("loginSubKey (base64): {}", STANDARD.encode(&login_key));
log::debug!("loginSubKey (hex): {}", hex::encode(&login_key));
// Step 4: Initialize SRP client
let srp_salt = STANDARD.decode(&srp_attrs.srp_salt)?;

View File

@@ -83,7 +83,7 @@ impl ApiClient {
// Add auth token if account_id is provided
if let Some(id) = account_id {
if let Some(token) = self.get_token(id) {
log::debug!("Adding auth token for account {id}: {token}");
log::debug!("Adding auth token for account {id}");
req = req.header(TOKEN_HEADER, token);
} else {
log::warn!("No token found for account {id}");

View File

@@ -238,29 +238,21 @@ async fn add_account(
// Decrypt token if encrypted
let token = if let Some(encrypted_token) = &auth_response.encrypted_token {
log::info!("Encrypted token from server (base64): {encrypted_token}");
log::info!("Public key (base64): {}", key_attributes.public_key);
let encrypted_bytes = decode_base64(encrypted_token)?;
log::info!("Encrypted token bytes length: {}", encrypted_bytes.len());
log::debug!("Encrypted token bytes length: {}", encrypted_bytes.len());
let decrypted = sealed_box_open(&encrypted_bytes, &public_key, &secret_key)?;
log::info!("Decrypted token bytes length: {}", decrypted.len());
log::info!("Decrypted token hex: {}", hex::encode(&decrypted));
log::debug!("Decrypted token bytes length: {}", decrypted.len());
// Try to interpret as UTF-8 string first
match String::from_utf8(decrypted.clone()) {
Ok(token_str) => {
log::info!("Decrypted token is UTF-8 string: {token_str}");
log::debug!("Decrypted token is valid UTF-8");
// If it's a string, use it as bytes
token_str.into_bytes()
}
Err(_) => {
log::info!("Token is not UTF-8, using raw bytes");
log::info!(
"Token as base64 URL: {}",
base64::engine::general_purpose::URL_SAFE.encode(&decrypted)
);
log::debug!("Token is not UTF-8, using raw bytes");
// If not UTF-8, use raw bytes
decrypted
}

View File

@@ -23,16 +23,9 @@ pub async fn run_export(account_email: Option<String>) -> Result<()> {
// Export specific account - try to find it with any app
let all_accounts = storage.accounts().list()?;
log::debug!("Found {} total accounts", all_accounts.len());
for acc in &all_accounts {
log::debug!("Account: email='{}', id={}", acc.email, acc.id);
}
let matching: Vec<Account> = all_accounts
.into_iter()
.filter(|a| {
let matches = a.email == email;
log::debug!("Comparing '{}' == '{}': {}", a.email, email, matches);
matches
})
.filter(|a| a.email == email)
.collect();
if matching.is_empty() {
@@ -169,8 +162,6 @@ async fn export_account(storage: &Storage, account: &Account) -> Result<()> {
Ok(key) => key,
Err(e) => {
log::error!("Failed to decrypt key for file {}: {}", file.id, e);
log::debug!("encrypted_key: {}", &file.encrypted_key);
log::debug!("key_decryption_nonce: {}", &file.key_decryption_nonce);
continue;
}
};