| Crates.io | history-redact |
| lib.rs | history-redact |
| version | 0.2.2 |
| created_at | 2025-11-07 17:43:57.20949+00 |
| updated_at | 2025-11-07 17:43:57.20949+00 |
| description | A fast, secure tool to redact sensitive information from shell command history |
| homepage | https://github.com/severeon/zsh-redact-history |
| repository | https://github.com/severeon/zsh-redact-history |
| max_upload_size | |
| id | 1921936 |
| size | 131,639 |
Fast, secure redaction of sensitive information from shell command history
Reduce accidental secret exposure in shell history as part of defense-in-depth security practices. History Redactor automatically redacts sensitive information before it's written to your history file, using blazing-fast Rust regex patterns.
⭐️ If this little tool saved you some time, feel free to buy me a coffee ⭐️
Every time you run a command like this:
export OPENAI_API_KEY=sk-1234567890abcdefghijklmnopqrstuvwxyz1234567890
curl -H "Authorization: Bearer secret_token" https://api.example.com
mysql -u root -p MySecretPassword123 -h localhost
...those secrets are written to your shell history file in plain text. If your system is compromised, or you accidentally share your history, those credentials are exposed.
History Redactor intercepts commands before they hit your history file and redacts sensitive patterns:
export OPENAI_API_KEY=[OPENAI_KEY_REDACTED]
curl -H "Authorization: Bearer [BEARER_TOKEN_REDACTED]" https://api.example.com
mysql -u root --password [REDACTED] -h localhost
Blazing Fast: Sub-5ms overhead even with 100+ redaction rules (Rust-powered regex engine)
Zero Config: Ships with sensible defaults for common secrets (API keys, tokens, passwords)
Flexible: Easy-to-customize regex patterns via simple config file
Shell Integration: Seamless Zsh integration via zshaddhistory hook
Safe: Non-destructive - only affects what's written to history, not command execution
Comprehensive: Built-in patterns for OpenAI, GitHub, AWS, database URLs, and more
Important: Understand what this tool protects and what it doesn't.
| ✅ What This Protects | ❌ What This Doesn't Protect |
|---|---|
| Shell history files on disk | Commands visible in ps during execution |
| Accidental history file sharing | Process monitoring and audit logs |
| Secrets in dotfiles/backups | Terminal scrollback buffers |
| Multi-session history exposure | Application logs and stdout |
| Network traffic containing secrets | |
| Memory dumps or core dumps |
History Redactor is ONE layer of defense-in-depth, not a complete secret management solution. Secrets passed as command-line arguments are still exposed during execution to:
ps auxww or /proc/[pid]/cmdlineFor comprehensive secret security:
chmod 600)Run history-redact explain-security after installation for detailed security boundaries and best practices.
See SECURITY.md for a complete threat model analysis.
Install the binary:
cargo install history-redact
Add this function to your ~/.zshrc file:
function zshaddhistory() {
local command="$1"
local redacted
local redacted_cmd
redacted=$(echo -n "$command" | history-redact redact 2>/dev/null)
if [[ $? -ne 0 ]]; then
echo "Warning: history-redact failed to process command" >&2
return 0
fi
redacted_cmd="${redacted#*|}"
print -sr -- "${redacted_cmd%%$'\n'}"
return 1
}
Then initialize the configuration and restart your shell:
history-redact init
source ~/.zshrc
git clone https://github.com/severeon/zsh-redact-history.git
cd zsh-redact-history
./install.sh
The install script will:
.zshrcIf you prefer to add the integration manually, install the binary first:
cargo install history-redact
history-redact init
Then add this to your ~/.zshrc:
# History Redact - Zsh Integration
function zshaddhistory() {
local redacted
redacted=$(echo -n "$1" | history-redact redact 2>/dev/null)
if [[ $? -eq 0 ]]; then
local exit_code="${redacted%%|*}"
local cmd="${redacted#*|}"
print -sr -- "${cmd%%$'\n'}"
fi
return 1
}
# Check version
history-redact --version
# Test redaction
history-redact test "export OPENAI_KEY=sk-1234567890123456789012345678901234567890123456ab"
# View configuration
history-redact config-path
# Test what would be redacted from a command
history-redact test "curl -H 'Authorization: Bearer abc123' api.example.com"
# Redact from stdin (used by shell hook)
echo "export KEY=secret" | history-redact redact
# Validate your configuration
history-redact validate-config --verbose
# Initialize/reset configuration
history-redact init --force
# Show config file location
history-redact config-path
Configuration lives in ~/.config/history-redact/rules.conf (XDG-compliant).
$HISTORY_REDACT_CONFIG environment variable~/.config/history-redact/rules.conf/etc/history-redact/rules.conf# Format: regex|||replacement
# OpenAI API keys
sk-[a-zA-Z0-9]{48}|||[OPENAI_KEY_REDACTED]
# Generic password flags
--password\s+\S+|||--password [REDACTED]
# Environment variables
API_KEY=\S+|||API_KEY=[REDACTED]
# Database connection strings
postgresql://[^:@]+:[^@]+@|||postgresql://[USER]:[PASS_REDACTED]@
Key points:
||| as the delimiter (triple pipe)# are commentsHistory Redactor ships with comprehensive patterns for:
API Keys & Tokens:
sk-...)sk-ant-...)ghp_..., gho_..., etc.)AKIA...)AIza...)xoxb-..., xoxp-...)Command-line Arguments:
--password, --token, --api-key, etc.-p (with port exclusions)Environment Variables:
API_KEY=..., SECRET=..., PASSWORD=...Database URLs:
Private Keys:
See rules.conf for the full list.
┌─────────────────┐
│ Shell Command │
│ "export KEY=sk-123..." │
└────────┬────────┘
│
▼
┌─────────────────────────┐
│ zshaddhistory hook │
│ (shell integration) │
└────────┬────────────────┘
│
▼
┌──────────────────────────┐
│ history-redact │
│ (Rust binary) │
│ - Load config │
│ - Apply regex rules │
│ - Return redacted cmd │
└────────┬─────────────────┘
│
▼
┌─────────────────────────┐
│ Redacted Command │
│ "export KEY=[REDACTED]"│
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ ~/.zsh_history │
│ (written to disk) │
└─────────────────────────┘
Benchmark on M1 MacBook Pro with 50 rules:
When you type a command containing a secret, it exists in multiple places:
1. Keyboard Input → 2. Shell Memory → 3. Process Arguments → 4. Command Output → 5. History File
[TYPED] [EXECUTING] [VISIBLE IN ps] [LOGS/STDOUT] [DISK]
↑
NOT PROTECTED
↓
History Redactor ONLY protects step 5 →
History Redactor operates at the final stage - preventing secrets from persisting to disk. This is valuable because:
However, secrets are already exposed during stages 1-4 to:
ps, top, audit logs)Instead of:
# ✗ BAD: Secret on command line (visible in ps, logs, history)
curl -H "Authorization: Bearer sk-1234567890abcdef" api.example.com
Use:
# ✓ BETTER: Environment variable (still visible in ps during export)
export TOKEN=sk-1234567890abcdef
curl -H "Authorization: Bearer $TOKEN" api.example.com
# History Redactor will redact the export line
# ✓✓ BEST: Load from secure store
export TOKEN=$(op read "op://vault/api/token") # 1Password CLI
export TOKEN=$(vault kv get -field=token secret/api) # HashiCorp Vault
export TOKEN=$(aws secretsmanager get-secret-value \
--secret-id api-token --query SecretString --output text) # AWS
# ✓✓ ALSO BEST: Interactive prompt
mysql -u root -p # Prompts for password, doesn't show in ps or history
# ✓✓ ALSO BEST: Config file with restricted permissions
chmod 600 ~/.config/myapp/credentials
myapp --config ~/.config/myapp/credentials
Good Use Cases:
Insufficient Alone:
Best practices:
history | grep -i 'password\|token\|key'history-redact explain-security to understand boundaries# See what would be redacted
history-redact test "curl -u admin:secret123 https://api.example.com"
Output:
Original command:
curl -u admin:secret123 https://api.example.com
Redacted command:
curl -u admin:[REDACTED] https://api.example.com
Matches (1 rule):
1. Pattern: -u\s+[^:]+:\S+
Before: curl -u admin:secret123 https://api.example.com
After: curl -u admin:[REDACTED] https://api.example.com
Add to ~/.config/history-redact/rules.conf:
# Redact email addresses
\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b|||[EMAIL_REDACTED]
# Redact IPv4 addresses
\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b|||[IP_REDACTED]
# Redact credit card numbers (basic)
\b[0-9]{4}[- ]?[0-9]{4}[- ]?[0-9]{4}[- ]?[0-9]{4}\b|||[CC_REDACTED]
# Custom API token format
myapp_token_[a-zA-Z0-9]{32}|||[MYAPP_TOKEN_REDACTED]
Then validate:
history-redact validate-config --verbose
# Source the helper function
source ~/.history-redact.zsh
# Redact existing history file (creates backup)
redact-history-file
# Debug build
cargo build
# Release build (optimized)
cargo build --release
# Run tests
cargo test
# Run only unit tests
cargo test --lib
# Run only integration tests
cargo test --test integration_test
# All tests
cargo test
# With output
cargo test -- --nocapture
# Specific test
cargo test test_openai_key_redaction
Contributions welcome! See CONTRIBUTING.md for guidelines.
Q: Does this slow down my shell? A: Negligible. Overhead is <5ms per command, imperceptible to humans.
Q: What if history-redact fails? A: The shell hook is designed to fail gracefully. If the binary fails, the original command is saved to history.
Q: Can I disable redaction temporarily?
A: Yes, comment out the zshaddhistory function in your .zshrc, or:
unset -f zshaddhistory # Disable
source ~/.zshrc # Re-enable
Q: Does it work with HISTFILE customization?
A: Yes, it's completely independent of your HISTFILE location.
Q: Can I see what's been redacted?
A: Use history-redact test <command> to preview redaction before execution.
Q: Will it redact commands I've already run?
A: No, it only affects new commands. Use redact-history-file to redact existing history.
Q: Is it safe for production systems? A: Yes, but remember: this protects history files only. For comprehensive secret management, use proper secret stores (Vault, AWS Secrets Manager, etc.).
Q: Is this enough for production/compliance requirements? A: No. History Redactor is a hygiene tool, not a complete security solution. Compliance frameworks (PCI DSS, HIPAA, SOC 2) require comprehensive secret management, audit logging, and multiple layers of security controls. Use this as ONE layer in defense-in-depth.
Q: Can attackers still see my secrets?
A: Yes. Secrets passed as command-line arguments are visible via process monitoring (ps), audit logs, network traffic, and terminal recordings during execution. This tool ONLY protects the history file after execution.
Q: Should I still use proper secret management? A: Absolutely! This is supplementary protection. Always prefer:
Q: Does this work with audit logging? A: History Redactor operates after command execution, so audit systems (auditd, sysdig) will still capture the original unredacted command. This tool protects the history file, not real-time monitoring.
cargo install supportMIT License - see LICENSE file for details.
regex crateImportant: This tool helps prevent secrets from being written to shell history, but it's not a substitute for proper secret management practices. Always use environment variables, secret stores, and proper access controls for sensitive credentials.