Stop Leaving Passwords in Your Linux Shell History

Sometimes when you have to check functioning of service or troubleshoot connection of apps in Development or Test environments, you need to SSH into server and run commands with sensitive data.

For example you may run the application’s docker container with specific env variables in order to check the container’s connection to the database:

docker run -d --name app \
-p 80:3000 \
-e DB_HOST=my-db.us-east-1.rds.amazonaws.com \
-e DB_USER=<username> \
-e DB_PASSWORD=<password>
-e DB_NAME=my_db
dkr.ecr.us-east-1.amazonaws.com/app-repo:v1.0.0

As you can see, here we type sensitive values of DB_USER and DB_PASSWORD right into the shell. If not properly managed, these values end up in shell history where everyone who has access to the server can view it.

To avoid storing sensitive commands in the shell history, follow these best practices:

Use a Space Before the Command

If your shell supports it (e.g., bash), prefix the command with a space. This relies on the HISTCONTROL environment variable being set to ignorespace. Using the HISTCONTROL variable you can control how bash stores your command history. You can tell it to ignore duplicate commands and/or to ignore commands that have leading whitespace.

export HISTCONTROL=ignorespace

If HISTCONTROL variable has the value of ignoreboth then the setting for using the space prefix is set.

echo $HISTCONTROL
Remember that this setting is temporary for the duration of running shell session.

You can set the flags in your ~/.bashrc file or in the global /etc/bash.bashrc file. The following command would append it to your ~/.bashrc file:

echo "HISTCONTROL=ignoreboth" >>~/.bashrc

Disable History Temporarily

Disable history logging for the current shell session before running the command:

set +o history
psql -h <db_endpoint> -U <db_name> -p 5432
set -o history

Use a Secure Method to Read Passwords

Use tools like read with -s to hide the password input:

read -sp "Enter Password: " PASSWORD
docker run -d --name app \
-p 80:3000 \
-e DB_HOST=my-db.us-east-1.rds.amazonaws.com \
-e DB_USER=<username> \
-e DB_PASSWORD=$PASSWORD
-e DB_NAME=my_db
dkr.ecr.us-east-1.amazonaws.com/app-repo:v1.0.0

Remove Specific Entries from History

If a sensitive command has been accidentally logged, remove it from the history:

history -d <line_number>

Or clear the entire history:

history -c

Set Alias to Clean History After Logout

In your .bash_aliases file set the following logout command to clean the history and exit the session:

alias logout="history -c && exit"

Set Patterns to Ignore Specific Commands

The HISTIGNORE environment variable controls which commands are entered into the history and which are ignored. It contains a list of patterns separated by colons (:) that when matched, drops a command rather than includes it in the file. For example to ignore all export commands:

HISTIGNORE=" :export *"

You do not need to export this variable.

Be warned however than ignoring an item from the history means that it cannot be recalled by any means — not even with the up and down arrows.

Use Encrypted Storage for Sensitive Variables

For frequently used sensitive data, consider using tool like pass. This is a password manager for Linux systems.

To install pass on Ubuntu:

sudo apt-add-repository universe
sudo apt-get update
sudo apt-get install pass

For example, to store the API key for a service like GitHub:

pass init --path=github/api_key gpg-id="<GPG_ID>" # Initialize store
pass insert github/api_key/my_pass # Store password

Retrieve the API key securely when needed:

API_KEY=$(pass github/api_key/my_pass)

Use the API key in your command:

curl -H "Authorization: token $API_KEY" https://api.github.com/user

Use GUI Tools to Manage Shell History

You can use the open-source shell manager tools like altuin to manage your shell history.

To delete specific entries in history, select specific command with arrow, type <CTR-O> and then <CTR-D>.

References: