Skip to main content
  1. Posts/

Disable Shell History Safely - Advanced OPSEC for Linux Operations

··1536 words·8 mins· loading · loading · ·
Table of Contents

Greetings, digital ghosts and phantoms. UncleSp1d3r here.

In the world of red teaming and adversarial simulation, silence isn’t just golden—it’s 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 legitimate users to remember what they did last Tuesday. They dutifully record every command, every typo, and unfortunately, every password you were too lazy to store safely elsewhere. 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.

  1. Do not wipe logs unless explicitly authorized. Deleting .bash_history is an Indicator of Compromise (IOC) in itself.
  2. Do not blind the blue team if the goal is a “Purple Team” or detection engineering exercise.
  3. Always have a rollback plan. If you edit 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, often managed by the shell process itself.

The Risks
#

  1. Credential Leakage: mysql -u root -pSuperSecretPassword. If this goes into ~/.bash_history, the next person who runs cat ~/.bash_history owns the database.
  2. tradecraft exposure: Your history file is a chronological playbook of your attack path. It reveals your tools, your C2 domains (if you wget a payload), and your techniques.
  3. lateral movement mapping: Secrets used to pivot to other machines often end up in history, allowing defenders to trace your path backward and forward.
  4. timeline reconstruction: 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. They see execve calls regardless of your HISTFILE setting.
  • Syslog/auditd: If the system administrator has configured audit rules to log execve system calls (e.g., auditctl -a always,exit -F arch=b64 -S execve), /var/log/audit/audit.log will still capture your commands.
  • keyloggers: Hardware keyloggers and OS-level hooks capture everything you type.
  • Snoopers: Other users running w or ps aux while you are typing.

Takeaway: 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 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.

  1. Backup the current history (optional, but good for safety).
  2. 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:

  1. Check your shell: Is it Bash, Zsh, or Fish?
  2. Check the logging: echo $HISTFILE, echo $HISTCONTROL, echo $PROMPT_COMMAND.
  3. Go Dark: unset HISTFILE or set +o history.
  4. Verify: Run a benign command, check if it persists (in a new tab if valid).
  5. Operate: Do your work.
  6. 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.


References
#

UncleSp1d3r
Author
UncleSp1d3r
As a computer security professional, I’m passionate about building secure systems and exploring new technologies to enhance threat detection and response capabilities. My experience with Rails development has enabled me to create efficient and scalable web applications. At the same time, my passion for learning Rust has allowed me to develop more secure and high-performance software. I’m also interested in Nim and love creating custom security tools.