Shell history is one source of leaked credentials. Commands containing API keys, bearer tokens, passwords, or connection strings are often written to history files without much thought.
We shouldn’t do it, but, let’s admit it, we all do it, especially when we feel safe, on a computer entirely under our control.
export OPENAI_API_KEY=sk-...
curl -H "Authorization: Bearer ghp_..." https://api.example.com
psql postgres://alice:password@example.com/db
Best practices
There are best practices and tricks that will help you keep secrets from bash/zsh/fish history. I found "Hiding secret keys from shell history: Part 1" to be extremely useful.
But it’s not just shell history. It may be a SELECT statement in your ~/.mysql_history, or a quick test stored permanently in your ~/.python_history, and so on.
And recently, AI coding assistants have introduced one more secret-concentration point. Claude Code, Codex, Gemini CLI, and Copilot CLI keep full session transcripts on disk; transcripts that may contain secrets copied from .env files, terminal output, or configuration files.
User: Connect to the production database.
Tool output:
DATABASE_URL=postgres://alice:password@example.com/db
OPENAI_API_KEY=sk-...
AWS_SECRET_ACCESS_KEY=...
shg scans these locations for credentials, and anything that looks like an API key or an access token. It scans shell and REPL histories, environment variables, AI agent command histories, and AI agent session transcripts. Everything runs locally, there is no network access or telemetry, and findings are redacted by default.
For example, running shg scan reports secrets found in shell/REPL history files or environment variables:
$ shg scan
[!!!] export OPENAI_API_KEY=s*************...**************5
~/.zsh_history:148 [inline_assign]
[!!!] curl -H "Authorization: Bearer g*************...**************5...
~/.zsh_history:576 [auth_header]
2 finding(s) detected (2 high, 0 medium, 0 low).
Remove flagged history entries and rotate affected credentials.
shg deep scans AI agent transcripts and groups findings by session instead of by line:
$ shg deep
~/.claude/projects/myapp/3f2c….jsonl
[!!!] known_token ghp_****…****2345 (3×, tool_output)
…export GITHUB_TOKEN=ghp_****…****2345…
1 secret(s) across 1 session file(s).
Rotate each credential, delete the affected session files, and make sure
this directory is not synced, committed, or world-readable.
If you are using zsh there is also a way to run shg on every command before it’s stored in history and prevent it from landing there if it contains secrets.
# the command executes normally, but it's not saved to history
$ export GH_TOKEN=ghp_381289xj_82j7nk_23
[shg] Warning: possible secret detected — not saved to history.
shg can’t eliminate the risk of secret leaks. But it makes it easier to discover accidental exposure before history files or agent transcripts are backed up, synchronized, committed, or shared.
shg is currently on v0.2.6 and has been significantly improved since the last time I wrote about it.