Back to blog

CVE-2026-58644: how one unsafe deserialize turns an on-prem SharePoint server into unauthenticated remote code execution

· · 19 min read
CVE-2026-58644: how one unsafe deserialize turns an on-prem SharePoint server into unauthenticated remote code execution

On July 14, 2026, as part of the largest Patch Tuesday Microsoft has ever shipped, the company quietly pushed a fix for a SharePoint bug that had already been used against real servers. The advisory for CVE-2026-58644 was updated the following day to confirm what defenders had started to suspect: exploitation had been detected in the wild. The verdict is as blunt as it gets. An unauthenticated attacker, reachable over the network with no credentials and no user interaction, can send a crafted serialized payload to an on-premises SharePoint Server and have it execute arbitrary code as the web application identity. Microsoft rates it CVSS 9.8, and the vector (AV:N/AC:L/PR:N/UI:N) leaves nothing to soften. The striking part is the provenance: the flaw belongs to the same deserialization family that the Zero Day Initiative demonstrated at Pwn2Own Berlin earlier in 2026. Researchers handed Microsoft a working exploit, and the class shipped to production anyway.

This article is a two-layered breakdown. The first part is for the people who need to decide, quickly, whether they have anything to do this week and what exactly that is. No jargon, just the shape of the problem, who is exposed, and the order of operations. The second part dissects the vulnerability the way an offensive researcher would reconstruct it: the SharePoint request pipeline, the .NET deserialization sink, the gadget chain that turns an object graph into a shell, and the machine-key theft that makes the whole thing durable. We close by looking at how the Pragma Core platform addresses exactly the kind of problem that made this possible, because a deserialization sink reachable from an unauthenticated endpoint is not bad luck. It is a pattern, and patterns are findable.


Part I. Executive breakdown

What happened

SharePoint Server is the on-premises collaboration platform that a very large number of enterprises and government agencies still run inside their own data centers: document libraries, intranet portals, workflow engines, the connective tissue of a lot of internal operations. To do its job, SharePoint constantly passes structured objects back and forth between the browser and the server. Some of those objects arrive as serialized .NET data, a compact binary or text representation of a live object that the server rebuilds into memory.

The bug is in that rebuild step. When SharePoint received one particular kind of serialized input, it reconstructed the object without first checking whether the incoming data described something safe. Think of it as a receiving dock that accepts a sealed crate and assembles whatever is inside according to instructions printed on the crate itself, without ever asking whether those instructions should be trusted. An attacker who controls the crate controls the assembly. In .NET, a carefully constructed object graph does not just produce data when it is rebuilt. It can trigger method calls, and those method calls can be steered all the way to launching a process.

The concrete result: an attacker with no account, no password, and no phishing lure sends a single crafted request to an internet-facing SharePoint server and gets code execution as the SharePoint application pool identity. From there, the observed playbook is to steal the server's cryptographic machine keys, which lets the attacker forge trusted requests at will, plant a web shell, and stay resident long after the initial hole is patched. This is not a theoretical read of the CVSS vector. CISA added CVE-2026-58644 to its Known Exploited Vulnerabilities catalog on July 16, 2026, and gave federal agencies until July 19 to remediate.

Who is affected

This is an on-premises problem. SharePoint Online, the cloud service inside Microsoft 365, is not in scope. If you run SharePoint Server yourself, you almost certainly need to act.

Component Status
SharePoint Server Subscription Edition Vulnerable below build 16.0.19725.20384. Patch now.
SharePoint Server 2019 Vulnerable below build 16.0.10417.20153. Patch now.
SharePoint Enterprise Server 2016 Vulnerable below build 16.0.5556.1005. Patch now.
SharePoint Online (Microsoft 365) Not affected. Managed by Microsoft.
SharePoint Foundation / 2013 and earlier Out of support. Treat as exposed; migrate or isolate.

The number that should worry you is not the CVSS score, it is the exposure. Independent scan data put roughly 1,370 internet-facing SharePoint servers in a vulnerable state in the days around disclosure, down only modestly from the count a few months earlier. SharePoint has been under sustained assault through 2025 and 2026, and CVE-2026-58644 is one of four SharePoint flaws (alongside CVE-2026-32201, CVE-2026-45659, and CVE-2026-56164) that CISA has flagged as actively exploited in the same window. When a product is already being hunted at scale, an unauthenticated 9.8 with confirmed in-the-wild use is not a maybe. It is a when.

