We have to be ever more careful with the stuff we store in our disks.
Only in 2025, there were at least half a dozen campaigns exploiting various pieces of modern supply chain software to exfiltrate sensitive data at scale. Some of these events even leveraged AI agents installed in people’s machines to help locate and extract sensitive information like tokens, crypto wallets and service account keys.
Even if you are careful with these things, it’s possible – likely even – that you have at least a couple of tokens or secrets laying around in plain text in your system.1
Unfortunately, many CLI tools still rely on – or at least encourage in “Getting Started”-style guides – insecure practices, such as storing tokens and secrets in plain text configuration files and passing them as command line arguments.
Is the OS Keyring a Viable Option?
If you use Linux with a fully-featured Desktop Environment such as GNOME, chances are you already have a Secret Service implementation installed, that you can interact with via the secret-tool utility:
|
|
While this can fulfill some basic use-cases, the data persistence options for the OS keyring are limited, so you should only use it for non-critical short-lived secrets.
Keyrings also usually stay unsealed for the duration of the user session, making them not suitable for protecting more sensitive information.
Password Managers
For critical and/or long-lived secrets, it’s recommended the usage of a proper password manager solution.
Solutions such as 1Password or Bitwarden would work fine (they both provide CLI tools for interacting with their vaults), but I’ve grown to prefer more lightweight options such as GNU Pass, at least for tokens and secrets that are mainly accessed via the terminal.
Dealing With Environment Variables
Some people just export their tokens in their ~/.bashrc and get on with it. This is not a recommended approach for sensitive information as these variables would be exposed indiscriminately to all user processes.
The same applies for other secrets stored in plain text files in your hard drive. Any process you start could just scan your files, discover sensitive information, and compromise them. This is more and more of a concern these days with the advent of AI tools that still lack proper sandboxing and security controls.
The GoPass Way
GoPass is a GNU Pass reimplementation in Go with a few extra goodies.
One of those goodies is the gopass env subcommand. Suppose you have the following secrets:
| Secret path | Value |
|---|---|
keys/aws/AWS_ACCESS_KEY_ID |
AKIA.. |
keys/aws/AWS_SECRET_ACCESS_KEY |
... |
You can run a command with these vars set with gopass env keys/aws -- aws s3 ls.
This feature alone greatly reduces the need for secrets stored in plain-text configuration files, since most tools allow you to pass credentials via environment variables as an alternative.
However, this implementation doesn’t cover all my needs for consuming secrets in the terminal. For instance, it’s not possible to run a command with secrets from multiple different prefixes (say a GitHub token + AWS credentials), unless you lay out your passwords in a specific way, possibly by duplicating files or symlinking files around.
My New Way (With GNU Pass)
After reading the GNU Pass main page recently I came across a section Extensions for pass. I used GNU Pass for many years and didn’t know that it could be extended like that!
So I decided to ask my new best friend Claude Code to come up with an extension that worked just like the gopass env subcommand, but with more options for composing secrets.
The full up-to-date version for this script can be found here, but the API looks like this:
|
|
You can use this by putting this file in /usr/lib/password-store/extensions or whatever that directory is for your distro.2
Security Considerations
This approach may have some security considerations of their own. In other words, do not blindly follow me, I may not know what I’m doing. 😄
A couple of things I can think of:
- As with any solution based on environment variables, the env vars for the launched processes can still be accessed via
/proc/<pid>/environand theps ecommand. - Exported variables are available to children processes, not only the original process launched by the script.
Alternative Approaches
Linus Heckemann’s Blog provide an alternative and more secure approach by not relying on environment variables at all, which of course can be more or less applicable depending on your workflow and the tools involved.
One particularly nice trick is the usage of process substitution capabilities supported by many of the modern shells, including bash, which suits tools like curl and vault:
|
|
The secrets extracted from GNU pass in the previous commands would not show up in usual places such as /proc/<PID>/environ and /proc/<PID>/cmdline, making this a very strong option for more sensitive tasks.
Of course you can also leverage Bash Aliases or Functions for abstracting away the details about how secrets are injected onto your most frequent commands.
SSH Keys
Other common type of secret to have laying around are SSH keys.
A recommendation is to use a hardware token such as the YubiKey for this, keeping the private key material secure, meaning that you don’t need to keep your SSH keys in your filesystem anymore. You can also configure the token to require “touch” confirmation for different operations, such as signing, encryption, or authentication, depending on your security and convenience requirements.
After configuring gpg-agent to also act as the SSH agent, you could use ssh-add -L to display the public key (which you can then add to ~/.ssh/authorized_keys on your servers), and ssh should forward authentication requests to the GPG agent.
If you choose this path, I’d strongly recommend checking out drduh’s Yubikey Guide.
Other option would be to leverage your own password manager’s features. Bitwarden (here) and 1Password (here), for instance, allow you to store your public and private keys in the password manager itself and then allow access to them via custom SSH agent implementations that you can plug into your system.
Closing Note
The idea for this post is just to show you how I do it. It may or may not work for you, and it’s definitely not the only way to do it, so feel free to experiment and choose whatever works best for you considering your security requirements!
-
You can use tools like TruffleHog for scanning your files. ↩︎
-
While possible, I advise against storing GNU Pass extensions in your
$HOMEbecause some malicious tool could inject undesired behavior to your extensions right after your secrets are decrypted. ↩︎