The Canvas Case Deep Dive
Logo of Canvas LMS via Wikimedia Commons
This is a companion to The Crime That Leaves Nothing Missing. That article, is about what cyber theft means as a category; the copy that does not subtract; and the question of whether a crime that leaves nothing missing is still a crime.
I usually don’t write articles like this one, but after enough reading, a little discussion with my engineer friend Phil, and a load ton of coffee on a rainy Friday 😆, I think I have enough context and a timeline of how the Canvas breach actually happened.
- The architecture that made it possible.
- The commit that, three weeks before the breach, named the unpatched surfaces.
- The twenty-four days between the public diff and the unauthorized access, and the two weeks between detection and a paid ransom.
This article is a timeline of events.
The Architecture
Logo of Instructure via Wikimedia Commons
Canvas LMS is a learning management system. According to Inside Higher Ed, about forty-one percent of higher education institutions in North America use it. It is also used in K-12 districts, in medical and nursing schools, in continuing-education programs around the world. Roughly 275 million users across approximately 8,809 institutions, according to Trend Micro’s consolidated reporting on the incident. It is, in industry terms, infrastructure.
Canvas has long had a free tier called Free-For-Teacher, or FFT. Educators could create a Canvas tenant, a self-contained instance with its own users and courses, without their institution’s involvement. The pitch was access. Try Canvas, see if it works for your classroom, bring it up the chain.
The architectural choice that proved consequential: FFT tenants shared back-end infrastructure with paid institutional tenants. The same servers, the same database cluster, the same service-account credentials in many cases. The separation between a free tier and a paid tier was a logical boundary, not a physical one.
To keep onboarding frictionless, identity verification on FFT accounts was looser than on paid institutional accounts. Email-based, mostly. The point was to remove friction. The unintended consequence was that an attacker who could get themselves an FFT tenant, and then find a way to traverse the logical boundary, could reach the same infrastructure that hosted the paid tenants. Bitdefender’s post-incident advisory framed it cleanly: “Freemium tiers in B2B SaaS frequently ship with weaker identity verification than paid tenants while sharing back-end infrastructure with the production product. When the verification gap becomes an exploitation gap, the isolation model collapses.”
April 1, 2026 — The Commit
On April 1, 2026 — Twenty-four days before the unauthorized access began, a commit landed in the public instructure/canvas-lms GitHub repository. SHA: 546ca8a1. Internal ticket: AE-3466. Title: “Pass current_user to SisPseudonym.for at all request-context calls.”
The commit’s message describes the bug:
Instructure Identity pseudonyms are only filtered from SisPseudonym.for results when current_user: is provided. Without it, pending inst pseudonyms are visible to all callers.
In plain English: in the Canvas codebase, there is a helper function called SisPseudonym.for that returns identity records — the records that map a user to their accounts across the system. The function had a filtering behavior that was supposed to scope those records to the calling user’s permissions. That filtering only worked when the current user context was passed in. Several callers were not passing it in. The result was that those callers would return identity records they were not supposed to be able to see, including identity records from other tenants.
The commit patches about ten callers. Files updated include users_controller.rb, sis_api_controller.rb, admins_controller.rb, submissions_api_controller.rb, communication_channels_controller.rb, two GraphQL types, and a couple of API helper libraries.
Then, beneath the test plan, the commit message says this:
Not addressed (no current_user context available): Background jobs and exporters (live_events.rb, gradebook_exporter.rb, enrollment_importer.rb, user_list_v2.rb, lti/*.rb, account_reports, custom_reports)
This is the unusual part. The author of the patch did not silently leave those files alone. They named them. The commit message itself listed the surfaces that still had the bug. The reason given is technically sensible; In background jobs and exporters there is no logged-in user from whose perspective to scope the query, so the simple fix of passing current_user does not apply. A more involved redesign would be required. But the listing was now public, in plain English, on a public repository.
The exporters and account-reports paths handle exactly the kind of bulk data that would later be exfiltrated: gradebooks, enrollment rosters, provisioning data, user lists at scale.
Two earlier commits from the same period are worth noting. On February 23, a commit hoisted the require_user filter to ApplicationController across roughly 150 controllers, making authentication opt-out rather than opt-in — “to avoid forgetting it,” as the message put it. Two days later, a separate commit fixed a cross-account data-leakage bug in the authentication audit for_user endpoint. Together with the April 1 commit, they describe an internal sweep against authorization gaps in the weeks leading up to the breach.
April 25 — Unauthorized Access Begins
Three weeks later, on or around April 25, an attacker established unauthorized access to Canvas’s production systems. The public framing in Instructure’s later disclosures and Bitdefender’s advisory is that the initial vector was social engineering; voice phishing against Instructure employees, paired with credential-harvesting pages branded to look like internal Instructure single-sign-on portals; a pattern named consistently across Bitdefender, Rescana, and Trend Micro’s post-incident analyses. That is consistent with ShinyHunters’ broader pattern across other 2025 and 2026 campaigns.
What happened next is not publicly confirmed in technical detail. What is documented is that, once inside, the attackers exfiltrated data using endpoints corresponding to “DAP queries, provisioning reports, user APIs, and Canvas data export features,” as BleepingComputer reported. Three of those four phrases, provisioning reports, user APIs, Canvas data export features, correspond directly to the surfaces that the April 1 commit had explicitly named as still vulnerable. account_reports. gradebook_exporter. enrollment_importer. The exporter and reporting paths that the commit message had listed by name.
A clarifying note: Instructure has not publicly confirmed that the April 1 commit is the vulnerability the attackers exploited. No CVE has been assigned. The chain of inference here is the alignment between the BleepingComputer attack-surface description and the commit’s Not addressed list. That is strong circumstantial evidence. It is not a confirmed root cause.
April 29 — Detection
Four days after the unauthorized access began, Instructure’s security team detected the intrusion. They revoked the attackers’ access, rotated credentials, and engaged third-party cyber-forensics experts, Instructure later confirmed on its public incident page. There was no immediate public disclosure. The systems remained operational. The academic year continued, including, at most US institutions, finals week.
May 3 — The Ransom Note
On May 3, ShinyHunters publicly claimed responsibility. Their initial post claimed 3.65 terabytes of exfiltrated data covering approximately 275 million users across roughly 8,809 institutions. The post named the attack surfaces in their own words: “DAP queries, provisioning reports, user APIs, Canvas data export features.” The phrasing is what allowed external observers, including me 😁, to begin reconstructing the chain back to the April 1 commit.
May 6–7 — The Second Breach
On May 6, Instructure issued a public statement indicating that the situation had been resolved.
On May 7, the Canvas login page was replaced with a ransomware message. ShinyHunters had returned. Their accompanying Telegram post taunted Instructure’s response: “Instead of contacting us to resolve it they ignored us and did some ‘security patches.’“
Instructure took Canvas, Canvas Beta, and Canvas Test offline for investigation. The Free-For-Teacher program was permanently shut down the following day. Service was restored on May 8.
May 11 — Settlement
Four days later, on May 11 - One day before ShinyHunters’ deadline to publish the stolen data, Instructure reached an agreement. The terms were not disclosed. A figure of approximately ten million US dollars has circulated as an unconfirmed estimate, the Wikipedia incident page frames it as “unconfirmed rumors,” and it has not been substantiated by Instructure. In exchange, ShinyHunters provided what they called shred logs, digital files purporting to confirm that the stolen data had been destroyed.
The same day, Instructure published an apology for what it described as a lack of transparency on its public incident-update page.
Whether the shred logs actually verify destruction is the subject of my other article. Briefly put, they do not. There is no possible artifact the attackers could provide that would prove the absence of every copy.
What We Still Don’t Know
As of the time of this writing, several things remain undisclosed or unresolved:
- The technical root cause. Instructure has not publicly confirmed which specific vulnerability or vulnerabilities were exploited. The reconstruction in this piece is circumstantial.
- Whether the carve-out surfaces have been patched. The files explicitly named as Not addressed in the April 1 commit,
gradebook_exporter.rb,account_reports,custom_reports, and the others, have not received public follow-up commits in the period since the breach. Whether they have been fixed in private branches and deployed only to production, or whether they remain in their pre-incident state, is not externally visible. - OFAC compliance of the ransom payment. US sanctions law requires screening before payments to known cybercriminal infrastructure. Whether Instructure’s payment satisfied that requirement is not public.
- Federal investigations. The US Department of Education’s Student Privacy Policy Office has formally requested information from Instructure on FERPA compliance. The FTC’s posture is reportedly active but not formally announced.
- Class-action exposure. Affected institutions have independent notification obligations under state breach-notification laws, FERPA, GDPR (for EU users), and the contracts they hold with students. The downstream legal pipeline has not yet fully formed.
This piece will not age well. By the time you are reading it, much of what is open here may be closed. Some of the reconstruction may turn out to be wrong. The point of writing it now is to capture what was visible at this moment, and how visible it was.
I might get back and update this article some time in the future if new elements are revealed, or I might just not. Because I’m only a human and can’t keep up with everything.
Till the next one, Stay safe and stay blessed!
References
- Inside Higher Ed (May 18, 2026). “No, Colleges Can’t Just Quit Canvas”
- Inside Higher Ed (May 11, 2026). “Instructure Pays Ransom to Canvas Hackers”
- The Hacker News, “Instructure Reaches Ransom Agreement with ShinyHunters to Stop 3.65TB Canvas Leak”
- BleepingComputer, “Instructure hacker claims data theft from 8,800 schools and universities”
- Bitdefender (May 2026). “Technical Advisory: ShinyHunters Breach of Instructure Canvas LMS”
- Rescana, “ShinyHunters Launches Second Major Attack on Instructure Canvas LMS via Free-For-Teacher Accounts”
- Trend Micro (May 2026). “What Is the Instructure Canvas Breach? Impact, Risks, and What Institutions Should Do”
- Instructure, Security Incident Update & FAQs
- US Department of Education / Federal Student Aid (May 12, 2026). “Technology Security Alert — Ongoing Cybersecurity Incident Involving the Canvas Learning Management System”
- Wikipedia, 2026 Canvas data breach
- Wikipedia, ShinyHunters
- Wikipedia, Instructure (Canvas LMS)
instructure/canvas-lmscommit546ca8a1— “Pass current_user to SisPseudonym.for at all request-context calls” (April 1, 2026)instructure/canvas-lmscommitc740023d— “hoist require_user filter to ApplicationController” (February 23, 2026)instructure/canvas-lmscommit01459787— “fix auth audit cross-account data leakage” (February 25, 2026)