2026-09-28 · CVE-2026-65660
CVE-2026-65660: The SharePoint Bug That Was Mislabeled 'Spoofing' Until It Wasn't
On August 12, 2026, Microsoft patched a SharePoint Server flaw it classified as spoofing, CVSS 6.5 — the kind of bug that gets a routine line item in a patch-management spreadsheet and not much else. By September 25, CISA had reclassified reality: the bug is a code injection vulnerability, it's being actively exploited to drop webshells on on-premises SharePoint farms, and it went on the Known Exploited Vulnerabilities catalog with a three-day remediation deadline — today, September 28.
That gap — "spoofing, 6.5" at disclosure versus "code injection, actively exploited, webshells" six weeks later — is the whole story. CVE-2026-65660 is a good case study not because the bug itself is exotic, but because it shows how badly an initial severity label can undersell a vulnerability once real attackers get their hands on it.
What the vulnerability actually is
CVE-2026-65660 lives in SharePoint's ToolPane component — the piece of the web-part editing UI that lets a site administrator preview and configure a web part before adding it to a page. When SharePoint renders that preview, it has to check the part being loaded against the SafeControls list, a configuration allowlist that's existed since SharePoint 2007 specifically to stop untrusted or unvetted .NET types from being instantiated and rendered on a page.
The bug is in how ToolPane builds the markup it uses to perform that check. The internal generator that constructs the control-registration string doesn't escape double-quote characters in attacker-controlled input. That means a specially crafted web-part directive can break out of the string SharePoint thinks it's building and inject its own attribute — including a type name that was never on the SafeControls allowlist.
In other words: the check exists, the check normally works, and this bug is a string-escaping failure that lets you smuggle a value past it. It's a markup-injection bug wearing an access-control bug's consequences — an attacker who can reach the ToolPane endpoint with a low-privileged, authenticated session can register an arbitrary .NET class and get it to execute server-side.
On its own, CVE-2026-65660 gets an attacker code execution as an authenticated user, not an anonymous one — Microsoft's original CVSS 6.5 wasn't wrong about the vulnerability in isolation, it was incomplete about what SharePoint's authentication model actually protects. Reaching unauthenticated RCE requires chaining it with a separate authentication-bypass weakness in the same on-prem SharePoint stack. That chaining is exactly what active exploitation looks like in the wild right now, and it's why "authenticated-only" bugs on internet-facing enterprise software deserve more triage weight than their CVSS number implies — the auth requirement is rarely the load-bearing part of the defense people assume it is.
Why the severity label was wrong
Microsoft's own advisory language matters here, because it shaped how a lot of organizations prioritized the patch. "Spoofing" reads as a phishing-adjacent, low-blast-radius bug category — something that might trick a user into trusting a forged page, not something that ends with a webshell on your SharePoint farm. Security teams triaging hundreds of monthly patches reasonably deprioritize "spoofing, 6.5" against "remote code execution, 9.8" from the same Patch Tuesday.
The reclassification came from external researchers who kept digging after the patch shipped, diffing the fix and reasoning about what the ToolPane change actually closed off. That's a pattern worth internalizing on its own: a vendor's initial CVE classification reflects the vendor's understanding of the bug's primary impact at disclosure time, not a ceiling on what the bug can do once someone else looks harder. SharePoint, vCenter, and a handful of other management-plane products have all had "the severity turned out to be worse than advertised" moments this year, and in every case the gap was discovered by people outside the vendor, after the patch was already public and diffable.
The exploitation timeline
| Date | Event |
|---|---|
| Aug 12, 2026 | Microsoft patches CVE-2026-65660, classified as spoofing, CVSS 6.5 |
| Aug–Sept 2026 | Researchers reanalyze the patch diff, determine actual impact is code injection → RCE (when chained) |
| Sept 25, 2026 | Microsoft confirms active exploitation; CISA adds it to the KEV catalog |
| Sept 25, 2026 | Observed attacks attempting to plant webshell backdoors on compromised farms |
| Sept 28, 2026 | Federal civilian remediation deadline |
Six weeks between "patch available" and "confirmed active exploitation" is not a fast burn compared to some of the same-week weaponizations we've covered before — but it's also not evidence that the bug sat unnoticed. It's evidence that a mislabeled bug can sit in a "we'll get to it" queue for weeks precisely because its label told defenders it wasn't urgent, right up until someone proved otherwise by using it against production systems.
SafeControls, and why allowlists on old software rot quietly
SharePoint's SafeControls list is a genuinely reasonable piece of defense-in-depth: don't let a web part instantiate arbitrary code, only ever the specific, reviewed set of controls an administrator has explicitly trusted. It's the same idea as a Content-Security-Policy allowlist or an API's permitted-parameters schema — a boundary that only works if every path that checks against it does so correctly, with no exceptions.
The failure mode here isn't that the allowlist concept is bad. It's that allowlist enforcement is only as strong as its weakest serialization path, and on a codebase with SharePoint's history — nearly two decades of incremental feature additions to the web-part rendering pipeline — there are a lot of code paths that eventually have to construct a string representing "which control is this." Every one of those paths is a place where an escaping bug can quietly reopen a door the SafeControls list was supposed to keep shut. This is the same class of lesson as an ORM that correctly parameterizes 99% of its queries except one hand-rolled string-concatenation helper nobody's touched since 2019 — the control isn't broken, one specific implementation of it is, and finding which one requires knowing the whole surface, not just the policy.
What this means for how we teach it
Web-part injection and allowlist-bypass bugs are a specific, teachable skill, and they're a different skill than "spot the SQL injection" or "spot the path traversal." The interesting part of CVE-2026-65660 isn't the escaping bug itself — string-escaping mistakes are common and well understood — it's the reasoning chain: this component has an allowlist, the allowlist is enforced by comparing against a generated string, generated strings can be malformed by unescaped input, therefore the allowlist can be bypassed by controlling what goes into the string before it's checked, not by attacking the check itself.
That's a pattern that recurs constantly in enterprise software: authentication and authorization decisions that get made against a value that was itself built from untrusted input somewhere upstream. Recognizing it requires actually tracing data from an input field through to the point where a security decision gets made on it — which is exactly the kind of thing that's nearly impossible to internalize from a slide describing "CWE-94: Improper Control of Generation of Code" in the abstract, and comes together fast the first time you watch an injected value change what a downstream allowlist check actually evaluates.
It's also a good reminder to build the habit of re-checking a vendor's own severity classification against what the CVE actually enables once a public writeup exists, rather than triaging purely off the initial CVSS score — because as CVE-2026-65660 shows, that number can describe last month's understanding of the bug, not this month's.
The takeaway
CVE-2026-65660 isn't remarkable for its exploit mechanics — a string-escaping failure that lets attacker input reach an allowlist check unsanitized is a well-worn bug class. It's remarkable as a live example of severity drift: a bug quietly reclassified from "spoofing" to "actively exploited code injection with observed webshell deployment" in the six weeks between patch and KEV listing, on a product that's internet-facing at a huge number of organizations by default. If your patch triage process treats a vendor's initial severity label as the last word rather than a snapshot, CVE-2026-65660 — like CVE-2026-59310 before it — is a reason to build in a second look once independent researchers start publishing analysis, and to make sure the people doing that triage have actually traced an allowlist-bypass chain themselves at least once, not just read the CVSS score.