The Bash Logging Module provides a special function for handling sensitive information that should not be written to persistent storage.
- Overview
- The log_sensitive Function
- When to Use log_sensitive
- Security Considerations
- Examples
- What log_sensitive Does NOT Do
- Best Practices
- Testing Sensitive Logging
- Related Documentation
The log_sensitive function allows you to log sensitive information that will:
- Display on console - Visible during interactive execution
- Never write to log files - Not persisted to disk
- Never send to journal - Not stored in systemd journal
- Not send to syslog - Excluded from system logs
Note: Be aware that
log_sensitiveonly controls what bash-logger writes to files and journal. If your script's stdout is redirected to a file (e.g.,./script.sh > output.log), the sensitive output will be captured by the shell. See Output Redirection Limitation for details.
#!/bin/bash
source /path/to/logging.sh
init_logger --log "/var/log/myapp.log" --journal --tag "myapp"
# Regular logging - goes everywhere
log_info "Authenticating user"
# Sensitive logging - console only
log_sensitive "API Token: $API_TOKEN"
log_sensitive "Password hash: $PASSWORD_HASH"
# Regular logging continues
log_info "Authentication successful"log_info "Starting authentication" # → Console, File, Journal
log_sensitive "Password: $PASSWORD" # → Console ONLY
log_info "Authentication complete" # → Console, File, JournalUse log_sensitive for:
- Passwords and passphrases
- API keys and tokens
- OAuth secrets
- Private keys
- Database connection strings with embedded credentials
- Session tokens
- Authentication credentials
- Encryption keys
- Personal Identifiable Information (PII) in some contexts
#!/bin/bash
source /path/to/logging.sh
init_logger --log "/var/log/api-client.log"
log_info "Connecting to API"
# Don't log the actual token to file
log_sensitive "Using API token: $API_TOKEN"
# Make API call
response=$(curl -H "Authorization: Bearer $API_TOKEN" "$API_URL")
log_info "API request completed with status: $status"#!/bin/bash
source /path/to/logging.sh
init_logger --log "/var/log/db-backup.log"
log_info "Starting database backup"
# Connection string contains password
log_sensitive "Database connection: postgresql://$DB_USER:$DB_PASS@$DB_HOST/$DB_NAME"
# Perform backup
pg_dump "$DB_NAME" > backup.sql
log_info "Backup completed successfully"Even though log_sensitive doesn't write to files or journals, the output still appears on the console. You must ensure:
- Terminal sessions are secure - Not being recorded or monitored
- Screen sharing is disabled - When handling sensitive data
- Terminal history is protected - Some terminals save output history
- Not running in logged SSH sessions - Some systems log terminal sessions
- No screen recording software - Terminal recordings can capture sensitive data
In production environments, consider:
#!/bin/bash
source /path/to/logging.sh
init_logger --log "/var/log/app.log" --journal
# Check if running interactively
if [[ -t 1 ]]; then
# Interactive - safe to show sensitive data
log_sensitive "Debug token: $TOKEN"
else
# Non-interactive - even console output might be captured
log_info "Token loaded (not displayed in non-interactive mode)"
fibash-logger provides secure-by-default protection against ANSI escape sequence injection attacks. This is important because malicious ANSI codes can:
- Manipulate terminal display - Clear screen, reposition cursor
- Hide information - Make previous output invisible
- Spoof messages - Create fake error or success messages
- Enable social engineering - Change window titles, fake prompts
- Exploit terminal bugs - Some terminal emulators have CVEs triggered by specific sequences
Default Behavior:
# By default, ANSI codes in user input are stripped
malicious_input=$'\e[2J\e[HFAKE ERROR\e[0m'
log_error "Processing: $malicious_input"
# Output: "Processing: FAKE ERROR" (without escape sequences)ANSI Code Protection:
- All user input is automatically scrubbed of ANSI escape sequences
- Library-generated colors (for log levels) are preserved
- This protection is transparent - no code changes needed
If You Need ANSI Codes in Log Messages:
Only enable unsafe mode if you have complete control over all logged content:
init_logger --unsafe-allow-ansi-codes # Not recommended
# Or at runtime:
set_unsafe_allow_ansi_codes trueSee Also:
- ANSI Code Injection Protection in Examples
- api-reference.md - set_unsafe_allow_ansi_codes function
- runtime-configuration.md - Runtime control
bash-logger includes protection against Time-of-Check Time-of-Use (TOCTOU) race condition attacks during log file creation. This prevents attackers from redirecting log output to unintended locations.
Attack Scenario Prevented:
Without protection, an attacker with local access could exploit a race condition:
# Terminal 1 - Your script
init_logger --log /tmp/app.log
# Terminal 2 - Attacker (timing attack between file checks)
rm -f /tmp/app.log
ln -s /etc/passwd /tmp/app.log
# Without protection: logs would be written to /etc/passwdSecurity Measures Implemented:
- Atomic File Creation - Uses noclobber mode to create files without race windows
- Symlink Detection - Immediately rejects symbolic links
- File Type Validation - Ensures only regular files are used for logging
- Write Permission Check - Validates write access before use
What This Protects Against:
- Log Redirection - Prevents logs from being written to sensitive files
- Symlink Attacks - Blocks attackers from linking log files to system files
- Privilege Escalation - Stops local users from hijacking log file paths
- File Substitution - Detects if a device file or other special file is substituted
Error Messages:
If a security issue is detected during initialization, you'll see:
Error: Log file path is a symbolic link
Error: Log file exists but is not a regular file (may be a directory or device)
Error: Log file '/path/to/log' is not writableBest Practices:
# Use absolute paths in trusted locations
init_logger --log "/var/log/myapp/app.log" # Good
# Avoid world-writable directories like /tmp in production
init_logger --log "/tmp/app.log" # Vulnerable to local attacks
# Use application-specific directories with proper permissions
sudo mkdir -p /var/log/myapp
sudo chown myuser:mygroup /var/log/myapp
chmod 750 /var/log/myapp
init_logger --log "/var/log/myapp/app.log" # SecureNote: While this protection significantly reduces the attack window, users with write access to log directories can still interfere with logging. Always use directories with appropriate permissions.
Instead of logging the full value, log a redacted version:
# Instead of:
log_sensitive "API Key: $API_KEY"
# Consider:
log_info "API Key: ${API_KEY:0:4}...${API_KEY: -4}" # Show first/last 4 chars
log_info "API Key loaded: [REDACTED]"
log_info "Using API key ending in: ...${API_KEY: -4}"Log a hash instead of the actual value:
# Log hash for verification without exposing actual value
KEY_HASH=$(echo -n "$API_KEY" | sha256sum | cut -d' ' -f1)
log_info "API Key hash: $KEY_HASH"Just indicate presence/absence:
if [[ -n "$API_KEY" ]]; then
log_info "API key is configured"
else
log_error "API key is missing"
fi#!/bin/bash
source /path/to/logging.sh
init_logger --log "/var/log/oauth.log"
log_info "Starting OAuth authentication"
# Get OAuth token
OAUTH_TOKEN=$(get_oauth_token "$CLIENT_ID" "$CLIENT_SECRET")
# Log for debugging, but don't persist
log_sensitive "OAuth Token: $OAUTH_TOKEN"
# Use token
make_api_request "$OAUTH_TOKEN"
log_info "OAuth authentication complete"#!/bin/bash
source /path/to/logging.sh
init_logger --log "/var/log/ssh-setup.log"
log_info "Setting up SSH keys"
# Generate key
ssh-keygen -t ed25519 -f /tmp/temp_key -N ""
# Show private key for debugging (console only)
log_sensitive "Private key content:"
log_sensitive "$(cat /tmp/temp_key)"
# Show public key (this is safe to log normally)
log_info "Public key: $(cat /tmp/temp_key.pub)"
# Clean up
rm -f /tmp/temp_key /tmp/temp_key.pub
log_info "SSH key setup complete"#!/bin/bash
source /path/to/logging.sh
init_logger --log "/var/log/app.log"
log_info "Application starting"
# Debug environment (sensitive variables to console only)
log_sensitive "Environment variables:"
log_sensitive "DATABASE_URL=$DATABASE_URL"
log_sensitive "SECRET_KEY=$SECRET_KEY"
log_sensitive "API_TOKEN=$API_TOKEN"
# Regular startup continues
log_info "Configuration loaded"#!/bin/bash
source /path/to/logging.sh
init_logger --log "/var/log/auth.log" --journal
authenticate_user() {
local username=$1
local password=$2
log_info "Authentication attempt for user: $username"
# Never log actual password to file/journal
log_sensitive "Password provided: $password"
# Perform authentication
if verify_credentials "$username" "$password"; then
log_info "Authentication successful for user: $username"
return 0
else
log_warn "Authentication failed for user: $username"
return 1
fi
}
authenticate_user "admin" "$USER_PASSWORD"log_sensitive is not a complete security solution. It:
- ✗ Does not encrypt the data
- ✗ Does not prevent console capture/recording
- ✗ Does not prevent terminal history logging
- ✗ Does not prevent memory dumps
- ✗ Does not prevent process monitoring
- ✗ Does not clear variables from memory
log_sensitive output goes to console (stdout) by default. If stdout is redirected to a file outside of
bash-logger's control, the sensitive data will be captured:
# ⚠️ Sensitive data IS captured when stdout is redirected
./script.sh > output.log 2>&1 # Captures log_sensitive output
./script.sh | tee output.log # Captures log_sensitive output
./script.sh 1> file.log # Captures log_sensitive output
# ✓ Sensitive data is NOT captured in normal interactive use
./script.sh # Direct console output onlyThis is a fundamental behavior of shell redirection and outside the control of bash-logger. The
log_sensitive function only controls what bash-logger writes to log files and journal — it cannot prevent
redirection of stdout by the calling script or shell.
How to Mitigate:
- Run scripts with sensitive logging in trusted environments only
- Be aware of shell redirections when executing scripts with sensitive operations
- For production, use bash-logger's
--quietflag with--logto disable console output entirely - Disable debug/sensitive logging in production using environment flags or log levels
- Consider redirecting stderr only:
./script.sh 2> error.log(stdout stays on console)
You must still:
- Store secrets in secure vaults (like HashiCorp Vault, AWS Secrets Manager)
- Use environment variables instead of hardcoding
- Implement proper access controls
- Use encrypted communication channels
- Follow the principle of least privilege
- Rotate credentials regularly
- Monitor for credential exposure
Only log sensitive data when absolutely necessary for debugging:
# Production
if [[ "$DEBUG_MODE" == "true" ]]; then
log_sensitive "Debug credentials: $CREDS"
fi
# Not in production
log_info "Credentials loaded successfully"Create helper functions for consistent redaction:
redact_token() {
local token=$1
local length=${#token}
if [[ $length -gt 8 ]]; then
echo "${token:0:4}...${token: -4}"
else
echo "[REDACTED]"
fi
}
log_info "API Token: $(redact_token "$API_TOKEN")"Make it clear in your code:
# SECURITY: This function handles sensitive authentication data
# Sensitive values are only logged to console via log_sensitive
# and are never persisted to disk or sent to journal
authenticate() {
log_sensitive "Auth token: $1"
# ... authentication logic ...
}Consider disabling sensitive logging entirely in production:
#!/bin/bash
source /path/to/logging.sh
init_logger --log "/var/log/app.log"
log_sensitive_safe() {
if [[ "${ENVIRONMENT}" != "production" ]]; then
log_sensitive "$@"
fi
}
# Only logs in non-production environments
log_sensitive_safe "API Key: $API_KEY"Regularly review your code for sensitive logging:
# Search for potential sensitive data in logs
grep -r "password\|token\|secret\|key" your_scripts/#!/bin/bash
source /path/to/logging.sh
LOG_FILE="/tmp/test-sensitive.log"
init_logger --log "$LOG_FILE"
log_info "Regular message"
log_sensitive "SECRET: this should not appear in file"
log_info "Another regular message"
echo "=== Log file contents ==="
cat "$LOG_FILE"
echo "=== End of log file ==="
# Verify the word "SECRET" doesn't appear in the log file
if grep -q "SECRET" "$LOG_FILE"; then
echo "ERROR: Sensitive data found in log file!"
exit 1
else
echo "SUCCESS: Sensitive data not in log file"
fi
rm "$LOG_FILE"- Log Levels - Understanding log severity levels
- Journal Logging - What doesn't go to the journal
- Examples - More examples of sensitive data handling
- Getting Started - Basic logging usage