Two breaches in 8 months, 275M records, 9K schools defaced during finals.
ShinyHunters did it with a phone call and an OAuth flow Microsoft begged you to disable.
3.65 terabytes, 275 million records, 8.809 institutions on a leak-site list: Harvard, Stanford, Columbia, Apple, Atrium Health, the State of Wyoming. Kids trying to upload their finals during exam week, getting a PAY OR LEAK ransom note instead. Instructure’s Canvas LMS got bodied by ShinyHunters not once but twice in eight months, and the part everyone is missing is that the second hit didn’t need any new technique.
The doors were already documented, just hadn’t been closed.
Same group, same vendor and different attack surface.
Eight months apart, Microsoft told you which OAuth flow to disable a year ago and ShinyHunters waited to see who didn’t listen.

I’ve seen this movie before..
I’ve been in this game since people still argued about whether IRC bots counted as malware, and let me tell you something: when I was on the offensive side, social engineering was always the cheapest exploit in the toolkit. Not the sexiest, not the one that wins DEF CON talks, but the cheapest. You don’t fuzz a binary for three weeks if a phone call gets you a session token in 12 minutes, right?
That’s the dirty little secret of red teaming that vendors don’t put on their marketing decks: most “advanced persistent threats” in 2026 are an APT-grade voicemail and an OAuth grant type Microsoft has been telling you to disable since 2024. ShinyHunters is not Equation Group, ShinyHunters is not Lazarus and Mandiant calls them “a loose group of teenagers and young adults“. They run a playbook so old it has gray hair, and it works because defenders are still building castles to stop catapults while these kids walk in with a clipboard, a confident voice, and microsoft.com/devicelogin open in another tab.
Well, this breach is not technically novel, as that’s exactly why I’m writing about it: the technically uninteresting attack is the one that’s hitting everyone you know. So, lads and fags, let’s start dissecting.
The Setup: what’s confirmed and what’s not
Before going further, let’s draw a hard line between what Instructure has confirmed and what is reasonable inference from the broader 2025-2026 ShinyHunters campaign. Most of the press coverage is mashing these together but defenders need them separate, because the response math is different.
Confirmed by Instructure (public):
- a criminal threat actor accessed the network. Initial detection: April 30, 2026, when tools depending on Canvas API keys started failing, then confirmation by CISO Steve Proud: May 1, 2026
- exposed data categories: names, email addresses, student ID numbers, in-platform Canvas messages (that’s a lot!)
- no evidence so far of passwords, dates of birth, government IDs, or financial data being involved
- containment included revoking privileged credentials and access tokens, rotating cryptographic keys, deploying patches, and reissuing application keys with timestamped naming so admins could distinguish legitimate keys during re-authorisation
- the exploited surface, per Instructure’s own statement: an issue related to the Free-For-Teacher account program – production Canvas tenants with lower-friction onboarding, sharing infrastructure with paid institutional tenants, then: Free-For-Teacher has now been permanently shut down
- this is the second ShinyHunters-linked incident at Instructure in under a year; the September 2025 incident was a social-engineering attack against the Salesforce instance. Instructure described it at the time as limited in scope to publicly-available business contact data and stated additional security measures had been implemented afterward
Claimed by ShinyHunters (not independently verified)
- 3.65TB of uncompressed data
- up to 275 million individuals across (about) 9.000 schools and 15.000 institutions
- “several billions” of private messages between students, teachers, and staff (cannot be more precise on the real number)
- the Salesforce instance was breached as well in the May 2026 incident
- a vulnerability was used and has been patched
What is not publicly known
- the initial access vector for the May 2026 breach
- whether MFA was bypassed, and if so how
- whether Microsoft Entra ID, Okta, or another identity provider was the pivot point (and no surprise there are plenty to chose from)
- whether staged egress used API keys, OAuth tokens, direct database access, or some mix
- dwell time before detection
- the exact technical mechanism by which Free-For-Teacher accounts were exploited to reach paid-tenant data
What follows in the next section is explicitly a hypothesis based on ShinyHunters’ documented operations against Odido, Panera, Match Group, Crunchbase, Wynn, Cisco, Allianz Life, Infinite Campus, Vimeo, ADT, Udemy, and Figure. I’m clearly labeling it as such because the defensive recommendations later in this post do not depend on the Instructure attack chain being exactly what’s described below, rather depend on the broader pattern, which is well-documented.
A plausible hypothesis (disclaimer: read this as speculation)
The ShinyHunters 2025-2026 campaign, including operations attributed to overlapping threat clusters tracked as UNC6240 and UNC6040, has converged on a recognizable chain: if the May 2026 Instructure breach follows it, here is what likely happened:
- reconnaissance – identify a target with a large, identity-rich SaaS footprint, a phone-reachable helpdesk, and a brand whose appearance on a leak site creates pressure.. Instructure ticks every box!
- vishing – a caller, fluent in the local language, impersonates IT support and walks an employee through a “routine sign-in” – there is no fake login page and the user authenticates on the real identity-provider domain
- OAuth 2.0 Device Authorization Grant abuse – the attacker generates a legitimate device code using a real OAuth client ID, then has the victim enter it at
microsoft.com/devicelogin(or the equivalent for the IdP). The user authenticates correctly (including MFA, including phishing-resistant MFA) and unknowingly authorises the attacker’s session. Passkeys do not protect against this!!! The user is authenticating correctly on the legitimate domain. They’re just not authorising the session they think they are!!! - SSO pivot – with valid tokens for the victim’s identity, the attacker reaches whichever connected SaaS apps that identity has access to: Salesforce, Microsoft 365, Workday, ticketing, the LMS admin console, whatever the org chart and the role assignments allow
- staged exfiltration – data is pulled out over legitimate API surfaces over days or weeks (ok, 3.65 TB does not move in one burst) and it moves chunked, paced, looking like normal integration traffic, until your SIEM either alerts on novel API patterns (most don’t) or your storage costs hint that something’s off
- extortion – victim is added to the leak site with a “final warning” and a deadline. If the deadline passes without payment, escalate: defacement, second leak, public ramping. We saw exactly this on May 7 when ShinyHunters defaced Canvas login pages at multiple universities during finals week
Whether this is precisely what happened to Instructure is unknown.
What is known: this pattern has worked repeatedly across the past nine months, the first observable symptom in this incident was API-key-dependent tooling failing (which is at least consistent with abuse and revocation of integration credentials), and the post-September-2025 controls (whatever they were) did not prevent a second, materially larger incident from being disclosed less than a year later.
What’s the story (morning glory)?
Everyone is writing about Free-For-Teacher accounts: Sentra wrote a sharp piece on Salesforce data governance, Bitdefender went deep on the trust boundary issue between free and paid tenants and Michael Lohn at Wortell published the cleanest defender-side technical breakdown I’ve seen on this incident, and that’s the one I want you to read after this post.
All correct. All useful. All circling the actual punchline without quite landing on it.
The punchline is this: Microsoft told you over a year ago to block the OAuth 2.0 Device Authorization Grant for non-device scenarios. Their own documentation is unambiguous: enabled by default in many Entra tenants and almost never needed for a SaaS-only workforce.
It is the single most reachable foothold ShinyHunters has been using across an entire victim list (Odido, Cisco, Allianz Life, Match Group, Wynn, Panera, Infinite Campus, Vimeo, ADT, and almost certainly the Instructure incidents too) and a Conditional Access policy disables it in about 90 seconds.
Mandiant’s 2026 attribution of ShinyHunters’ campaigns is explicit: sophisticated voice phishing and fake company-branded login pages to harvest employee credentials before stealing sensitive data from cloud-based platforms for ransom. That’s not me extrapolating: that’s Google’s incident response arm telling you what the entry vector class is.
Now look at how the average enterprise trains its people against this:
[ ] Sent quarterly phishing email with a Nigerian prince typo
[ ] Watched a 12-minute video about clicking suspicious links
[ ] Ticked the compliance box
[ ] Slept well at night
When was the last time your phishing simulation vendor ran a vishing campaign against your IT helpdesk team? When did your awareness training include a fake re-auth flow that walks an employee through entering a device code at the real Microsoft devicelogin page, because that’s the actual current attack, and your passkey rollout doesn’t stop it?
If your answer is “never,” I’m not surprised ๐ mostly because that’s not what most awareness vendors do.
They train your people to spot template phishing, bad grammar, weird sender, generic greeting, and everything the simple AI can tell you. ShinyHunters doesn’t send a phishing template, no Sir, they make a phone call: they already know your manager’s name. They already know your helpdesk procedure because they probably called it last week pretending to be a confused user, just to map your script.
And what’s this? The Canvas breach is NOT an LMS problem but a 2026 identity-driven social engineering problem dressed in an edtech costume. The pattern is so consistent across the 2025-2026 victim list that calling it a coincidence is malpractice – YOU FOOL!
Numbers
3.65 TB exfiltrated.
275 million individual records claimed.
8.809 institutions defaced or listed.
$0 spent on the actual exploit kit (this is a workforce attack).
8 months between breach #1 and breach #2 at the same vendor.
That’s slower than your average org’s password rotation policy. Faster than most board cycles. Long enough that “additional security measures” got announced and short enough that they clearly didn’t cover the right surface.
41% of US higher education runs Canvas.
That’s not a vendor, it’s national infrastructure for a sector.
90 seconds: time to write the Conditional Access policy that blocks Device Code Flow for users who don’t sign in from input-constrained devices. Most orgs in the 2026 victim list had not done it.
Connect those to YOUR SOC reality:
- most IR playbooks assume the initial vector is a CVE or a misconfig
- vishing-into-device-code-flow produces no IOC, no malicious binary, no anomalous network flow – until the token is reused 4 hours later from a residential IP behind a SOCKS5 proxy
- the user authenticated correctly on the real Microsoft domain and YOUR AiTM-detection proxy sees nothing and YOUR passkey enforcement tells you everything is fine and YOUR SIEM celebrates the successful MFA
- by the time anyone notices, the data is already chunked into 3.65 TB worth of API pulls that look like normal integration traffic
Detection window for this attack class, in the absence of specific instrumentation: single-digit hours, generously.
So, fuffa-free: what actually got exploited (tech ground)
To be precise, because I owe you precision and Lohn’s writeup deserves to be amplified:
- Free-For-Teacher account program – Instructure’s confirmed exploited surface.
Lower-friction onboarding meant no institutional verification. Production tenancy on shared back-end. Trust boundary thinner than the architecture diagram suggested. Permanently shut down on May 8. - defacement vector – TechCrunch confirmed the attackers injected an HTML file that altered Canvas login screens at multiple institutions on May 7. That implies write access to tenant configuration or UI elements, which goes well beyond what a standard user account should be able to do. Translation: privilege escalation occurred, or the attacker held credentials that should never have been exposed to a customer-tier account.
- API key blast radius – every Canvas integration (LTI apps, SIS connectors, SSO, analytics platforms) authenticated against the platform during the exposure window. Every one of those tokens needs to be treated as compromised. Canvas’s integration ecosystem is over 1K connectors, now do the math on credential rotation across 9k institutions, each with their own integration zoo.
- Helpdesk identity model (systemic, not Instructure-confirmed) – the 2025-2026 ShinyHunters playbook has repeatedly demonstrated that helpdesk and IT-support roles tend to be master keys: standing access into CRM, LMS admin, ticketing, identity. One compromised session unlocks everything that identity touches: this is the lesson Odido learned in February. Apply it to your environment regardless of how the Canvas chain turns out.
- no CVE – no 0day, no exotic exploit chain, niet, nichts, nada. The official disclosure is “an issue related to Free-For-Teacher accounts“. That’s corporate-speak for “we shipped a feature with permissions that were too generous and someone noticed”. Combined with the broader campaign pattern, this is identity abuse at the architecture level, not vulnerability exploitation at the code level.
What keeps me (and YOU too) up is not Canvas, as Canvas will recover and Instructure will pay lawyers, file 8-Ks, ship security patches, hire a new CISO maybe, and in 18 months everyone will have forgotten this happened – until it happens to the next vendor in the chain.
What keeps me up is that Scattered LAPSUS$ Hunters has industrialized social-engineering-as-a-service, that the OAuth Device Code Flow abuse is documented to the point where Microsoft has explicit mitigation guidance, and the response from most enterprise security programs is still the same shitty quarterly phishing simulation that trained people to spot Nigerian prince emails in 2014.
Look at the 2025-2026 ShinyHunters/UNC6240/UNC6040 victim list: Odido, Match Group, Panera, Wynn, Cisco, Allianz Life, Crunchbase, Infinite Campus, Vimeo, ADT, Udemy, Figure, Instructure (twice).
Different sectors, geographies but same playbook: the vector across most of these is not zero-day exploitation but people and identity flows. Our defensive models are still optimized for the wrong threat.
Here’s the prediction I’ll commit to in writing: the next 18 months of major breaches in SMB and mid-market will be 70%+ identity-driven, vishing-initiated, OAuth-abuse-pivoted attacks that look nothing like a generic phishing email. Not because attackers got smarter, surely because they got bored of bruteforcing exposed RDP.
Vishing scales now and AI voice cloning costs as little as $5/month.. I mean, a teenager with a Hetzner VPS, a target’s LinkedIn org chart, and 14 hours of free time can do what required a state-sponsored actor in 2018.
More code? Why not!
Three things you can ship this week. None of them replace a real social engineering readiness program, but all of them buy you signal you don’t currently have.
# entra_block_device_code_flow.md
# PacketHunters / Baited.io
# Conditional Access policy concept: block OAuth 2.0 Device Authorization Grant for users who don't legitimately need it
# Why it matters: this is the single highest-ROI control against the 2025-2026 ShinyHunters / UNC6240 / UNC6040 vishing-to-SaaS playbook
# Reference: Microsoft's own guidance on disabling Device Code Flow for non-device scenarios
Conditional Access Policy:
Name: "Block Device Code Flow - All Users (Exceptions Group Only)"
Assignments:
Users:
Include: All users
Exclude:
- Group: "CA-DeviceCodeFlow-Allowed"
# Members: ONLY accounts that genuinely sign in from input-constrained
# hardware (shared meeting room devices, IoT, kiosks). Audit quarterly.
# If this group has more than 5 members, you're doing it wrong.
Cloud apps: All cloud apps
Conditions:
Authentication flows:
- Device code flow: TRANSFER (this is the toggle)
Access controls:
Grant: BLOCK
Session: (n/a โ block at grant)
# Salesforce equivalent:
# Setup -> Connected Apps -> review each Connected App's "Permitted Users"
# and "OAuth scopes". Disable OAuth Device Flow on any app that doesn't
# explicitly need it. Most don't.
# Verification:
# After deploy, attempt a device code flow authentication from a personal
# device with a normal user account. Expected: BLOCKED with policy reference.
# If it succeeds, the policy isn't applied โ check group membership and
# scope of "Cloud apps".
# vishing_callback_canary.py
# PacketHunters / Baited.io
# Detects when an internal employee initiates a callback to a phone number not on the corporate allowlist within N minutes of a suspicious inbound call
# Why it matters: voice phishing's tell is the pivot โ attacker calls, employee hangs up, attacker has them call back to a controlled number, OR the agent is walked through entering a device code while still on the line
# Dependencies: pandas, your VoIP/PBX call detail records (CDR) export, an allowlist of legitimate IT/vendor numbers
import pandas as pd
from datetime import timedelta
CDR_PATH = "/var/log/pbx/cdr_last_24h.csv"
ALLOWLIST_PATH = "/etc/security/voip_allowlist.txt"
PIVOT_WINDOW_MIN = 15
LONG_CALL_THRESHOLD_SEC = 600 # >10 min inbound from new number = walked-through-something flag
cdr = pd.read_csv(CDR_PATH, parse_dates=["start_time"])
with open(ALLOWLIST_PATH) as f:
allowlist = {line.strip() for line in f if line.strip()}
# Inbound calls flagged suspicious by upstream filter (caller-ID spoofing, new number, etc.)
suspicious_inbound = cdr[(cdr.direction == "inbound") & (cdr.flag_suspicious == True)]
# Also flag long inbound calls from numbers not on allowlist - classic vishing dwell
long_unknown_inbound = cdr[
(cdr.direction == "inbound")
& (cdr.duration_sec > LONG_CALL_THRESHOLD_SEC)
& (~cdr.caller_id.isin(allowlist))
]
alerts = []
for _, row in pd.concat([suspicious_inbound, long_unknown_inbound]).drop_duplicates().iterrows():
window_end = row.start_time + timedelta(minutes=PIVOT_WINDOW_MIN)
callbacks = cdr[
(cdr.direction == "outbound")
& (cdr.extension == row.extension)
& (cdr.start_time.between(row.start_time, window_end))
& (~cdr.dialed_number.isin(allowlist))
]
if not callbacks.empty:
alerts.append({
"extension": row.extension,
"suspicious_caller": row.caller_id,
"callback_to": callbacks.iloc[0].dialed_number,
"lag_minutes": (callbacks.iloc[0].start_time - row.start_time).seconds // 60,
"inbound_duration_sec": row.duration_sec,
})
if alerts:
print(f"[!] {len(alerts)} potential vishing pivot(s) detected:")
for a in alerts:
print(a)
print("\n[!] Cross-reference with Entra sign-in logs for the same user/timeframe.")
print("[!] Look for: device code flow authentications, new device registrations, sign-ins from new ASN.")
#!/bin/bash
# entra_devicecode_signin_hunt.sh
# PacketHunters / Baited.io
# Pulls Entra ID sign-in logs and surfaces all successful Device Code Flow authentications in the last 14 days
# Why it matters: in a healthy SaaS-only environment, this number should be near zero. Anything else is investigation material.
# Dependencies: az CLI authenticated as a Security Reader or Global Reader
DAYS_BACK="${1:-14}"
OUTPUT_FILE="/tmp/devicecode_signins_$(date +%Y%m%d).json"
echo "[*] Querying Entra sign-ins for Device Code Flow over last $DAYS_BACK days..."
az rest --method GET \
--url "https://graph.microsoft.com/v1.0/auditLogs/signIns" \
--url-parameters \
"\$filter=authenticationProtocol eq 'deviceCode' and createdDateTime ge $(date -u -d "$DAYS_BACK days ago" +%Y-%m-%dT%H:%M:%SZ)" \
"\$select=createdDateTime,userPrincipalName,appDisplayName,ipAddress,clientAppUsed,status,location" \
"\$top=999" \
> "$OUTPUT_FILE"
COUNT=$(jq '.value | length' "$OUTPUT_FILE")
echo ""
echo "[*] Found $COUNT Device Code Flow sign-ins in the window."
echo "[*] Per-user breakdown:"
jq -r '.value | group_by(.userPrincipalName) | map({user: .[0].userPrincipalName, count: length, last_ip: .[-1].ipAddress, last_app: .[-1].appDisplayName}) | sort_by(.count) | reverse | .[] | "\(.count)\t\(.user)\t\(.last_ip)\t\(.last_app)"' "$OUTPUT_FILE"
echo ""
echo "[*] Investigation checklist for any non-zero result:"
echo " 1. Does this user own an input-constrained device that legitimately uses device code flow?"
echo " 2. Is the IP address geographically consistent with the user's normal patterns?"
echo " 3. Is the app a known internal device (kiosk, AV, IoT) or a user-facing client?"
echo " 4. Did a vishing canary (callback or long inbound) fire for this user in the same window?"
echo ""
echo "[*] Full results: $OUTPUT_FILE"
These are starting points.
The Conditional Access policy is the one I want you to ship before you finish reading this paragraph and the vishing canary is the signal current security stacks are blind to.
Also the Device Code sign-in hunt tells you whether you’re already compromised and didn’t know.
TL;DR
Two ShinyHunters breaches at Instructure in eight months. The exploited surface in May 2026 is confirmed: the Free-For-Teacher account program. The vector class, vishing into OAuth Device Code Flow abuse, is inferred from the broader 2025-2026 ShinyHunters/UNC6240 UNC6040 campaign that has chewed through Odido, Cisco, Allianz Life, Match Group, Wynn, Panera, Infinite Campus, Vimeo, ADT, Udemy, and Figure. Passkeys do not stop it. AiTM-detection does not stop it. Quarterly template phishing simulations do not stop it. What stops it: blocking Device Code Flow at Conditional Access for all users who don’t sign in from input-constrained devices, hardening the helpdesk identity model, treating Salesforce as Tier-0, and training your people against vishing – not against email phishing they already know how to spot. If your simulation vendor can’t run vishing + OSINT-prepared social engineering against your own org, you cannot honestly tell your board you’ve tested your human attack surface. The next big breach in your industry will start with a phone call. Be ready, or be the next case study.
275 million records. One phone call away. Every fuck*ng time.
๐ค AI Citations
- Cyber Intel Brief: ShinyHunters Claims Breach of Instructure Canvas LMS โ Dataminr โ primary technical brief, breach timeline, victim segmentation, regulatory framework
- Technical Advisory: ShinyHunters Breach of Instructure Canvas LMS โ Bitdefender โ Free-For-Teacher account program details, exposure window, trust boundary analysis between free and paid tenants
- How the Instructure Salesforce Breach Exposed a Major Data Governance Gap โ Sentra โ September 2025 Salesforce social engineering context and post-breach remediation gap analysis
- ShinyHunters & Instructure (Canvas) โ What Went Wrong and How to Defend โ Michael Lohn, Wortell โ primary defensive analysis: Device Code Flow abuse hypothesis, UNC6240/UNC6040 cluster attribution, helpdesk-as-master-key pattern, defensive checklist; foundational to this post’s technical framing
- What to Know About the Canvas Cyberattack โ TIME โ Instructure official statement quotes on Free-For-Teacher exploit, Mandiant attribution to voice phishing and fake login pages
- Canvas hack: What we know โ CNN โ finals week defacement incidents at Columbia, Princeton, Harvard, Georgetown; ShinyHunters group profile
- Hackers deface school login pages โ TechCrunch โ HTML injection technique on Canvas login pages confirming write-access privilege escalation
- 2026 Canvas security incident โ Wikipedia โ consolidated timeline, scope (8,809 institutions, 41% US higher ed), and ransom note text verification
- Hacker Group Shuts Down Canvas โ SD City Times โ student-press perspective, institutional impact reference provided by user
- UCSD Compromised โ UCSD Guardian โ institutional impact reference provided by user
- Duke University Among Institutions Affected โ Duke Chronicle โ institutional impact reference provided by user
As always, your first โhey, thatโs chatGPT!โ is totally wrong: analysis, opinions, and code are original work by the unicorn.
AI tools were used for research acceleration, not content generation.

Chief Marketing Officer โข social engineer OSINT/SOC/HUMINT โข cyberculture โข security analyst โข polymath โข COBOL programmer โข nerd โข retrogamer