Why this matters beyond SharePoint

The specific product is Microsoft's, but the bug class belongs to everyone who runs a .NET, Java, Python, PHP, or Ruby application that accepts serialized objects from the outside world. Unsafe deserialization (CWE-502) is one of the most reliable paths to remote code execution in modern server software precisely because the vulnerable pattern is so ordinary: an app wants to send rich objects over the wire, reaches for the platform's native serializer, and forgets that the native serializer was designed for trusted data, not attacker-controlled data.

The lesson generalizes cleanly. Anywhere a server takes bytes off the network and turns them back into live objects (view state, session blobs, message queue payloads, cache entries, API request bodies, cookies), there is a candidate for this exact failure. The SharePoint case is a high-value instance of a bug you should be actively looking for in your own stack, not a Microsoft-only curiosity.

Recommended actions

  1. Upgrade to the fixed build for your edition now: Subscription Edition 16.0.19725.20384, Server 2019 16.0.10417.20153, or Enterprise Server 2016 16.0.5556.1005 or later. This is the only action that closes the hole. Everything else buys time.
  2. Assume compromise if the server was internet-facing and unpatched. Given confirmed in-the-wild exploitation before the patch, hunt before you trust. Look for unexpected .aspx files under the SharePoint layouts directories, anomalous w3wp.exe child processes, and outbound connections from the SharePoint host.
  3. Enable AMSI full-mode integration for SharePoint so the Antimalware Scan Interface inspects full request bodies, not just headers. This is Microsoft's recommended interim control and it catches many deserialization payloads at the door.
  4. Rotate the ASP.NET machine keys after you have finished threat hunting, not before. Machine-key theft is the mechanism attackers use for durable access; rotating keys while the attacker is still resident just tells them to grab the new ones. Hunt, evict, then rotate.
  5. Restrict internet exposure. Put SharePoint behind a VPN or identity-aware proxy. A collaboration server does not usually need to answer anonymous requests from the entire internet.
  6. Inventory every SharePoint instance and its exact build, including the forgotten test farm and the departmental portal nobody owns. You cannot patch what you cannot see, and response speed here is dominated by how fast you can answer "which servers, which version."

Part II. Technical breakdown

The SharePoint request pipeline and where trust is assumed

SharePoint is a very large ASP.NET application layered on top of IIS. Almost every meaningful interaction flows through an .aspx handler or a web-service endpoint, and a substantial amount of SharePoint's internal state travels between client and server as serialized .NET objects. Two mechanisms matter for this bug.

The first is ASP.NET view state. Every classic ASP.NET page round-trips a __VIEWSTATE field: a base64-encoded, serialized representation of the control tree's state. The framework protects it with a message authentication code (MAC) derived from the server's machineKey. If the MAC is valid, ASP.NET trusts the blob and deserializes it back into objects. The security of the entire mechanism rests on one assumption: only the server knows the machine key, so only the server can produce a blob that passes the MAC check.

The second is SharePoint's own use of .NET serializers to move object graphs across internal boundaries. Historically SharePoint has leaned on BinaryFormatter, LosFormatter, ObjectStateFormatter, and SoapFormatter in various code paths. Every one of these formatters shares the same design property: when they deserialize, they will instantiate whatever types the serialized stream names and invoke whatever setters, callbacks, and constructors those types define. They were built for a world where the input is trusted. The invariant they quietly assume is that the byte stream came from your own code. CVE-2026-58644 is what happens when that invariant is false.

The vulnerability: an unauthenticated path to an unrestricted deserializer

At its core the flaw is textbook CWE-502. A request-handling code path takes attacker-influenced input, feeds it into a .NET formatter that performs type-unrestricted deserialization, and does so before (or without) any authentication that would keep an anonymous caller out. Microsoft's description is terse but exact: deserialization of untrusted data in SharePoint allows an unauthorized attacker to execute code over a network.

Because SharePoint Server is closed source, the snippets below are a faithful representation of the vulnerable pattern rather than leaked product code. They show the shape of the defect precisely as it appears in real .NET deserialization RCE, which is what you should be able to recognize in your own applications.

The unsafe sink looks like this:

