DEV Community

Cover image for Your private key doesn't belong in your terminal. Here's the Foundry fix.
Satori Geeks
Satori Geeks

Posted on

Your private key doesn't belong in your terminal. Here's the Foundry fix.

You're about to run forge script --broadcast. The command needs a private key. The options that come to mind first all share the same problem: paste it into the terminal and it ends up in .bash_history or .zsh_history. Put it in .env and it's one accidental git add away from the repo. Hardcode it in the deploy script and it's in version history the moment the file is committed. These aren't theoretical risks — they're how keys get exposed.

There is a better way built directly into Foundry.

Using Foundry's encrypted keystore

Import your private key into an encrypted keystore:

cast wallet import deployer --interactive
Enter fullscreen mode Exit fullscreen mode

The --interactive flag prompts for your private key and a password. Foundry stores the key encrypted at ~/.foundry/keystores/deployer. Nothing touches shell history. The name deployer is arbitrary — use whatever you'll recognise.

Before running a deploy, confirm the import worked:

cast wallet list
Enter fullscreen mode Exit fullscreen mode

This lists all keystores by name. If deployer appears, the import succeeded. Two seconds, one less thing to debug mid-deploy.

Now run the deploy referencing the keystore by name:

forge script script/Deploy.s.sol \
  --rpc-url $RPC_URL \
  --account deployer \
  --broadcast \
  --verify
Enter fullscreen mode Exit fullscreen mode

--account deployer tells Foundry which keystore to use. It prompts for the password at runtime. The private key is not in the command, not in .env, not anywhere in the repository. The password prompt is the only moment the key decrypts, and it never leaves your machine.

What this protects against: shell history logs every command you run — .bash_history, .zsh_history, your terminal emulator's scrollback. .env files get committed. Command arguments show up in process listings. The key is encrypted at rest and decrypted only at deploy time. There is no passive exposure surface.

One note on the password

The password matters. A weak password on an encrypted keystore holding a deploy key for a contract with real funds is not meaningfully safer than .env. Use a password manager. The keystore adds a layer; the quality of your password determines what that layer is worth.


This is now the default for every remaining week of this series. First-time setup took about ninety seconds. The instinct — "I don't feel okay putting it in the terminal" — was right; the tooling already had the answer.

The build this came from: Week 1: Base — 56/60

Scoring methodology for the series: How I'm Scoring the Chains

Top comments (0)