The first time I saw a customer's email address printed in plain text in a log file, I felt my stomach drop. It wasn’t just careless. It was dangerous.
Masking email addresses in logs is not optional. It’s a necessity. Whether you’re debugging a CLI tool, scripting a quick fix, or handling shell completions, unmasked personal data in logs is an open door. Once it’s written down, it’s hard to erase. It spreads.
Logs pile up. They sync across environments. They’re backed up, copied, and inspected by people who don’t always need to see the data inside them. If an email address is there in full, it’s already too late. The fix is simple: mask it before it ever makes it to disk or stdout.
Why Logs Leak Emails
Shell tools often print more than you think. Add autocompletion to the mix—bash, zsh, or fish—and you have scripts echoing data you never intended to reveal. Completion scripts can trigger commands in subtle ways. These commands can output sensitive strings even when the user never runs them directly.
One forgotten debug echo. One verbose flag left turned on. That’s all it takes.
How to Mask Email Addresses in Shell Logs
Pattern matching and substitution are your best friends here. In bash or zsh, a basic regex can replace everything between the first character and the domain, leaving only minimal context. For instance:
sed -E 's/([a-zA-Z0-9._%+-])[^@]*(@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/\1***\2/g'
This transformation makes user@example.com become u***@example.com. The logs still work for identifying sessions, but the exact address is gone.
You should mask at the source of logging, not after the fact. If your CLI completion scripts run helper commands, ensure they never print unmasked data in the first place. Bake the regex into those scripts or a shared shell library.
Testing for Leaks
Don’t assume your code is safe—test it. Create mock email addresses and run your shell completion scripts. Capture the output. Search for @ signs and review each match. If you find a full address, patch the script.
Automate this in CI so the mistake never reappears. Every time new completion code or logging logic changes, run the checks again. Make it part of your definition of done.
Masking Beyond the Shell
The same logic applies to server logs, cron jobs, and temporary debug files. If a script touches a real email address, strip it or mask it before it leaves memory. This isn’t about hiding errors—it’s about following the principle of least exposure.
See It Done Right
You can spend days wiring this up yourself—or you can see it done right, live, in minutes. Check out how hoop.dev handles secure logging and shell integration without leaking sensitive data. Set it up, run your flow, and watch your logs stay clean.
The best time to mask data is before it ever hits the log. The second best time is now.