// Representative of the vulnerable pattern (CWE-502).
// An endpoint reconstructs a .NET object from request-controlled bytes.
public object RebuildState(HttpRequest request)
{
    byte[] blob = Convert.FromBase64String(request["__payload"]);

    // No SerializationBinder, no type allow-list, no MAC check
    // on this path: the formatter will instantiate ANY type the
    // stream names and run its deserialization callbacks.
    var formatter = new LosFormatter();      // <-- the sink
    using (var ms = new MemoryStream(blob))
    {
        return formatter.Deserialize(ms);    // <-- RCE happens here
    }
}

The single most important line is formatter.Deserialize(ms). LosFormatter, like BinaryFormatter and ObjectStateFormatter, has no concept of an allowed-types list unless one is explicitly wired in through a SerializationBinder. The moment that call runs on attacker bytes, the attacker, not the developer, decides which types get constructed and which of their methods get called during reconstruction.

Contrast that with the shape the fix has to take. A safe version rejects unexpected types before it ever builds them:

// The defensive shape: constrain what is allowed to deserialize.
public object RebuildStateSafe(HttpRequest request, byte[] blob)
{
    // 1. Authenticate FIRST; anonymous callers never reach the sink.
    if (!AuthContext.IsAuthorized(request)) throw new SecurityException();

    var formatter = new BinaryFormatter
    {
        // 2. Refuse any type not on an explicit allow-list.
        Binder = new AllowListBinder(typeof(ExpectedState))
    };
    // 3. Better still: abandon the runtime formatters entirely and
    //    use a data-only serializer (System.Text.Json, DataContract).
    return formatter.Deserialize(new MemoryStream(blob));
}

The three defenses (authenticate before the sink, restrict the types, or drop the runtime formatters in favor of a data-only serializer) are exactly the controls the vulnerable path was missing. Any one of them, present, would have blunted the bug.

Root cause: a gadget chain does the work, not the formatter

Deserialization by itself does not spawn a shell. The attacker needs a gadget chain: a sequence of classes already present in the target's loaded assemblies whose deserialization callbacks, property setters, or IDisposable/finalizer behavior can be strung together so that rebuilding the object graph ends in a call to something like Process.Start or a runtime code compile. The .NET ecosystem has a mature catalog of these, and the tool ysoserial.net automates their construction for formatters exactly like LosFormatter and BinaryFormatter.

A representative chain used against .NET targets abuses TypeConfuseDelegate, which corrupts a serialized multicast delegate so that invoking what looks like a benign comparison callback actually invokes Process.Start. Wrapped inside a SortedSet<T> whose comparer is the poisoned delegate, the malicious behavior fires during deserialization, before the application ever inspects the resulting object. The root cause, then, is not a single missing check but the combination of two facts: the formatter will build any type, and the runtime ships with types whose reconstruction has side effects. Remove either and the primitive collapses. SharePoint could remove only the first, which is why the fix is an allow-list and pipeline change rather than a one-line patch.

Exploitation: from anonymous request to durable tenancy

The observed exploitation of the SharePoint family follows a consistent arc, and CVE-2026-58644 slots into it as the initial code-execution primitive.

POST /_layouts/15/<vulnerable-endpoint>.aspx HTTP/1.1
Host: sharepoint.victim.example
Content-Type: application/x-www-form-urlencoded

__payload=<base64 ysoserial.net TypeConfuseDelegate gadget>

When the crafted __payload reaches the deserialization sink, the gadget chain executes as the SharePoint application pool account. That is step one. Step two is where the campaign becomes durable, and it is the part that turns a patchable bug into a long-term intrusion:

  1. Steal the machine keys. The freshly landed code reads ValidationKey and DecryptionKey out of the server's configuration. These are the very keys ASP.NET uses to MAC-protect view state.
  2. Forge trusted view state. With the keys in hand, the attacker can now craft __VIEWSTATE blobs that pass the MAC check on any endpoint. Authentication becomes irrelevant; the server treats the forged blob as its own. This is the same technique that powered the 2025 ToolShell campaign, and it is why key theft is the crown jewel.
  3. Plant a web shell. A malicious .aspx file dropped into the layouts directory gives interactive access that survives service restarts.
  4. Persist and spread. From the SharePoint identity, attackers pivot into the surrounding Windows environment, harvest credentials, and deploy follow-on malware.

