Skip to content
Security First — Part 11 of 30

Two-Factor Authentication: Protect Your Own Accounts First

Written by claude-sonnet-4 · Edited by claude-sonnet-4
two-factor authentication2FAMFAaccount securitynpm securitysupply chain attackspasskeysFIDO2phishingdeveloper security

Security First — Part 11 of 30


The Day Chalk Got Poisoned

September 8, 2025. Josh Junon — known in the open-source world as "Qix" — was having a long week. He was on his phone, knocking things off his to-do list, when an email arrived from support@npmjs.help.

It looked exactly like an official npm security notice. The message was urgent: his two-factor authentication credentials needed to be updated before September 10, or his account would be locked. A deadline. A link. An official-looking page.

He clicked it.

Within minutes, attackers had his username, password, and his 2FA token — intercepted in real time by a man-in-the-middle proxy. Within hours, they had published malicious versions of chalk, debug, ansi-styles, and 15 other foundational JavaScript packages. These weren't obscure libraries. Combined, they had over 2.6 billion weekly downloads.

The injected code was a crypto wallet drainer. Any web app that bundled those packages — and pulled the latest version automatically — was now potentially redirecting its users' cryptocurrency transactions to attackers.

The malicious versions were live for approximately two hours before the community caught it.

Two hours. 2.6 billion downloads. One phishing email.

Here's the part that should make you uncomfortable: Josh Junon did have 2FA enabled. The attackers just stole the code along with his password, in real time. Classic SMS and TOTP codes can be intercepted — and attackers now have industrialized tools to do it.

So what does 2FA actually protect against, where does it fall short, and how do you set it up properly for the accounts that matter most to you as a vibe coder? Let's get into it.


Why Passwords Alone Are a Dead End

Let me tell you something I've learned in 25 years of watching systems get compromised: a password is just a shared secret, and secrets have a way of getting out.

Passwords leak in data breaches. They get phished. They get guessed. They get reused across sites. If you're building apps with AI assistance, you're creating accounts on GitHub, Vercel, Netlify, Railway, Supabase, Stripe, OpenAI — all of them holding credentials, billing info, and live production code. A stolen password for any one of these isn't just a personal inconvenience. It's a direct path into your users' data.

Two-factor authentication (2FA) is the practice of requiring a second proof of identity beyond your password — something you have (a phone, a hardware key) rather than just something you know (a password). Even if your password leaks, an attacker still can't get in without that second factor.

But not all 2FA is created equal. The September 2025 npm attack proved it.


The 2FA Spectrum: From Weak to Bulletproof

Here's how the major 2FA methods rank, from least to most secure:

1. SMS Text Message Codes — Avoid If Possible

You get a text with a 6-digit code. Simple, familiar, and unfortunately the weakest form of 2FA.

SMS codes are vulnerable to:

  • SIM swapping — attackers convince your carrier to transfer your number to their SIM
  • SS7 exploits — flaws in the old telecom signaling protocol that can intercept texts
  • AiTM (Adversary-in-the-Middle) attacks — exactly what happened to Josh Junon

Use SMS 2FA only when it's the only option available. It's still better than no 2FA, but treat it as a fallback, not a primary defense.

2. TOTP Authenticator Apps — Good, With a Known Weakness

TOTP stands for Time-based One-Time Password. Apps like Google Authenticator, Authy, and 1Password generate these — a new 6-digit code every 30 seconds, derived from a shared secret and the current time.

This is much better than SMS. No carrier involvement, no interception over cellular networks. But as the npm attack demonstrated, TOTP codes can still be phished in real time. If an attacker gets you to type your code into a fake login page, their proxy forwards it immediately to the real site before it expires.

TOTP is the right choice for most accounts. Just be paranoid about what URL you're typing it into.

3. Hardware Security Keys (FIDO2/WebAuthn) — The Gold Standard

A physical USB or NFC key like a YubiKey. You plug it in and tap it. No typing a code. No interception possible.

Here's why it's bulletproof: the key cryptographically signs a challenge that includes the exact domain you're logging into. If you're on a fake npmjs.help page instead of npmjs.com, the key simply refuses to authenticate. The FIDO2 standard is immune to AiTM attacks because the credential is bound to the legitimate site's origin.

A $50 YubiKey protects your GitHub account better than any other method available.

4. Passkeys — The Best of Both Worlds

Passkeys are FIDO2 credentials stored on your device (phone, laptop, or password manager). They use biometrics (Face ID, fingerprint) as the "tap to confirm" step. Same phishing resistance as hardware keys, but no separate device to carry.

Major platforms — GitHub, Google, Apple, Microsoft — now support passkeys. Set them up wherever you can.


Setting Up 2FA on Your Critical Developer Accounts

Here are the accounts that matter most for vibe coders, and exactly how to secure them.

GitHub

GitHub is where your code lives. Compromise here means an attacker can push backdoors to your repos, poison your CI/CD pipelines, or expose private code.

GitHub now requires 2FA for all accounts. Here's how to set it up with an authenticator app and a passkey:

1. Go to Settings → Password and authentication
2. Under "Two-factor authentication", click Enable
3. Scan the QR code with your authenticator app (Authy, 1Password, Google Authenticator)
4. Save your recovery codes somewhere safe (password manager, printed paper)
5. Then add a passkey: Settings → Password and authentication → Passkeys → Add passkey

If you have a YubiKey, add it under Security keys in the same section. This makes it your primary factor.

npm (Node Package Manager)

The September 2025 attack targeted npm maintainers specifically. If you publish packages — or even just have an npm account — this is critical.

# Log in via CLI, then check your auth status
npm whoami
npm profile get

# Enable 2FA for auth and publishing
npm profile enable-2fa auth-and-writes

You'll be prompted to scan a QR code with your authenticator app. The auth-and-writes flag means every package publish requires your 2FA code — an attacker with just your password cannot push malicious packages.

Also check your npm automation tokens. These are long-lived tokens that bypass 2FA for CI pipelines. Audit them:

# Visit https://www.npmjs.com/settings/~/tokens
# Revoke any tokens you don't recognize or no longer use

Vercel, Netlify, Railway (Deployment Platforms)

These platforms have the keys to your live production environment. Most support TOTP authenticator apps:

Vercel:  Account → Settings → Security → Two-Factor Authentication
Netlify: User Settings → Security → Two-Factor Authentication  
Railway:  Account → Security → Enable Authenticator App

For each: scan the QR code, save your recovery codes, done.

Supabase, PlanetScale (Database Platforms)

Database credentials in the wrong hands = your users' data exposed. Lock these down:

Supabase: Account → Security → Multi-Factor Authentication

If you're using Supabase for a production app, also make sure your service role key isn't hardcoded in client-side code. That's a separate article, but worth double-checking now.

OpenAI, Anthropic (AI API Providers)

These accounts have billing attached and API keys that could rack up thousands in charges. Enable 2FA in your account settings and always rotate API keys if you accidentally commit them to a public repo.


Protecting Against the Real Attack: Phishing

The npm attackers didn't break any encryption. They sent a convincing email and waited. Here's your defense playbook:

Never click 2FA update links in emails. If you get an email saying your 2FA needs updating, close the email and navigate directly to the site by typing the URL yourself. Legitimate services don't force 2FA resets via email links.

Check URLs obsessively before entering any code. npmjs.com vs npmjs.help. github.com vs github-security.com. One character can cost you everything.

Enable login notifications. GitHub and most platforms will email you when a new device signs in. Turn this on — it's your early warning system.

Use a password manager. Tools like 1Password, Bitwarden, or Dashlane will only autofill your credentials on the correct domain. They won't fill in your GitHub password on a fake site. This is an underrated anti-phishing tool.

Here's a quick Python script you can adapt to check if a URL you've received matches a known-good domain before you interact with it:

from urllib.parse import urlparse

TRUSTED_DOMAINS = {
    "github.com",
    "npmjs.com",
    "vercel.com",
    "netlify.com",
    "supabase.com",
    "openai.com",
}

def is_trusted_url(url: str) -> bool:
    """Check if a URL belongs to a trusted domain."""
    try:
        parsed = urlparse(url)
        hostname = parsed.hostname or ""
        # Check exact match or subdomain of trusted domain
        return any(
            hostname == domain or hostname.endswith("." + domain)
            for domain in TRUSTED_DOMAINS
        )
    except Exception:
        return False

# Examples
print(is_trusted_url("https://github.com/settings/security"))  # True
print(is_trusted_url("https://npmjs.help/reset-2fa"))           # False
print(is_trusted_url("https://github-security.net/alert"))      # False

Paste this into a quick script or ask your AI assistant to build it into a browser extension. The point is: verify before you click.


A Word on the GitLab 2FA Bypass (January 2026)

Just to underscore that even platform-level 2FA isn't perfect: in January 2026, security researchers disclosed CVE-2026-0723, a critical vulnerability in GitLab that allowed attackers to bypass 2FA entirely by submitting forged device responses. If you had the victim's username and password, their 2FA was irrelevant.

GitLab patched it quickly, but the lesson stands: 2FA is a layer, not a guarantee. Keep software updated. Enable login alerts. Use phishing-resistant methods where possible. Defense in depth.


Your Action Checklist

Here's everything to do this week, in order of priority:

  • GitHub: Enable 2FA with an authenticator app. Add a passkey if your device supports it. Save recovery codes in your password manager.
  • npm: Run npm profile enable-2fa auth-and-writes. Audit and revoke unused tokens at npmjs.com/settings/~/tokens.
  • Deployment platforms (Vercel, Netlify, Railway): Enable TOTP 2FA in account security settings.
  • Database platforms (Supabase, PlanetScale): Enable MFA. Rotate any service role keys you've ever accidentally shared.
  • AI API providers (OpenAI, Anthropic): Enable 2FA. Check for leaked API keys in your public repos with git log --all -S 'sk-'.
  • Password manager: If you don't use one, start today. 1Password and Bitwarden both have excellent free tiers.
  • Recovery codes: For every 2FA you enable, download and store the recovery codes in your password manager. Do this now, not after you're locked out.
  • Upgrade to passkeys or a hardware key for your GitHub account specifically — it's the most targeted account in your developer stack.
  • Never click email links for security updates. Navigate directly to the site instead.

Ask The Guild

Have you ever had a developer account compromised — or had a close call with a phishing email? What tipped you off, or what did you wish you'd done differently?

Share your story in the community thread. Bonus points if you can describe the attacker's social engineering tactic — recognizing these patterns is half the battle. And if you've already set up hardware security keys or passkeys on your accounts, drop a comment telling us how the experience was. The Guild learns from real stories, not just theory.


Tom Hundley is a software architect with 25 years of experience. He writes the Security First series to help vibe coders ship safely without needing a security team behind them.

Copy A Prompt Next

Start safely

If this article changed how you think about the problem, copy a prompt that turns that judgment into one safe, reviewable next step.

Matching public prompts

6

Keep the task scoped, copy the prompt, then inspect one reviewable diff before the agent continues.

Need the safest first move instead? Open the curated sample prompts before you browse the broader library.

Start Here — Build Safely With AIStart Here — Build Safely With AI

Choose a Tiny First Win

How to pick a first project that teaches the workflow without dragging you into complex product and engineering problems.

Preview
"I need help shrinking this idea into a safe first vibe-coded project.
The big idea is: [describe idea]
Reduce it to the smallest useful version by:
1. removing anything that requires auth, billing, production data, or complicated integrations
2. keeping only one user and one core job to be done
Security First

Turn this security lesson into a repeatable review habit

This article gives you the judgment call. The security paths give you the vocabulary, checklists, and repetition to catch the next issue before it reaches users.

Best Next Path

Identity and Authentication Deep Dive

Guild Member · $29/mo

Go deep on sessions, JWTs, OAuth flows, enterprise identity, and the auth mistakes that AI-generated code keeps repeating.

15 lessonsIncluded with the full Guild Member library

Need the free route first?

Start with Start Here — Build Safely With AI if you want the workflow and vocabulary before you dive into the deeper path above.

T

About Tom Hundley

Tom Hundley writes for builders who need stronger technical judgment around AI-assisted software work. The Guild turns production experience into public articles, copy-paste prompts, and structured learning paths that help non-software developers supervise AI agents more safely.

Do this next

Leave this article with one concrete move. Copy the matching prompt, or start with the path that teaches the safest next skill in sequence.