A junior dev on my team once had his GitHub account taken over because he reused a password that leaked in an unrelated breach two years earlier. The attacker didn’t touch his code — they went straight for his npm publish token and pushed a malicious version of an internal package. It took us a weekend to clean up. He had 2FA available on every account involved. He just hadn’t turned it on.
That’s the thing about two-factor authentication: developers preach it to users and skip it themselves. We tell clients to enforce MFA on their admin panels while our own GitHub, AWS console, and production SSH keys sit behind a single password. Here’s why that gap is more dangerous for us than for almost anyone else, and how to close it without slowing yourself down.
Why developers are a bigger target than “regular” users
A compromised user account usually gets you one person’s data. A compromised developer account gets you the keys to everything that person can touch — source repos, CI/CD pipelines, cloud infrastructure, database credentials, deployment scripts, and often other people’s accounts through shared secrets. Attackers know this. Credential-stuffing campaigns increasingly target GitHub, GitLab, npm, PyPI, and Docker Hub specifically because one set of stolen credentials can turn into a supply-chain attack affecting thousands of downstream users.
The 2021 Codecov breach started with a single leaked credential in a Docker image. The 2022 LastPass breach traced back to a developer’s compromised home computer. These weren’t sophisticated zero-days — they were accounts without proper second factors, sitting on systems with outsized blast radius.
Where to turn on 2FA first (in priority order)
If you’re doing this today, don’t try to lock down everything at once. Start here:
- Source control (GitHub, GitLab, Bitbucket) — this is your code and your commit history. GitHub has required 2FA for contributors to popular packages since 2022 for good reason.
- Cloud provider consoles (AWS, GCP, Azure) — one compromised root or IAM user with console access can spin up mining instances or exfiltrate an entire S3 bucket before you notice the bill.
- Package registries (npm, PyPI, Composer/Packagist, RubyGems) — if you publish anything, this is a direct supply-chain vector. npm has supported 2FA-required publishing since 2020; turn it on for any package with real download numbers.
- Domain registrar and DNS provider — often overlooked, but whoever controls DNS controls where your email and site traffic go. This is the account attackers want most because it lets them intercept password reset emails for everything else.
- Password manager and email — these are the recovery path for everything above, so they need the strongest protection of all.
SMS is better than nothing, but stop treating it as secure
I used SMS-based 2FA for years because it was the path of least resistance. Then SIM-swapping went from theoretical to routine — attackers social-engineer your carrier into porting your number to a new SIM, and suddenly they’re receiving your codes. It happened to a friend who lost access to his Coinbase and email accounts in the same afternoon.
For anything tied to production access, use an authenticator app (Authy, Google Authenticator, or 1Password’s built-in TOTP) or, better, a hardware key like a YubiKey. Hardware keys use FIDO2/WebAuthn, which is phishing-resistant — even if someone tricks you into entering credentials on a fake login page, the key won’t authenticate against the wrong domain. GitHub, Google, AWS, and most major registries all support hardware keys now. I keep one on my keychain and a backup one in a drawer at home; losing your only 2FA device is its own kind of disaster.
2FA in CI/CD and automation without breaking your pipeline
The usual objection is “2FA breaks automation.” It doesn’t have to, if you separate human accounts from machine accounts properly:
- Use fine-grained personal access tokens or deploy keys for CI/CD, scoped to exactly what the pipeline needs — never your personal 2FA-protected login.
- Rotate tokens on a schedule (I do it quarterly) and revoke anything tied to a contractor or ex-employee immediately, not “when we get to it.”
- For AWS, use IAM roles for CI/CD instead of long-lived access keys wherever possible — no static credentials means nothing to steal.
- Store secrets in a proper vault (AWS Secrets Manager, HashiCorp Vault, or even GitHub Actions’ encrypted secrets) instead of hardcoding them or passing them through Slack “just this once.”
The human login gets 2FA. The machine gets a scoped, rotated, revocable credential. Conflating the two is how teams end up either skipping 2FA entirely or breaking their deploys every time someone’s phone dies.
What this actually costs you
Setting up 2FA properly across the accounts above takes about 45 minutes if you do it in one sitting: five services, a couple of minutes each to scan a QR code or register a hardware key, plus saving backup codes somewhere safe (not a screenshot on your desktop — a password manager’s secure notes, or printed and locked away). That’s the entire cost. Compare it to a weekend spent rotating every credential your team has ever touched because one account got popped, which is what my colleague and I did after that npm incident.
I also recommend turning on login notifications everywhere that offers them. GitHub, Google, and AWS will all email you when a new device signs in. It’s not prevention, but it’s an early warning that’s saved me from at least one attempted takeover — I got the email, revoked the session, and rotated the password before whoever it was got past the login screen.
The takeaway
You don’t need to overhaul your entire security posture this week. Pick the five accounts above, spend your next coffee break setting up an authenticator app or hardware key on each one, and save your backup codes properly. Developers are high-value targets precisely because our accounts touch so much infrastructure — treating 2FA as something you configure for clients but skip for yourself is the exact gap attackers are counting on.