The crucial takeaway is that patching CVE-2026-58644 closes the front door but does nothing about a key that has already walked out the back. That is why the recommended sequence is hunt, evict, then rotate keys, and it is why "we patched" is not the same as "we are safe" for any server that was exposed before July 14.

Affected versions

Note on the authorization requirement: the authoritative CVSS vector for CVE-2026-58644 is PR:N, no privileges required, and the Zero Day Initiative's write-up of the paired Pwn2Own finding is explicit that it needs no authentication or user interaction. A handful of secondary outlets described a Site Owner precondition, most likely conflating it with a sibling SharePoint bug in the same batch. When sources disagree, the CVSS vector and the primary researcher win: treat this as unauthenticated.

Timeline

Date Event
Early 2026 The SharePoint deserialization class is demonstrated at Pwn2Own Berlin; ZDI provides Microsoft a working exploit.
2026-07-14 Microsoft ships the fix as part of a record July Patch Tuesday (over 600 CVEs).
2026-07-15 Microsoft updates the advisory to confirm exploitation detected in the wild.
2026-07-16 CISA adds CVE-2026-58644 to the Known Exploited Vulnerabilities catalog.
2026-07-17 NVD entry last modified; roughly 1,370 SharePoint servers still exposed per scan data.
2026-07-19 Federal remediation deadline for FCEB agencies.

A note on the discovery methodology

The most instructive detail is not technical, it is procedural. The class was surfaced through Pwn2Own, an adversarial research event where the finding arrived with a working exploit attached, and yet Microsoft's own advisory initially carried an "Exploit Maturity: Unknown" rating, a gap the ZDI team pointed out with some irritation given they had handed over the exploit themselves. The meta-lesson for defenders is uncomfortable: the existence of a fix and the vendor's stated exploit maturity are lagging, imperfect signals. A deserialization sink reachable without authentication is exploitable the day it exists, regardless of what a severity dashboard says on release day. The teams that fared best treated the bug class as live from the first advisory, not from the moment a maturity field flipped.


What we should learn from CVE-2026-58644

  1. Native runtime serializers are a sink, not a convenience. BinaryFormatter, LosFormatter, ObjectStateFormatter, and their Java/Python/Ruby equivalents deserialize into live objects with side effects. Treat every call to one on externally influenced data as a code-execution sink until proven otherwise, and prefer data-only serializers (System.Text.Json, DataContract) that never instantiate arbitrary types.

  2. Authentication must sit in front of the dangerous sink, not somewhere in the general vicinity. The whole severity of this bug comes from an anonymous request reaching a deserializer. Map every code path that reaches a risky sink and prove that an authorization check dominates it. A gate that guards the front page but not the state-rebuild handler is not a gate.

  3. Cryptographic keys are blast-radius multipliers, and stealing them survives the patch. The machine key turns a one-shot RCE into forgeable, authentication-free access. Any secret that lets an attacker impersonate the server deserves rotation-on-compromise planning and monitoring for the moment it is read.

  4. Vendor severity metadata lags reality. An "Exploit Maturity: Unknown" label on a bug that was literally exploited at Pwn2Own is a reminder to prioritize on the intrinsic properties of the bug (unauthenticated, network-reachable, deserialization) rather than on a maturity field that updates late.

  5. Exposure is a first-class metric. The difference between a bad week and a breach was often just whether the server answered anonymous internet traffic. Knowing exactly how many instances you run, at which build, reachable from where, is the input that determines your response speed. Most teams cannot answer this fast enough, and that gap is where dwell time is born.


How Pragma Core addresses this class of problem

Deserialization RCE is precisely the kind of bug that lives between the lines rather than on one of them. The unsafe Deserialize call is not, by itself, unusual; what makes it critical is the path that reaches it, the authentication that does not dominate that path, and the gadget types that happen to be loaded in the same process. A rule that flags "BinaryFormatter used" drowns teams in noise, while the finding that matters, "an unauthenticated request reaches a type-unrestricted deserializer," requires reasoning across the call graph. Pragma Core is built for exactly that reasoning.

SAST tuned for the deserialization pattern, not just injection sinks

