Clever uses of pass, the Unix password manager

2020-08-11 @Technology

Pass (main site, Arch wiki) is a command-line Unix password manager that utilizes GPG for all underlying encryption. However, beyond passwords, we can utilize it in a number of clever ways.


General usage

More of a prereq than a tip, install bash-completion or whatever shell completion that pertains to you. Pass usage becomes vastly easier once all command-line arguments and password-store hierarchy conveniently expand as you type.

First, all proceeding operations impact your password store directory, this either $HOME/.pass or $PASSWORD_STORE_DIR.

Initialize the main password store. This merely creates the respective folder with a .gpg-id file containing your desired gpg key identifier.

pass init <gpg id>

Insert new passwords

pass insert ebay
pass insert email/user1
pass insert email/user2

Each prompts you to enter and reenter the desired password. The first creates ebay.gpg within your password store directory, the latter two user1.gpg and user2.gpg within the email sub-folder. (Optional: append the -e flag to echo the entered text to your terminal in exchange for only one entry prompt.)

The flexibility of any directory hierarchy is extremely helpful for password organization and command-line auto-completion. Furthermore, pass creates all missing sub-folders to any level of depth.

Generate new passwords

pass generate -c <acct_critical> 20
pass generate -c -n <acct_non_critical> 10

The first creates a more secure, alpha-numeric and symbolic 20-character password. The second creates an alpha-numeric only password (-n = no symbols) of 10 characters. Both copy the password to the system clipboard (-c) rather than echo it to the terminal.

Access an existing password

pass acct_non_critical
pass -c email/user1

The first echoes the password to the terminal in plain glory. The second copies the password to the system clipboard for the default 45 seconds, this handier and far more secure.

Again, auto-completion is wonderful when entering these commands.

Edit an existing password

This opens up the password for editing within your configured text $EDITOR.

pass edit <name>

Copy, move, delete

pass cp email/user1 email/user3
pass mv user4 email/user4
pass rm old_account
pass rm -r email

The first effectively copies user1.gpg to user3.gpg, both to have the same password. The second moves user4.gpg to email/user4.gpg. The third deletes old_account.gpg. The fourth recursively clears the entire email subfolder of passwords.

All of these operations you can also execute using the plain unix cp/mv/rm on the respective files in the password store directory. There’s no other metadata to consider. The mechanism is quiet simple and transparent!

File encryption and multi-line password files

pass supports multi-line passwords, manually entered via pass insert -m <name> or edited/appended via pass edit <name>. With edit you can even expand an initially single-line password file.

Following traditional usage, a multi-line password might resemble the following:

street address

The default copy command pass -c only copies the first line of such a multi-line password file, in this case the very password.

However, pass edit or pass [show] enables you to edit/see the entire blob.

Additionally, pass -c[num] copies the indicated line.

We can thus store any amount of data in a ‘password’ file, including entire documents.

Here we pipe a file secret_answers.txt for encrypted storage within the password file sensitive/secret_answers:

pass insert -m sensitive/secret_answers < secret_answers.txt
# Or
cat secret_answers.txt | pass insert -m sensitive/secret_answers

Better yet, to recursively encrypt an entire directory sensitive_dir within the folder sensitive of your password store, folder structure maintained:

for file in $(find sensitive_dir -type f); do 
    pass insert -m "sensitive/$file" < "$file" > /dev/null 

You could also achieve the above via direct gpg manipulation outside your password store. However, pass greatly abstracts the viewing and especially the editing of such encrypted data with the simplicity of the pass edit command.

One might suggest an encrypted container or filesystem solutions. This is ultimately a matter of taste. For my part, I’ve never cared much for their relative complexity of implementation, configuration and management.

The amount of frequently read/written files that I consider encryption-worthy (beyond whatever security inherent to their storage medium), tends to number relatively small. I’d rather deal with the ad-hoc encryption of individual files, and pass makes this seamless.

Other sensitive data encryption

I don’t like sensitive bits to be plain text viewable, be it strictly for my own eyes. This includes not only passwords but possibly compromising API keys or other access codes.

These often appear within command line arguments or configuration files. Here I present a few use to circumvent the issue with pass.


Cloud providers often feature HTTP based APIs requiring a key. With curl, we might access the API as such:

curl -H "API-Key: <sensitive>" ...

I’d rather the plain key not appear, per the incorporation of this shell call to pass:

curl -H "API-Key: $(pass provider/api_key)" ...


s3cmd enables CLI access to the Amazon S3 object storage. The $HOME/.s3cfg config annoyingly echoes the access/secret keys in plain text form:

access_key = <sensitive>
secret_key = <sensitive>

Instead, we can set them to blank strings (necessary for proper functioning)

access_key = ''
secret_key = ''

and setup the following alias to pass the keys on the command line, encrypted in our password store:

alias s3cmd="s3cmd --access_key="'$(pass aws/access)'" \
    --secret_key="'$(pass aws/secret)'

Note above the single quotes around the invocation of $(pass ...). This is necessary to postpone the command evaluation until execution, rather than the resulting keys appear directly in your rendered alias.

isync/mbsync and mstmp

mbsync locally syncs your Imap email mailbox. I personally don’t wish to be prompted for the account password on each synchronization.

The solution either requires storing the plain text password in the Pass directive of the .mbsyncrc config file, or the alternative password evaluator directive as follows:

PassCmd "pass email/user1"

The identical situation presents itself in the case of msmtp, the email sending framework. To store a password in the config, we could either opt for the plain text password <plain text>, or

passwordeval "pass email/user1"

Once again, pass to the rescue.

Questions, comments? Connect.