Device code phishing: How EvilTokens worked and how to stop it Microsoft's Digital Crimes Unit announced on September 22 that it disrupted EvilTokens, a phishing-as-a-service platform that compromised more than 12,000 inboxes at over 10,000 organizations since it appeared in February 2026 by abusing the OAuth 2.0 device authorization grant rather than stealing passwords or defeating MFA. Microsoft tracks the operator as Storm-2992, and the kit sold for $1,500 plus a $500 monthly subscription with 44 lure templates, generating device codes live so the full 15-minute validity window began when a victim clicked. The attack matters because the same device-code sign-in flow is used by smart TVs, printers, conference-room hardware, CLIs and coding agents, and passkeys do not stop it. Device code phishing: How EvilTokens worked and how to stop it Microsoft took down a phishing service that used the OAuth device flow to get into 12,000 inboxes without stealing a single password. Here's what the attack means for teams that offer device-code sign-in. On September 22, Microsoft's Digital Crimes Unit announced it had disrupted EvilTokens. EvilTokens was a phishing-as-a-service platform that had compromised more than 12,000 inboxes at over 10,000 organizations since it appeared in February 2026. It didn't crack passwords or get around MFA with a clever exploit. It used the OAuth 2.0 device authorization grant exactly as designed. Microsoft tracks the operator as Storm-2992. The device grant https://workos.com/blog/oauth-device-authorization-grant is the flow behind "go to this URL and enter this code." Smart TVs, printers and conference-room hardware use it, and more and more so do CLIs, coding agents and developer tools. If your product has an acme login command, you probably use this flow too. That makes EvilTokens worth understanding even if you never touch Microsoft 365. What is device code phishing? Device code phishing is an attack where the attacker starts an OAuth device sign-in and tricks someone into approving it. The victim goes to the real sign-in page, enters a code the attacker gave them, and completes their own password and MFA. The attacker's device then receives valid access and refresh tokens. No password is stolen and no fake login page is involved, which is why the attack gets past MFA and many phishing filters. How the device flow is supposed to work The device authorization grant RFC 8628 https://www.rfc-editor.org/rfc/rfc8628.html solves a real problem. Some clients can't host a browser or receive a redirect. So the client asks the authorization server for two codes: - A device code it keeps to itself and uses to poll for tokens. - A short user code it shows the person, along with a verification uri . The person opens that URL on a phone or laptop, signs in, enters the code and approves. Meanwhile the device polls the token endpoint. Once approval lands, it receives an access token and a refresh token. There's one assumption hidden in this design: the person entering the code is the same person who started the flow. The spec knows this is fragile. Section 5.4 is titled "Remote phishing" and describes nearly the exact attack EvilTokens ran. What EvilTokens did differently Device code phishing isn't new. We wrote about Storm-2372 https://workos.com/blog/oauth-device-authorization-grant running the same technique in 2025. EvilTokens turned it into a product: a $1,500 kit plus a $500 monthly subscription, with 44 lure templates and a backend built to make each step reliable. Two details made the service unusually effective. - Codes were created live. A device code expires, and Microsoft's is valid for 15 minutes. Older campaigns put a code straight into the email, so it often expired before anyone read it. EvilTokens created the code only when the victim clicked the link, so the full 15 minutes started at the moment of maximum attention. - Signed-in users barely had to do anything. If the victim already had an active Microsoft session, they pasted the code, confirmed, and the attacker's session was authorized. There was no password prompt and no MFA challenge, because the victim had already completed both. After that, Microsoft saw attackers register new devices to obtain a Primary Refresh Token for long-term access, sometimes within 10 minutes. They created inbox rules to hide their activity and ran Microsoft Graph queries to map the organization. An AI assistant built into the kit sorted through compromised mailboxes to find payment approvers and draft convincing follow-up fraud. Do passkeys stop device code phishing? No. It's tempting to file this under "enforce phishing-resistant MFA." That's worth doing for other reasons, but it doesn't close this hole. Passkeys stop adversary-in-the-middle phishing because the credential is bound to the real site's origin. In device code phishing, the victim is on the real site. The passkey works perfectly. It authenticates the victim, who then approves a request that belongs to someone else. Phishing-resistant MFA protects the sign-in. It doesn't protect what the user approves after signing in. In our 2025 post we listed "users always enter codes on trusted domains" as a strength of the device flow. EvilTokens shows the flip side: the trusted domain is exactly what makes the lure believable. What this means if you offer device-code sign-in Microsoft's first recommendation is blunt: block device code flow wherever possible. That's the right call for a Microsoft 365 tenant. For a product whose CLI depends on this flow, it's the wrong answer. The job is to keep the flow and make it harder to use against your own users. Here's where each control sits: Make the approval screen say what's being approved RFC 8628 asks the authorization server to tell the user they're authorizing a device and to confirm the device is in their possession. A screen that says "Approve sign-in?" gives a phished user nothing to catch. A screen that names the application, and asks the user to confirm the code matches what their own terminal shows, gives them a chance. This matters most for verification uri complete , the one-click link with the code already filled in. It's convenient for legitimate users, and it's exactly what a phisher wants to put in an email. AuthKit's CLI Auth https://workos.com/docs/user-management/cli-auth handles this by requiring users on the one-click path to confirm the code matches what's in their terminal. Keep the window short on your side too The device can't defend against remote phishing, because in that scenario the attacker owns the device. What your CLI can do is avoid stretching the flow beyond what it needs. That means honoring expires in and interval , and stopping on terminal errors instead of retrying forever: Let enterprise customers turn it off Plenty of your customers' employees will never use your CLI. For them, device sign-in is attack surface with no benefit, and their security teams will ask about it on a questionnaire, especially after this week. A per-organization setting that disables device sign-in, or limits it to specific groups, turns Microsoft's "block it wherever possible" into something your customers can actually do inside your product. Treat device-flow sign-ins as their own signal A device-flow sign-in isn't just another login. A user's first one, one that happens right after they receive an external email, or one where the approving browser and the polling client are in different countries all deserve extra attention. Log device-flow sign-ins separately so you can alert on them and show them in your customer-facing audit trail. If you use WorkOS Audit Logs https://workos.com/docs/audit-logs , that can be its own event, scoped to the customer's organization, so their security team can export it or review it alongside the rest of their trail. General sign-in anomaly detection helps too. On AuthKit, Radar https://workos.com/docs/radar watches sign-ins for patterns like impossible travel and can block or challenge them, or notify users and admins. It won't know that a particular approval was meant for someone else's device, so the device-flow-specific checks above are still yours to add. Plan for revocation lag Microsoft's incident guidance contains an uncomfortable note. Revoking sessions often only invalidates refresh tokens, so existing access tokens can stay valid for up to an hour, and EvilTokens operators worked inside that window. Microsoft's advice was to temporarily disable the account. The same gap exists in any system that issues self-contained access tokens. A token is a snapshot of what was true when it was issued. Keep access token lifetimes short, and check session state server-side before sensitive actions like changing payout details or exporting data. In AuthKit, access token duration, maximum session length and inactivity timeout are configurable per application https://workos.com/docs/user-management/sessions , and each access token carries a sid claim you can check against the session. We cover the tradeoffs in Your access token is a snapshot, not a live query https://workos.com/blog/access-token-claims-authorization . The takeaway EvilTokens didn't break OAuth. It relied on a trust assumption that RFC 8628 warned about in writing, and it made that assumption cheap to exploit at scale. Microsoft also notes the disruption wasn't a full takedown, so similar services will likely follow. If you ship device-code sign-in, the flow is still the right tool for CLIs and agents. The work is making sure the approval step shows users what they're approving, the window stays short, customers can switch the flow off, and revocation takes effect when you need it to. If you're adding device sign-in to a CLI or agent, the CLI Auth guide https://workos.com/docs/user-management/cli-auth walks through the full flow on AuthKit.