Inside the ShinyHunters vishing playbook: two captured Okta clones and a passkey bypass
Inside two captured Okta phishing clones: how a vishing kit relays number matching, disables phishing-resistant factors, and keeps victims on the line.

TL;DR
- A ShinyHunters-style voice-phishing crew has been standing up cloned Okta login pages on <brand>.claims domains since late July. We captured the kit live on two of them and took it apart.
- It is a real-time adversary-in-the-middle relay, and it beats Okta Verify number matching. The page polls its server every two seconds for the live challenge digit and shows it to the victim. Number matching only works if the phisher cannot see the number.
- Every origin-bound factor on its menu is deliberately broken. FastPass, security key, and PIV/CAC all render as real options and all fail with the same excuse. The operator disabled exactly the factors that cannot be relayed.
- Passkeys stop this. If a user touched one of these pages, treat it as a session compromise: revoke sessions and tokens, then move the account to origin-bound FIDO2/WebAuthn.
The campaign
This campaign is ongoing as of publication. We've anonymized targets and some tactics out of respect for impacted organizations.
A voice-phishing operation linked to the ShinyHunters name has been hitting Okta single sign-on accounts since late 2025. By January 2026, security firms counted over 100 targeted. In July, Health-ISAC warned that successful attacks against healthcare companies were accelerating. In late July, the operators started a new wave of infrastructure: .claims domains impersonating specific brands, each hosting a cloned Okta login page behind Cloudflare. We have tracked 29 of them since late August.
Campaign targeting quickly expanded. The first three registrations, all on July 29, impersonate crypto and decentralized finance brands. The first enterprise brand lure appears on August 1, and from there the set is almost entirely healthcare, insurance, and other large Okta tenants. Certificate issuance dates follow the same order. It appears that crypto targets were a proving ground before moving to corporate single sign-on within three days.
Two public incidents match this playbook:
- ReliaQuest. Help Net Security reported on August 25 that a caller social-engineered an employee through a lookalike Okta page. ShinyHunters claimed SSO access and posted screenshots; ReliaQuest says other controls limited the impact. reliaquest.claims is in our August 25 baseline.
- McKesson. Days later, McKesson disclosed a breach: vishing calls, stolen Okta credentials, and a walk through Salesforce and Snowflake that ended with ShinyHunters claiming 284 million patient records. Two McKesson lure domains sit among the dormant .com names described below, registered in the days before that disclosure.
Note: ReliaQuest did not name the domain, though BleepingComputer's sources put it at reliaquest.claims. McKesson did not disclose.
Who is behind this
Google Threat Intelligence and Okta have documented the broader pattern since 2025: a caller impersonating IT or the help desk, an organization-branded credential page, and a phishing panel built so an operator can log in on the other side while the caller keeps the victim on the line. Okta customers are a favorite target because one Okta login page, repainted, works against almost any company.
A note on the name. ShinyHunters is a brand, used by the actors themselves and applied broadly by press coverage; the vendors above track the underlying activity under their own cluster designations. We use it the way the public reporting does, as a label for a pattern of behavior, not as an identification of whoever is running these two servers.
The .claims campaign matches that pattern in every detail we can observe. The two deployments we captured share a registration fingerprint with the rest of the set: a budget registrar, Cloudflare fronting, the brand name as the entire second-level label, registration clustered in a five-week window. The fingerprint ties the domains to each other. It does not tie them to a name. We describe the operator by fingerprint and leave attribution to the people with the telemetry to make it.
The attack chain
1. The call. It starts with a phone call, not an email. Someone claiming to be IT, the help desk, or HR, with a reason to act now: a benefits deadline, a claims system migration, a security re-verification. The caller stays on the line and reads out the address, or texts it.
2. The domain. yourcompany.claims. Your employer's real name, a dot, and a word that sounds like it belongs at an insurer, a health plan, or a bank. Nothing misspelled, nothing appended. "We need you to re-verify your account for the claims portal" sounds normal at most of the companies on the target list.
3. The page. An Okta sign-in screen, and a faithful one: the "Connecting to" banner, the company logo, the real layout and typography, "Powered by Okta" in the corner. The address bar shows what looks like a real SSO redirect with SAML-style parameters. The kit paints that URL into the address bar itself after the page loads. It is decoration.
4. The credentials. Username, then password, on separate screens, the way real Okta works. The kit sends each to the operator as it is typed.
5. The push. The page shows the user's own phone number, masked to the last four digits, and a two-digit number to tap in Okta Verify. The user opens the app, sees a push waiting, sees the number match, and taps it.
6. The "approved" screen. The page shows a success state for a few seconds. On the other side, the operator now holds a live Okta session.
Every instinct the user followed was correct for a real login, with the exception of the domain.
Bypassing MFA with AiTM
Number matching exists to kill MFA fatigue attacks. The screen shows a number, and your authenticator makes you confirm the same number. An attacker who triggers a push blind cannot approve it, because they cannot see the screen.
An AiTM kit does not store credentials and replay them later. It sits between two live sessions, the victim's and the operator's, and relays between them in real time. When the victim submits a password, the operator's backend starts a real login against the real Okta tenant. Okta sends a real push and generates a real challenge digit. The kit's page polls the operator's server every two seconds, and when the digit comes back, the page shows it to the victim.
The relay does not stop at number matching. Anything a user can read off one screen and type into another can be relayed by something sitting between the two screens.
The kit disables exactly the factors that would have worked
The factor menu is the most useful thing in the bundle, because of what does not work on it. Seven options render under "Verify it's you with a security method," plus a PIV/CAC smart card button on the sign-in screen itself.
Functional (selecting one sends the choice to the operator and advances the flow):
- Google Authenticator
- Enter a code
- Get a push notification
- Phone
- SMS
Dead ends (render as normal, selectable options; only set an error message):
- Okta FastPass
- Security key or biometric authenticator
- PIV/CAC smart card
All three dead ends fail with the same wording, "currently unavailable in this region," and resolve to the same error handler in the deobfuscated bundle. The split is exact: every factor the kit accepts can be relayed, every factor it refuses is origin-bound. The operator did not drop WebAuthn because it was hard to build. A passkey would have signed for yourcompany.okta.com, refused to sign for yourcompany.claims, and killed the login in front of a victim who was still on the phone.
The excuse is well chosen too. Regional unavailability sounds like an IT constraint rather than a failure, and a caller still on the line can talk the victim past it toward a method that works.
Inside the kit
We observed two live deployments of the kit. Both are Next.js apps carrying an identical login component and an identical bot-scoring helper, differing only in per-build hashes, the brand config, and a few randomized paths. We reversed the obfuscated client bundle down to the capture logic, working from saved copies. Nothing we did touched the live sites.
Nothing happens until a captcha clears. The login interface, the address-bar repaint, and the beacon that tells the operator a victim has arrived all wait on a captcha gate. A caller walking someone through the page reads that as one more normal login step. For a scanner, it is another wall.
Capture is staged. Username, password, MFA response, each posted to a kit-controlled endpoint as it is entered, tagged with brand and step. The password field is a plain text input masked with CSS; the show/hide toggle flips the styling, and the kit reads the real characters either way.
The victim's browser stays tethered to the operator for the whole session:
- A session poll every two seconds pulls server-supplied values, including the masked phone number and the live challenge digit.
- A server-sent event channel lets the operator push a "kick" that redirects the victim away on command.
- A heartbeat and a pause flag let the operator control pacing and how long the victim stays.
- A separate push-status poll and an arrival beacon round out the set, alongside the captcha endpoint.
It is a panel a human watches while relaying a login. The fake "approved" screens serve the same purpose: submit a code and the page shows success for three seconds before looping back to the factor menu; approve a push and it waits ten seconds, shows success, then loops back the same way. Neither screen reflects any decision Okta made. Both buy the operator time to finish the real login while the victim believes they are through.
Most of this is standard phishing-as-a-service tradecraft in 2026, and Okta has documented number-match bypass in this kit family since January. What we have not seen documented is a factor menu with every origin-bound option rendered and deliberately broken.
Evading analysis
The kit works hard to show researchers and scanners something different from what a victim sees.
The address-bar trick is the cleverest piece. After load, the page rewrites the visible URL to look like an Okta SAML SSO redirect, with a random value where a signed request would go. It never navigates. It repaints the bar. That does three jobs: it makes the page look legitimate, it scrubs the per-victim lure link out of the address bar and history, and it cloaks. Copy that SSO-looking URL and replay it, and the server sends you to the real Okta. The URL a victim pastes into a ticket leads investigators away from the kit.
Under that sits a scoring system that decides whether a visitor is a target or an analyst. It watches for:
- Honeypot fills. Four inputs sit inside the form, positioned far off-screen, sized to a single pixel, zero opacity, pointer events disabled, negative z-index, hidden from assistive technology. A sighted user never sees them and a screen reader never announces them, so anything that fills one is not a person.
- navigator.webdriver and a list of known headless user agents.
- Submission speed. A form submitted faster than anyone could type it.
- Mouse movement. A five-second window after load in which the pointer never moves. Someone reading a login screen moves the pointer well inside five seconds. Something taking a screenshot never does.
The scoring is the interesting part. Signals are weighted and summed against a threshold set low enough that a single honeypot fill, or the automation flag on its own, disqualifies you outright. A headless user agent alone does not. The kit will serve its interface to something that looks automated so long as nothing else corroborates, which says the operator would rather absorb a few analysts than lose a victim to a false positive. Cross the threshold and the page bounces you to the real okta.com before the phishing interface ever renders.
The infrastructure
Our August 25 baseline is 29 brand-related .claims domains sharing one registration fingerprint. The same fingerprint covers roughly twice that number once you include generic and nonsense second-level names, so 29 is the set we can argue domain by domain, not the whole of what the operator holds. We are withholding the target names, with ReliaQuest as the one exception because that name is already in public reporting. A domain in this set is a lure that was built. Targeting is not a compromise.
The 29 do not all rest on the same evidence:
| Evidence in the collection | Domains | What the count establishes |
|---|---|---|
| Registry server hold status | 24 | Saved registration records show the domains suspended; this does not by itself establish their earlier page content |
| Captured live phishing deployments | 2 | Preserved client bundles and build manifests support every technical finding in this article |
| Campaign fingerprint, no live DNS | 3 | Registered infrastructure, staged or abandoned; we did not observe deployment |
| Total baseline | 29 |
Grouped by the apparent industry of the impersonated brand:
| Apparent target industry | Domains | Share |
|---|---|---|
| Healthcare, life sciences, medical technology | 8 | 27.6% |
| Financial services and insurance | 8 | 27.6% |
| Retail and restaurants | 3 | 10.3% |
| Consumer technology | 2 | 6.9% |
| Travel and hospitality | 1 | 3.4% |
| Media and entertainment | 1 | 3.4% |
| Cybersecurity | 1 | 3.4% |
| Crypto and decentralized finance, or tentative mapping | 5 | 17.2% |
| Total | 29 |
Note: these numbers are samples and non-exhaustive.
Healthcare and financial services are 16 of 29, about 55%. That fits the pretext. The spread across retail, tech, travel, and media says the operator is targeting the identity provider, not an industry. Same Okta page, different logo.
The last row is not really a residual category. Those names, plus several more outside the 29, are the crypto cluster the campaign opened with in late July. In a table sorted by industry they look like leftovers. In a table sorted by date they are the beginning. The dormant .com names below widen the picture again, and one organization appears three times under different naming conventions, which suggests the operator retries a target rather than moving on.
Registry response.
On August 23 and 24, the .claims registry placed 24 of the baseline domains on server hold, 22 of them in two automated batches on August 24. The operator replaced them the same afternoon.
| Event on August 24 | Time, UTC |
|---|---|
| Registry suspends 18 domains | 14:20:47 to 14:20:49 |
| Registry suspends 4 more | 15:30:56 to 15:30:58 |
| Operator registers the first replacement | 19:46:04 |
| Operator registers the second | 19:46:14 |
Both replacements were live when we collected them the next day, and they are the source of every technical finding in this article. Since that sweep, new .claims registrations matching the fingerprint have been suspended within one to three days, and the operator has stopped deploying there. Fingerprint-matching .claims names still get registered, but they arrive dead.
The move to .com. Since August 1, the operator has been registering claims-<brand>.com and <brand>-claims.com names on the same registrar and leaving them dormant. More than two dozen are still unused. On September 1, two .com domains registered the day before served the same kit, with the same apex block and the same decoy redirect to the real Okta tenant. We saw them on September 1 and 2 and not afterward. .com does not auto-suspend the way .claims did.
What that means for takedowns. Suspending a domain costs a registrar an abuse review and takes hours or days. Replacing one costs the operator a few dollars and a scripted API call, and the reserve of dormant .com and parked .claims names says they planned for it. A domain in this campaign only needs to survive one phone call, and the call is over in minutes. Registry pressure made one TLD unusable, which is a real cost, and the operator absorbed it in an afternoon. Run the takedowns. Do not build the defense on them.
What to do about it
If you do one thing, move your Okta administrators and high-value users to passkeys or YubiKeys with no fallback option. That one control stops this attack dead in its tracks.
Human risk and awareness: train for the call, not the typo.
- Make it normal and blameless to hang up on an unexpected "IT" or "HR" caller and ring the help desk back on a known internal number.
- Teach that a correct-looking address bar proves nothing, even one that looks like a real SSO redirect, because a page can paint its own URL.
- Retire "approving MFA on your own phone means it's you." A push you did not start, or a number-match prompt that arrives right after a support call, is a reason to stop, not a reason to tap.
- Simulate multi-channel vishing attacks before the real one. Measure your baseline and how your process holds up.
Incident response: on any confirmed interaction, work this list.
- Assume the username and password are compromised.
- Assume every MFA interaction is compromised, including an approved Okta Verify number-match push.
- Revoke active sessions, refresh tokens, and OAuth grants. A password reset alone leaves relayed tokens valid.
- Hunt the downstream signs: sign-ins from an unfamiliar device or location, new MFA enrollments, unexpected OAuth grants, above all where they line up with a reported support call or a visit to one of these pages.
Google's guidance on responding to this class of SaaS intrusion covers the wider investigation.
Threat hunters: a kit built on a mainstream framework can betray its own backend through public build assets. That generalizes well past this campaign. Three smaller lessons travel with it.
- Hunt by pattern, not by brand list. Both September deployments were caught by a naming-and-registrar sweep and missed entirely by the brand-name monitor, because their targets were not on it yet.
- Nameserver assignment groups infrastructure. Cloudflare hands each account a stable pair of nameserver hostnames, so domains sharing a pair share an account. That grouped domains across waves for us and cost nothing to check.
- Know when a pivot is closed before you spend a week on it. These domains sat behind Cloudflare from the moment they were registered, so no origin address has ever been public, and every pivot that starts from one is unavailable here.
The channel nobody tests is the one that was used
This campaign reached employees on a channel security doesn't own and doesn't monitor. Most awareness programs measure the corporate inbox and stop there. This attack never touched an email.
Mirage runs AI-generated vishing calls to the numbers your employees answer and social engineering messages through Microsoft Teams, using pretexts like the passkey migration described in this post. Employees who get the call can report it through a Slack or Teams agent they already have open, one message instead of a support ticket. Employees who don't catch it get browser-based coaching mapped to what happened on the call.
What comes back is what a click rate can't measure: whether your people comply when the story matches a program you're running, and whether the verification path you published is one they use when the phone rings.