Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 

Repository files navigation

shhh

A single-file shell secret manager backed by GPG symmetric (AES256) encryption.

Each secret is stored as ~/.shhh/<name>.gpg. Listing never decrypts; only get and edit ever touch plaintext. Values never appear in process arguments, shell history, or persistent temp files.

Install

cp shhh ~/.local/bin/shhh
chmod +x ~/.local/bin/shhh

Make sure ~/.local/bin is on your $PATH (add to ~/.zshrc or ~/.bashrc if needed):

export PATH="$HOME/.local/bin:$PATH"

Dependencies

Dependency How to install
bash ≥ 3.2 Pre-installed on Linux and macOS
gpg (GnuPG) pacman -S gnupg · apt install gnupg · brew install gnupg
sha256sum or shasum Pre-installed on Linux and macOS
shred Optional — overwrites temp files before deletion; falls back to rm -f if absent (not available on macOS)

Environment variables

Variable Default Purpose
SHHH_DIR ~/.shhh Directory where <name>.gpg files are stored
EDITOR nvim Editor opened by shhh edit
TMPDIR /tmp Base directory for temp files used by shhh edit

Usage

# Store a secret — prompted silently, confirmed
shhh set db_password

# Store from a pipe (one trailing newline is stripped)
echo "s3cr3t" | shhh set api_key
printf '%s' "s3cr3t" | shhh set api_key

# Retrieve — output is exactly the stored bytes, no newline added
shhh get db_password
shhh get api_key | pbcopy                       # copy to clipboard (macOS)
shhh get api_key | xclip -selection clipboard   # copy to clipboard (Linux)

# Use inline in scripts
psql "postgres://user:$(shhh get db_password)@host/db"

# List all secret names (never decrypts)
shhh list

# Edit a secret in place
shhh edit api_key
EDITOR=nano shhh edit api_key   # override editor for one invocation

# Rename or copy (operates on .gpg files directly — no decryption)
shhh rename api_key stripe_api_key
shhh cp stripe_api_key stripe_api_key_backup

# Delete (asks for confirmation)
shhh rm stripe_api_key_backup

# Generate a random secret from /dev/urandom (base64-encoded)
shhh gen session_secret          # 32 bytes (default)
shhh gen signing_key 64          # 64 bytes

Passphrase and pinentry

GPG will prompt for your symmetric passphrase via whatever pinentry program is configured in ~/.gnupg/gpg-agent.conf. On a desktop this is often a GUI dialog. To keep everything in the terminal, install a terminal-based pinentry and point the agent at it:

Arch / Debian / Ubuntu

# Arch
sudo pacman -S pinentry

# Debian / Ubuntu
sudo apt install pinentry-tty
# ~/.gnupg/gpg-agent.conf
pinentry-program /usr/bin/pinentry-tty

macOS

brew install pinentry-mac
# ~/.gnupg/gpg-agent.conf
pinentry-program /opt/homebrew/bin/pinentry-mac

Reload the agent after any change to gpg-agent.conf:

gpg-connect-agent reloadagent /bye

Caching the passphrase

By default GPG prompts on every get or edit. To cache it:

# ~/.gnupg/gpg-agent.conf
default-cache-ttl 3600    # seconds since last use (1 hour)
max-cache-ttl     86400   # hard ceiling (24 hours)

Security tradeoff: while the passphrase is cached, any process running as your user can decrypt your secrets without a prompt. Set default-cache-ttl 0 to disable caching entirely.

Security design

  • $SHHH_DIR is created chmod 700; every .gpg file is chmod 600.
  • Plaintext values never appear in process arguments (visible via ps) or shell history.
  • Encryption writes to a staging temp file first and only replaces the destination with mv on success — a failed encryption cannot truncate an existing secret.
  • All temp files are registered on creation and removed by an EXIT trap (via shred -u if available, otherwise rm -f), including on unexpected failure.
  • shhh list, shhh rename, and shhh cp never decrypt anything.

Caveats

edit writes plaintext to disk The decrypted value lives in $TMPDIR during editing. On most Linux systems $TMPDIR is tmpfs (RAM-backed), but this is not guaranteed. For automated use, prefer set/get.
Shared passphrase All secrets share one GPG passphrase. There is no per-secret key. Anyone with the passphrase can decrypt every secret in $SHHH_DIR.
No versioning shhh set overwrites silently. There is no history or audit log.
/dev/tty required The TTY prompt (set), delete confirmation (rm), and editor (edit) all open /dev/tty. This fails in fully detached environments such as some CI runners — use pipe mode for set and avoid rm/edit in those contexts.
Filesystem atomicity mv is only atomic when source and destination share a filesystem. The staging file is created inside $SHHH_DIR to guarantee this. If you point SHHH_DIR at a separate mount point, verify this still holds.
Multi-line pipe input Only one trailing newline is stripped. `printf 'a\nb\n\n'

About

keep it between us - AES256 encrypted secrets, straight from your terminal

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages