Lion Cipher Lab
Defend against OAuth 2.0 device-code phishing — simulate the attack, then shut it down
- Identity & Access Management
- Intermediate
- ~75 min
- Free · no account required
Why it matters
Device-code phishing has become one of the cleanest ways to take over an account without ever touching a password, and defenders keep missing it because it does not look like an attack. Every control people trust -- 'we have MFA,' 'we block credential phishing,' 'we scan for fake login pages' -- is bypassed, because the victim signs in at the REAL identity provider, completes real MFA, and clicks a real approve button. The only thing the attacker supplied was a short code and a good story ('IT here, please approve this device enrolment'). The tokens that come out are genuine. This matters to…
What you'll learn
- explaining in plain words what the OAuth 2.0 device authorization grant (RFC 8628) is: a sign-in flow for devices that cannot show a browser, where the device gets a short user_code, the human approves it in a normal browser elsewhere, and the device then polls a token endpoint to receive its tokens
- defining every moving part of the flow the first time it appears -- device_code, user_code, verification_uri, expires_in, interval, consent, and the /token poll returning authorization_pending until approval
- standing up a small, plainly-labelled Python simulation of an RFC 8628 authorization server using ONLY the standard library (http.server), so the whole attack-and-defend loop runs offline and free on a server you own
- running device-code phishing end to end in the lab: the attacker starts the flow, captures the user_code, and gets a modelled victim to approve it -- so the tokens are legitimately issued to the attacker who is polling, with NO password ever stolen
- seeing why this is not a bug to patch: the tokens were issued exactly as designed; the exposures are a consent screen that does not identify the requesting app or context, and the grant being available to accounts that never use it
- measuring the BEFORE state honestly: with a weak, generic consent page the modelled victim approves and the attacker's poll returns an access token (success count = 1)
- hardening and RE-MEASURING four defences independently: (1) an informative consent screen that names the requesting client, shows the request's IP/approximate location, and warns 'only approve if YOU started this' so the modelled victim declines; (2) a short user_code lifetime so the phishing window closes and the token request fails as expired; (3) polling rate-limits (slow_down) that blunt automation; (4) the strongest control -- denying the device grant entirely for accounts/clients that do not need it (conditional access)
- the judgment: device-code phishing is a consent-UX and grant-availability problem, so user warnings help but are never reliable on their own; the durable fix is to not expose the device grant to users and high-value accounts who do not need it
- placing the technique on MITRE ATT&CK -- T1528 (Steal Application Access Token) -- so you know what a defender hunts and monitors for
Steps in this lab
- First, the shape of the problem — a legitimate flow, abused
- Set up: build a tiny RFC 8628 authorization server, offline
- Meet the legitimate flow (30 seconds, so the abuse is obvious)
- BEFORE — run the phish and get a token (success count = 1)
- Why it worked — and why there is nothing to 'patch'
- HARDEN #1 — an informative consent screen (victim declines)
- HARDEN #2 — a short user_code lifetime (window closes)
- HARDEN #3 — rate-limit the polling (slow_down)
- HARDEN #4 — the fix that holds: deny the grant to accounts that don't need it
- Honest limits, and how a pro thinks about it