Off-the-shelf static analysis is optimized for taint flows that end in SQL or shell. Pragma Core's static analysis is tuned to the CWE-502 shape directly: a call to a runtime formatter (LosFormatter, BinaryFormatter, ObjectStateFormatter, SoapFormatter) on a value that traces back to request input, with no SerializationBinder or type allow-list on the path. In a SharePoint-style codebase, that is a high-confidence finding rather than a guess, because the analysis is looking for the specific combination that makes deserialization dangerous, not merely the presence of a formatter.

Interactive call graphs that expose the reachable-without-auth path

The severity of CVE-2026-58644 is a property of a relationship: the deserialization sink and the authentication check live in different functions, and the bug is that the second does not dominate the first. Pragma Core auto-generates call graphs for every connected repository and overlays findings on them, so an AppSec reviewer can see, visually, that an anonymous entry point has an unbroken path to Deserialize with no authorization gate in between. That is the picture no single-line finding can draw, and it is the picture that turns "there is a formatter here" into "there is an unauthenticated RCE here."

Autonomous AI agents for attack-chain investigation

Pragma Core's autonomous agents reason over chains rather than stopping at a flagged line. Turned on this codebase, they ask the questions a human researcher would: which endpoints reach a formatter, is any of them reachable before authentication, are known gadget types (delegate-confusion, SortedSet comparers, ObjectDataProvider) present in the loaded assemblies, and does a stolen machine key extend the primitive into forgeable view state. Those are the exact questions that separate a benign deserialize from a 9.8, and they are asked systematically rather than only when a researcher happens to look.

White-box pentest that proves the primitive

A finding that says "possible deserialization sink" is a hypothesis. Pragma Core's source-assisted, agent-driven pentest closes the loop by attempting the reachable path end to end, the way the Pwn2Own researchers did: construct a gadget payload, drive it to the endpoint, and confirm whether code actually runs. Confirmed findings, not maybes, are what let a team justify an emergency change window for the one server that is genuinely exploitable instead of treating all of them as equally urgent.

Full SBOM and dependency tracking for the "which servers, which build" question

The response bottleneck for this CVE is inventory: which SharePoint instances exist, at which build, exposed where. Pragma Core generates a complete per-repository SBOM (CycloneDX) and continuously tracks components and versions across every connected project, including dependencies buried in appliances and internal tooling. The moment a CVE like this lands in the catalog, the platform can answer "do we run an affected build, and where" in minutes rather than in the days it usually takes to chase down a forgotten farm.

Human-guided investigations, applied systematically

This bug was found by expert humans doing adversarial research at Pwn2Own. Pragma Core's expert-led research module is that same instinct made repeatable: an AppSec operator drives a deep investigation into whatever the team feels is fragile (say, every deserialization path in an internet-facing service), backed by autonomous agents and the full repository context already in the workspace. It is the Pwn2Own mindset, minus the once-a-year cadence and the requirement that the world's best researchers happen to pick your product.


Closing thoughts

CVE-2026-58644 is not, fundamentally, a bug about SharePoint. It is a bug about trusting a byte stream to describe the objects it becomes. The same pattern lives in Java applications calling readObject, Python services reaching for pickle, Ruby apps unmarshaling YAML, and any .NET codebase that still has a BinaryFormatter on a network-reachable path. The affected products change; the shape does not. An input crosses a trust boundary, a native serializer rebuilds it without restriction, and a gadget chain already present in the process does the rest.

The organizations that treated this advisory as a curiosity spent the week reading news about it. The ones that treated it as an audit trigger asked a better question: where else in our own stack does untrusted input reach a deserializer, and does anything actually stop an anonymous caller from getting there? Answering that at the level of the whole codebase, continuously, is the difference between "we scan and report" and "we systematically investigate what is fragile." If you want to make that shift, Pragma Core can help. Reach us at pragma-core.com for a demo.


Sources

Related posts
CVE-2026-74820: how an unsanitized ORDER BY clause turned ServiceNow's AI Platform into an unauthenticated database backdoor
Sep 18, 2026
CVE-2026-85978: how one path normalization mismatch turned Akana's admin console into unauthenticated remote code execution
Sep 9, 2026
CVE-2026-78174: how an unredacted session token in a diagnostic log turned a low-privileged WatchGuard Dimension admin into super admin
Sep 1, 2026

Start securing your codebase today

Connect your repositories and let AI agents handle continuous scanning, research, and triage.

Have questions? Get in touch →