Greetings, digital ghosts and phantoms. UncleSp1d3r here.
In the world of red teaming and adversarial simulation, silence is not just golden—it is survival. One of the most common tradecraft failures I see during engagements is the accidental leakage of sensitive information into shell history files. It’s a rookie mistake that burns operations, exposes credentials, and leaves behind a “how-to” guide for anyone who compromises the system after you.
By default, most shells are helpful. They want you to legitimate users to remember what you did last Tuesday. They dutifully record every command, every typo, and unfortunately, every hardcoded password you were too properly lazy to put into a file. For us, this “helpfulness” is an operational security (OpSec) nightmare.
This article is a deep dive into the mechanics of shell history, how to disable it safely, how to manage it when it’s already there, and crucial context on what these techniques won’t hide from a competent blue team.
[!IMPORTANT] Rules of Engagement Warning
The techniques described here are for minimizing your footprint and preventing credential leakage.
- Do not wipe logs unless explicitly authorized. Deleting
.bash_historyis an Indicator of Compromise (IoC) in itself.- Do not blind the blue team if the goal is a “Purple Team” or detection engineering exercise.
- Always have a rollback plan. If you modify a user’s shell configuration, put it back when you leave.
The Anatomy of the Footprint
Before we start disabling things, we need to understand what we are fighting. Command history is a convenience feature, usually managed by the shell process itself.
The Risks
- Credential Leakage:
mysql -u root -pSuperSecretPassword. If this goes into~/.bash_history, the next person who runscat ~/.bash_historyowns the database. - Tradecraft Exposure: Your history file is a chronological playbook of your attack path. It reveals your toolset, your C2 domains (if you
wgeta payload), and your methodology. - Lateral Movement Mapping: Secrets used to pivot to other machines often end up in history, allowing defenders to trace your path backward and forward.
- Timelining: Even without timestamps (though most modern shells add them), the order of commands helps incident responders reconstruct the incident with frightening accuracy.
The False Sense of Security
Disabling shell history prevents the shell from writing to a file. It does not prevent:
- EDR/XDR Telemetry: Modern Endpoint Detection and Response tools hook the kernel (e.g., via eBPF or Auditd) to see process execution.
execvecalls are seen regardless of yourHISTFILEsetting. - Syslog/Auditd: If the system administrator has configured audit rules to log
execvesyscalls (e.g.,auditctl -a always,exit -F arch=b64 -S execve), your commands are logged to/var/log/audit/audit.log. - Keyloggers: Obviously.
- Snoopers: Other users running
worps auxwhile you are typing.
Takeway: Disabling history is for cleanup and credential hygiene, not for evading active EDR.
Mastering Bash History Control
Bash (Bourne Again Shell) is the industry standard. If you are on a Linux box, you are likely in Bash.
Temporary Disabling (The “Space” Trick)
This is the absolute minimum viable OpSec. Most default .bashrc files (especially on Ubuntu/Debian) contain:
HISTCONTROL=ignoreboth
This sets ignorespace and ignoredups. It means if you start your command with a space, it won’t be saved to history.
$ whoami
# ^ Note the leading space. This safe.
However, never trust, always verify. Check existing settings:
echo $HISTCONTROL
If it’s empty, user export HISTCONTROL=ignoreboth immediately.
The Session Kill Switch
To disable history for the current session without modifying any permanent files or variables that might look suspicious in a process dump (less suspicious than unset):
set +o history
This stops the shell from adding lines to the history list in memory. To re-enable it:
set -o history
The Nuclear Option: Nullifying the File
The HISTFILE variable determines where history is written when the shell exits. If you unset it or point it to nothingness, nothing is written.
# Option 1: Unset the variable (Most Common)
unset HISTFILE
# Option 2: Point to the void (Safer if applications expect the var to exist)
export HISTFILE=/dev/null
# Option 3: Reduce size to zero
export HISTSIZE=0
export HISTFILESIZE=0
Recommendation: Put this in your initial “landing” snippet or alias.
Advanced Bash: The PROMPT_COMMAND Trap
Some paranoid sysadmins use PROMPT_COMMAND to log every command to syslog immediately, bypassing standard history files.
Check it:
echo $PROMPT_COMMAND
If you see something like logger -p local0.notice ..., you are being watched in real-time. You can attempt to unset it:
unset PROMPT_COMMAND
Warning: If the admin is alerting on this variable changing, you just tripped an alarm.
The .bash_history File Attributes
Sometimes you can’t write to history because the admin made it immutable. Check attributes:
lsattr ~/.bash_history
If you see the a (append only) or i (immutable) flags, you cannot delete entries, only append (or nothing). You shouldn’t be messing with chattr unless you are root, and if you are root, you have bigger fish to fry.
Zsh (Z Shell) OpSec
Zsh is the default on macOS and increasingly common on developer machines (Kali uses it by default now too).
The Private Mode
Zsh generally does not respect HISTCONTROL=ignorespace. Instead, it uses setopt.
To prevent the current shell from saving history:
# Unset the save file
unset HISTFILE
# Disable specific options
unsetopt SHARE_HISTORY
unsetopt INC_APPEND_HISTORY
The “Leading Space” equivalent in Zsh is:
setopt HIST_IGNORE_SPACE
Zsh “Private” Shell
If you can start a new shell instance, Zsh offers a specific mode for this:
zsh --private
This is excellent for one-off tasks where you don’t want to mess with the user’s current environment.
Fish Shell
Fish is friendly. Too friendly. It has aggressive autosuggestions based on history.
Private Mode
Like Zsh, the best way to operate in Fish is to launch a private session:
fish --private
Session Specific
If you are stuck in an existing session:
set -g fish_history ""
This tells Fish not to load or save history for the global scope of this session.
Other Shells & Interpreters
Often, we forget that it’s not just the shell logging us. Interactive interpreters have their own history files.
Python
If you drop into a python shell to do some quick math or decoding, it logs to ~/.python_history.
Prevention:
export PYTHONHISTORY=""
# Or inside python:
import os
import readline
readline.clear_history()
MySQL / PostgreSQL
mysql client logs to ~/.mysql_history.
psql client logs to ~/.psql_history.
Prevention:
export MYSQL_HISTFILE=/dev/null
export PSQL_HISTORY=/dev/null
Less / Vim
Yes, even less maintains a history file (~/.lesshst) of search terms! If you search for a password inside a log file using /password, that search term is saved.
Prevention:
export LESSHISTFILE=-
Vim uses ~/.viminfo.
Prevention: Use vim -i NONE to start vim without reading or writing the info file.
PowerShell on Linux (pwsh)
Microsoft’s PowerShell is now cross-platform and very popular in DevOps environments. It maintains a history file at ~/.local/share/powershell/PSReadLine/ConsoleHost_history.txt.
Disabling Tracking:
Set-PSReadLineOption -HistorySaveStyle SaveNothing
Safe Session:
pwsh -NoProfile -NoExit -Command 'Set-PSReadLineOption -HistorySaveStyle SaveNothing'
Automated Hygiene Script
Here is a bash function you can copy-paste into your terminal (using the leading space trick!) to set up a cleaner environment for your current session.
# Start with a space!
clean_env() {
# Disable Bash History
unset HISTFILE
export HISTSIZE=0
export HISTFILESIZE=0
# Disable Python History
export PYTHONHISTORY=""
# Disable MySQL History
export MYSQL_HISTFILE=/dev/null
# Disable Less History
export LESSHISTFILE=-
# Tell user status
echo "[+] Operational Security: Session history logging disabled."
echo "[+] Note: Active logging (auditd/syslog) is NOT disabled."
}
Incident Response: “I messed up”
So you typed aws configure and pasted the secret key, and then realized you weren’t in a private shell. Now it’s on disk.
Do NOT just rm ~/.bash_history.
Deleting the file is suspicious. A user almost never deletes their entire history file.
Surgical Deletion
Use sed to remove the specific line.
- Backup the current history (optional, but good for safety).
- Edit in place.
# Using sed to delete lines containing "SecretKey"
sed -i '/SecretKey/d' ~/.bash_history
# Reload history into current session (if you are staying)
history -r
The “Cat” Method
If you need to truncate hiddenly without changing the inode (which sed -i might do depending on implementation), you can cat into it.
# Read everything NOT matching your secret, write to temp
grep -v "SecretKey" ~/.bash_history > /tmp/.hist
# Overwrite original
cat /tmp/.hist > ~/.bash_history
# Remove temp
rm /tmp/.hist
Summary Checklist
Before you type a single sensitive character on a target system:
- Check your shell: Is it Bash, Zsh, or Fish?
- Check the logging:
echo $HISTFILE,echo $HISTCONTROL,echo $PROMPT_COMMAND. - Go Dark:
unset HISTFILEorset +o history. - Verify: Run a benign command, check if it persists (in a new tab if valid).
- Operate: Do your work.
- Leave No Trace: If you enabled logging temporarily or made mistakes, surgically clean them.
Operational security is not about being invisible to machines—that is technically impossible against a perfect sensor. It is about being invisible to the humans looking at the logs later. Don’t give them a free comprehensive report of your activities.
Stay safe, stay hidden.
UncleSp1d3r out.