Three Magento Zero-Days in One Year. Here's What I Learned and How They're "Similar".
SessionReaper, PolyShell and StyleSmuggler hit different parts of Magento months apart, from different people. Side by side they stop being three stories and start looking like one reused recipe.
A Magento zero-day hits harder than caffeine. Keeps you awake just as long, and unlike coffee there is no polite way to decline one.
And it's always the same origin story. Some random hacker, too much time on their hands, pushing code on a Saturday night while the rest of us are pretending to have a weekend. Nobody schedules these. They just arrive, usually around the hour you finally sat down.
Three of them in about a year. SessionReaper in the autumn, PolyShell in the spring, StyleSmuggler this month.
Different bugs. Different parts of Magento, being the customer address upload, the guest cart, and the template engine. Different people behind them, as far as anyone can tell. Adobe issued a different patch for each one, on a different day, with a different number.
I read all three write-ups because I had to. Every store we run was affected by at least one of them, and by StyleSmuggler we were reading Sansec's post while the attack was already in our logs. Reading the manual and the incident at the same time. Not a great morning.
And somewhere in the third read-through it stopped feeling like three stories.
They are not the same vulnerability. I want to be careful here, because “it's all the same” is exactly the kind of sentence that makes security people close the tab. The bugs are genuinely different, and if you are patching them you patch them differently.
But the attack, meaning the shape of it, the order of the moves, what the attacker needs from you and what they leave behind, is close to identical across all three. Once you see the shape, the next one is much less surprising. That is worth more than knowing any single CVE number, because the next CVE number does not exist yet.
So here is the shape.
The three, quickly
SessionReaper (CVE-2025-54236). A flaw in the Commerce REST API, rated 9.1. An attacker uploads what looks like session data through the customer address file upload endpoint, and a nested deserialization bug in the REST API turns that file into code the server runs. Account takeover, and unauthenticated remote code execution when the store keeps its sessions in files. Adobe patched it in September 2025. The first real attacks landed six weeks later, the day after a public technical analysis went out. At that point 62% of stores had still not patched.
PolyShell (APSB25-94). Magento's REST API accepts a file upload as a custom option on a guest cart item. The validator checks that the bytes look like an image. It never checks that the filename does. So you send a file that begins GIF89a, which satisfies the image check, and continues with PHP, which satisfies nothing but does run. Six characters of costume and the bouncer waves it through. No login needed either, just a guest cart ID and a product SKU, both free to get. Sansec saw the first probing on 16 March 2026, mass scanning by the 19th, and by the end of the month 79.5% of monitored stores had been hit at least once. On one day in March they counted 471 stores compromised in a single hour.
StyleSmuggler (CVE-2026-75650). Rated 10.0, and a zero-day in the truest sense, with attacks on 4 September 2026 and Adobe's hotfix on the 7th. A crafted GraphQL request abuses styles properties to smuggle PHP into a file Magento writes by itself during normal operation, such as a payment failure report. A second request makes Magento render that file. Versions 2.4.4 through 2.4.9 were affected. Sansec reproduced it on clean installs, and one of the first victims was running a store patched in July and August. Fully patched, by its own process, and still exposed.
That is three different bugs. Now the part that matters.
1. Nobody sends one request (Multiple Stages)
Not one of these is a single-shot exploit. Every one of them splits into plant and execute, and the two halves look nothing alike.
SessionReaper plants a poisoned session file, then triggers the deserialization. PolyShell uploads a fake image, then asks the web server for it as a PHP page. StyleSmuggler poisons a report file through a query string, then hits an entirely different address to make Magento render it.
Both halves are boring on their own. That is the point. Stage one is a file upload, and stores accept files all day. Stage two is a request for a path that exists, and servers serve paths all day. Neither request is remarkable in isolation, and anything that only ever looks at one request at a time will find nothing wrong with either.
In our own StyleSmuggler logs the two stages came from different addresses, one second apart. Whoever built it had already assumed someone might be watching one of them.
23:50:17 GET /graphql?styles[...] -> 200 (probe)
23:50:18 POST /paypal/transparent/... -> 403 (payload, different address)If you take one thing from this post: stop thinking of an exploit as a request. Think of it as a sequence. The defensive question is not “is this request malicious” but “should this client be doing this here at all”.
2. The second vulnerability is your server, and nobody sends you an advisory for that one (Multiple Places)
This is the one that changed how I think, so forgive me for spending a paragraph on it.
None of these three is purely a Magento bug. Each one needs a second condition, and that second condition is your infrastructure.
SessionReaper reaches full remote code execution when sessions are stored as files. Move them to Redis and the worst outcome gets meaningfully smaller.
PolyShell is the clearest case. The upload always succeeds. Whether that upload becomes code execution depends entirely on your web server, meaning an Apache without the .htaccess that ships with Magento, or an NGINX config that cheerfully hands any .php file to FastCGI. With a correct config the file just sits there, inert. Sansec is blunter about the long tail: the file stays on disk forever, so a future config change, a migration, or a new server can arm it years later.
StyleSmuggler needs the directory where Magento writes its own reports to be reachable and renderable.
Remember the PolyShell hacker I interviewed. Not a Magento developer, not a developer at all by their own account, and they still knew this cold.
If you're on NGINX, that blocks a full RCE. If you have Magento 2 on Apache, and worse, with cPanel, it's almost certainly gone.
They were right, and they knew it before I did. Which is a humbling thing to type.
So the same CVE, the same payload, the same attacker, produces either a harmless file or a total compromise depending on a config file nobody has opened in two years. Adobe cannot patch that for you. It is not in the advisory. It is in your stack, sitting quietly next to a comment that says TODO: clean this up, dated 2021.
3. They all come in through the API (!Important)
REST for SessionReaper. REST for PolyShell. GraphQL for StyleSmuggler.
Not one of them touches the storefront a shopper uses. No forms, no login page, no checkout. Every single one goes through the machine-facing side of Magento, the part built for payment providers, stock systems and mobile apps, and the part almost nobody has ever looked at a log line from.
This is not a coincidence, and it is not sophistication. It is where the surface is. The API takes structured input, it takes it without a session, it is documented in detail, and it is identical on every Magento store on earth. Write the exploit once, it runs everywhere.
Which brings up the thing I keep saying to anyone who will listen. That hacker told me they had never operated a Magento store, could not code, found a CVE post, and had AI build them an API attack. “A new CVE is a new toy to play with.” Three people, eight hours, a large chunk of the internet.
That is the modern attacker profile, and it explains the target choice perfectly. Someone who cannot read Magento's source can still read Magento's API documentation, because the documentation is the exploit surface. AI closed the gap between a published CVE and a working automated exploit, and the gap is now measured in hours.
Counter-argument, because I do try to argue with myself: this does not mean your API is a liability you should switch off. Your integrations need it, your app needs it, and disabling GraphQL, which was Sansec's own emergency advice during StyleSmuggler and reasonable advice for a day, is not something you can live with for a month. The point is not to close the API. The point is to stop treating it as a quiet back office, and start treating it as the front door it demonstrably is.
4. The way in is disposable. What it leaves behind is not. (Damage)
Every one of these dropped something built to last, delivered by something built to vanish.
SessionReaper's payloads included test shells that delete themselves after running once, alongside persistent backdoors written into bootstrap and error handler files, which is exactly where nobody looks.
The StyleSmuggler shell we caught expired after 180 seconds, demanded a secret value in the request, and removed itself when finished. Had it run once, it would have taken the evidence with it. What it was there to install was a Rust binary pretending to be a normal Linux kernel thread, later versions renaming themselves after font and clock utilities, with cron entries restarting them twice an hour, and command-and-control traffic shaped to look like NTP time sync so it slides past outbound firewall rules.
PolyShell crews dropped a webshell, then scattered a second backdoor across several directories in case you found the first, then injected skimmer JavaScript that caches itself in the browser so it survives you cleaning the page.
Note the craftsmanship gap, by the way. The person who could not code got AI to write the way in. Somebody who very much can code wrote the thing that stays. These are not the same skill level and often not the same person, which is its own uncomfortable thought: the amateur opens the door, the professional moves in.
The asymmetry is the lesson. The entry is designed to be forgotten. The implant is designed to be permanent. Which means “I found the webshell and deleted it” is not an incident response. It is the first thirty seconds of one.
5. The scanning never stops, so being unknown protects nothing (Never Stop)
SessionReaper's real attacks arrived six weeks after the patch, the moment a technical analysis was published. PolyShell was being probed a day before public disclosure and was mass-scanned inside 72 hours. StyleSmuggler's campaign came back several days later, same payload, but sent from 178 different residential and proxy addresses across a dozen countries, one or two requests each.
That last detail deserves a moment, because it quietly kills a defence a lot of people rely on. If every attacking address only ever sends one request, then blocking bad addresses achieves nothing at all. The block always lands after the request that mattered, on an address that was never coming back.
The spray is permanent and it is indiscriminate. Nobody chose your store. As I put it after the interview: you don't get targeted, you get found. “We're too small to matter” is not a security posture. It just means you are in the same spray radius as everyone else, with less of a security team.
So there is really only one point here
None of this was crafted by hand. It doesn't read like a person who knows Magento sat down and studied it. It reads like someone pointed a machine at a published CVE and let it write the attack, which, based on the one I actually spoke to, is exactly what happened.
And look at what that machine produced. Three different weaknesses, in three unrelated corners of Magento, chained across multiple stages, with the entry thrown away and the implant left behind. That is a lot of sophistication from people who, in at least one case, could not write the code themselves and had never used the software they were breaking.
But the pattern underneath it never changes. It has been the same all three times, and I expect it to be the same the next time.
Which is the good news, oddly. A pattern you can name is a pattern you can prepare for. You patch fast, because that is the floor and there is no version of this where patching does not matter. And then you build layers behind the patch, because every one of these had a window where no patch existed, and something has to hold the line during that window.
That is all defence in depth really is. Not one clever product that recognises attacks, but layer upon layer of ordinary controls, each asking a different simple question, so that the front door is merely difficult rather than open. Allegedly difficult, I should say. Nobody gets to call it locked.
I don't know what the next one will be called. Something with a capital letter in the middle, probably. CartWraith. StyleReaper II. Whatever the naming committee of one person on a Saturday decides.
Credit to Sansec, Searchlight Cyber and Assetnote for the public research these three write-ups are built on. Store identities and defence internals are deliberately omitted.
StoreFrame runs and secures Magento on your own cloud, with an OpenResty edge in front of every store, hardened containers, continuous scanning, and central logs the server itself cannot touch. Built for the attack that doesn't have a name yet.
See how StoreFrame secures Magento infrastructureA founder, an engineer at heart, an independent consultant who seek alternatives to the mainstream — Currently focused in burning AI tokens to deliver the best agentic e-Commerce experience.
More Articles
More Articles
Every Magento merchant asks whether the platform will still be here, and still be free, in five years. We stopped answering shop by shop and moved every customer to Mage-OS. Here's why.
One decision saved us setup time on every store, kept catalogue pages fast and stopped more bots: a self-hosted, Turnstile-style challenge that installs itself.
More than ten detectors score every request before anything is decided. Here is the scoreboard, what each signal is bad at, and the customers we annoyed on the way.
Every bot says it is Chrome. The handshake says otherwise. How we read JA4 and HTTP/2 fingerprints at the edge, why we needed both, and where they fail.
There are a dozen ways to put a web server in front of Magento. I tried most of them and landed on OpenResty — NGINX with Lua superpowers. Here's the honest case for it, and against the alternatives.
Half of a Magento store's traffic are bots, and today's scrapers solve puzzles and rent home internet. Here is the layered strategy we run, with real numbers.

