Handle Secrets
Best practices for handling secrets that users pass to your CLI tool (API keys, tokens, passwords), not secrets used during development.
Core Principles
- Never accept secrets as command-line arguments - Arguments are visible via
ps aux, recorded in shell history, and captured by audit logs - Make the secure path the default - Users who do nothing special should get the safest behavior
- Separate config from credentials - Non-sensitive settings and secret material belong in different files
- Mask secrets in all output - Debug logs, error messages, HTTP traces, and verbose output must redact secret values
- Warn loudly about insecure behavior - If users opt into something dangerous, tell them explicitly
Security Hierarchy (Safest to Most Dangerous)
| Method | Safety | Use when |
|---|---|---|
| OS keychain / credential helper | Safest | Persistent storage for interactive users |
Secret references (op://, vault URIs) |
Safe | Storing pointers instead of secrets |
| Stdin / pipes / file descriptors | Safe | Automation and scripting |
| Interactive TTY prompt | Safe | Human users at a terminal |
| Config files (0600 permissions) | Acceptable | Persistent storage without keychain |
| Environment variables | Acceptable | CI/CD pipelines and containers |
| Command-line arguments | Never | - |
Workflow
- Quick reviews: Check against
references/checklist.md - Choosing an input method: Read
references/security-hierarchy.md - Designing credential flows: Read
references/design-patterns.md - Avoiding known pitfalls: Read
references/anti-patterns.md - Language-specific code: Read
references/language-libraries.md
Reference Navigation
Quick reviews (default):
references/checklist.md- Condensed, actionable rules
Deep dives by topic:
references/security-hierarchy.md- Ranked input methods with attack surfaces and mitigationsreferences/design-patterns.md- Credential fallback chains, OAuth device flow, token hygiene, maskingreferences/anti-patterns.md- Real CVEs and incidents from insecure secret handlingreferences/language-libraries.md- Rust, Go, Python, Node.js, Ruby libraries and code patterns
Credential Resolution Fallback Chain
Tools should resolve credentials in this order:
- Environment variable (for CI/CD)
- Credential helper / OS keychain (for persistent storage)
- Config file with 0600 permissions (fallback)
- Interactive TTY prompt (for humans)
Never fall through to accepting --password <value> as an argument.
Sources
- Building CLI tools that handle user secrets responsibly - Mac Chaffee
- GitHub CLI, Docker, AWS CLI, kubectl, and 1Password CLI implementations