Your credential attack surface
A software developer's credential attack surface is vastly larger than a typical employee's. In a given week, a developer might authenticate to: GitHub/GitLab, AWS/GCP/Azure console, production and staging databases, Vercel/Netlify/Railway, Stripe, PagerDuty, Datadog, Sentry, internal admin panels, SSH servers, Kubernetes clusters, HashiCorp Vault, and a dozen SaaS tools. Each is an attack vector. Each credential, if compromised, can cascade.
Developer credentials are also disproportionately high-value targets. A compromised GitHub account with production deploy access is worth vastly more to an attacker than a standard employee's email account. Supply chain attacks — injecting malicious code via compromised developer credentials — have caused some of the most damaging breaches of the past five years (SolarWinds, Codecov, CircleCI).
Personal account hygiene
Start with the fundamentals before addressing the developer-specific risks:
- GitHub/GitLab: Enable MFA (prefer hardware key or TOTP, not SMS). Use SSH keys for repository access rather than HTTPS with password. Enable commit signing with GPG.
- Cloud consoles: MFA on every cloud account without exception. Root/owner accounts should use hardware MFA (YubiKey). Enable login notifications.
- Email: Your developer email account is a recovery target for every other account. It needs the strongest MFA you have — hardware key if possible. If it falls, everything falls.
- Package registry accounts: npm, PyPI, RubyGems — these accounts can be used to push malicious packages. Enable MFA. Review what you've published and whether it's still maintained.
Secrets management fundamentals
The core principle: secrets should never be stored in the same place as code. The mechanisms for achieving this have matured significantly:
- Development: Use
.envfiles (never committed) or local secrets manager tooling (1Password CLI, Doppler, direnv) - CI/CD: Use your platform's native secrets store (GitHub Actions Secrets, GitLab CI Variables, CircleCI Contexts) — never hardcode in workflow files
- Production: Use a dedicated secrets management service: HashiCorp Vault (self-hosted), AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, Doppler, or Infisical
- Rotation: All production secrets should be rotatable with zero downtime. If rotating a secret requires a deploy, the architecture has a problem.
The secret management hierarchy in a well-run system:
- Vault / cloud secrets manager holds the canonical secret
- Applications authenticate to the vault using short-lived tokens (IAM roles, Vault dynamic credentials)
- Secrets are injected at runtime, never written to disk or included in container images
- Access to the vault itself is logged, audited, and protected with hardware MFA
.env files and what goes wrong
The .env file pattern is ubiquitous in development. It works well when used correctly and catastrophically when not. The rules:
- Always add
.envto.gitignorebefore the first commit. Adding it later doesn't remove existing history — you need to usegit filter-branchorgit filter-repo, and the credentials may already be on remotes or forks. - Commit a
.env.examplewith dummy values but never commit a.envwith real values, even in a private repository. - Private repositories are not secret storage. GitHub employees, GitHub security scanning, future collaborators, and anyone who gets read access to the repo all see the full Git history. A secret in a private repo's history is a secret that has been shared with GitHub infrastructure.
- Different secrets per environment. Development, staging, and production should have different credentials. A developer's local
.envshould never contain production database credentials.
Credentials in Git — the biggest risk
Accidentally committing credentials to a Git repository is the most common developer security incident. GitHub's secret scanning service finds and reports known credential patterns automatically, but by the time a notification arrives, the secret may already have been indexed by public scanners.
If you commit a secret to a public repository:
- Revoke the secret immediately — before fixing the code, before telling anyone. The secret is already compromised.
- Check your cloud provider's access logs for the period since the commit to identify any unauthorised use
- Rotate the secret to a new value
- Remove the secret from Git history using
git filter-repo(the modern replacement forfilter-branch) - Force-push to overwrite the history on all remotes
- Notify any forks or collaborators who may have cloned the repository during the exposure window
Tools that help prevent this: git-secrets (AWS), detect-secrets (Yelp), gitleaks, and truffleHog — run as pre-commit hooks to catch credentials before they reach a remote.
API key hygiene
Most developer credential incidents involve API keys rather than passwords. Best practices:
- Scope minimally: Create API keys with the minimum permissions required. A key for reading analytics data should not have write access to production data.
- One key per environment: Separate keys for development, staging, and production. If a dev key leaks, production is not exposed.
- Set expiry: Most platforms support API key expiry. Use it. Short-lived keys reduce the exposure window if a key is compromised.
- Rotate regularly: API keys for production systems should be rotated on a schedule — quarterly at minimum, or on any suspected exposure.
- Audit active keys: Review which API keys are active, which are being used, and which haven't been called in 90+ days. Inactive keys are attack surface with no benefit — revoke them.
- Never log API keys: Application logs frequently capture request headers and body contents. Ensure your logging configuration redacts authorization headers.
SSH key management
- Use Ed25519, not RSA-2048:
ssh-keygen -t ed25519 -C "your_email@example.com". Ed25519 is faster, shorter, and considered more secure than RSA-2048 or RSA-4096. - Passphrase-protect your private key: Use a strong random passphrase (generated by PassGeni or your password manager). The passphrase encrypts the private key on disk — if someone gets your key file, they can't use it without the passphrase.
- Use SSH agent:
ssh-agentcaches your decrypted key in memory so you don't retype the passphrase on every connection. On macOS, 1Password integrates directly as an SSH agent. - One key per device: Don't copy your private key across machines. Generate a new key on each device and add its public key to each service. This way, if a device is compromised or lost, you revoke only that device's key.
- Audit and remove stale keys: Review your GitHub, Bitbucket, and server
authorized_keysfiles periodically. Remove keys from devices you no longer own.
CI/CD pipeline secrets
CI/CD pipelines are high-value targets — they have deployment access and often run with elevated permissions. Common mistakes:
- Secrets printed in build logs (especially from debug commands or error messages)
- Secrets in Docker image layers — inspect with
docker historyto verify no secrets are baked in - Shared secrets across all branches — use environment-scoped secrets so feature branches can't access production credentials
- Overly permissive pipeline service accounts — apply least privilege to the IAM roles your CI/CD assumes
Use short-lived credentials for deployments where possible. OIDC integration between GitHub Actions and AWS/GCP/Azure allows pipelines to authenticate without storing long-lived credentials at all.
Database credentials
Database credentials deserve specific attention because a compromise typically means direct access to all application data:
- Never connect to production databases from local development machines with production credentials
- Use different database users per application/service — don't share a single database superuser credential across all applications
- Database passwords should be at minimum 20 characters, randomly generated, and stored in a secrets manager
- Enable connection string encryption — use SSL/TLS for all database connections, even inside a VPC
- Consider dynamic credentials: HashiCorp Vault database secrets engine generates short-lived credentials on-demand, eliminating long-lived database passwords entirely
Team credential sharing
The inevitable reality of small dev teams: some credentials need to be shared (staging database, shared API keys, deployment accounts). The wrong way: Slack DMs, email, shared Google Docs. The right way:
- 1Password Teams: Shared vaults, granular permissions, audit logs, and automatic access revocation when someone leaves the team. The standard tool for dev team credential management.
- Bitwarden Teams: Open-source option with shared organisations. Slightly less polished UX but free for small teams and fully self-hostable if you need on-premises storage.
- For production secrets specifically: Use a dedicated secrets manager (Vault, Doppler, Infisical) — not a password manager. Applications should fetch secrets dynamically, not a developer looking them up and pasting them.
op run for injecting secrets into processes), SSH agent integration, and automatic access revocation. Bitwarden Teams is the open-source alternative at lower cost.
Password manager setup for developers
The recommended setup for a developer's personal credential management:
- Choose a password manager: 1Password (best UX, SSH agent integration) or Bitwarden (open-source, self-hostable)
- Set a strong, unique master password — a 6-word Diceware passphrase you have memorised and stored nowhere digitally
- Enable MFA on your password manager account — hardware key as first factor if supported
- Migrate all existing credentials into the vault — use the built-in audit tools to identify duplicates, weak passwords, and breached credentials
- Install the browser extension and desktop app — auto-fill removes the friction of strong unique passwords
- Set up the CLI: 1Password CLI (
op) or Bitwarden CLI (bw) allows secrets injection into local development scripts and terminal workflows - Configure SSH agent integration if available — 1Password can serve as your SSH agent, so your key passphrase is protected by your vault's biometric unlock