We will be speaking at Meet Magento Germany on 22 October 2026. Come say hello.

Proudly supporting Mage-OS contributors — limited lifetime free access. Mage-OS contributors, please reach out. Terms, policies, and FAQ are still being finalized.

Security

We Survived StyleSmuggler, a Magento Zero-Day. Here's What Actually Stopped It.

8 minutes read
Laurentius Judhianto
Laurentius JudhiantoFounder, Platform Engineer
We Survived StyleSmuggler, a Magento Zero-Day. Here's What Actually Stopped It.

StyleSmuggler ran attacker code on Magento stores with no login and no patch, and was fired at stores we operate before a fix existed. Nothing got in. The layer that stopped it was built for scrapers.

In September 2026, Sansec disclosed StyleSmuggler: a flaw that let an attacker run their own code on a Magento or Adobe Commerce store without logging in. No patch existed. It worked on fully patched stores.

That last part is the uncomfortable bit. The standard advice — stay patched — is good advice, and it bought nothing here. A zero-day is by definition the attack your patches don't know about yet.

Every store we operate was on an affected version. A real attacker fired it at several of them over two nights.

Nothing was compromised. This post is about which defence stopped it — because it wasn't the one most people would point to, and that's the whole lesson.

The attack

Two stages. Stage one abused a URL parameter to plant attacker-controlled content in a file on the server. Stage two visited a second address to make the server run it.

Here's what it looked like in our logs, with the store and addresses removed. First the probe:

23:50:17  GET  /graphql?styles[first]=../var/log/system.log
               &styles[generatorClass]=Aws\S3\S3Client
               &styles[second]=Magento\Framework\DataObject ...

One second later, from a different address, the payload:

23:50:18  POST /paypal/transparent/response/?<?=eval(base64_decode('…'))
          -> 403

Nine requests in twelve seconds — six probes, three payloads, interleaved. The probing and the payload came from separate addresses — a small operation, not a lone script.

The planted code was well made. It expired after 180 seconds, required a secret password in the request, and deleted itself when done. Had it run once, it would have erased the evidence on the way out.

How we found out

It started with a question from the team: are we vulnerable to this? The honest answer was yes, every store, so we went looking for signs it had already been used.

The first sweep came back clean. It was also looking in the wrong directory. Nothing found is not the same as nothing there — a lesson we relearned on the spot, and now every scan we run has to report how many files it actually examined.

The second sweep found the requests above. Two stores that night, a third the next. One of the addresses involved sat a single digit away from a genuine customer's, who was busy loading product images on a Windows laptop. We checked before we accused anyone. Worth doing.

What stopped it: the anti-bot layer

In front of every store we run sits an anti-bot layer. Its everyday job is keeping scrapers, price-crawlers and junk automation away from the shop. It doesn't recognise attacks. It asks one question: does this look like a real person in a real browser?

It answers that by weighing many small, independent signals — how the visitor arrived, what the client says it is, how the connection itself is negotiated at the protocol level (which is hard to fake), how the visitor moves through the site. Each signal nudges a score. A low score passes. A middling score gets a challenge that a real browser solves invisibly and a script generally can't. A high score is refused outright.

No single signal decides. That's deliberate: any one of them can be spoofed, and spoofing all of them convincingly is real work.

Stage two of the attack didn't do that work. It landed on a shopper page — the page PayPal sends a customer's browser back to after payment — in a way that looked nothing like a shopper. A real customer never arrives there like that. It was an odd request, not shopper behaviour. It scored past the cut-off and was refused.

The layer never knew this was StyleSmuggler. It never looked at the attack code in the URL. It saw automated software on a page meant for shoppers, and turned it away.

A tool built to stop scrapers stopped an attempt to run code on our server. Not because it understood the danger — because the attacker hadn't bothered to look like a customer.

Then why don't our payment providers get blocked?

Fair question. Payment providers, carriers and stock systems don't look like browsers either.

They pass because they use different doors. Legitimate software connects to a store through known channels, and those channels have checks of their own, built for software rather than shoppers. A stock system on one of our stores sends hundreds of requests a day and every one passes.

The attacker used the wrong door. Stage two went to a page PayPal redirects shoppers to — a page for people, not a channel for software. That choice is what exposed them.

It was a POST, and a POST is easy to mistake for an API call. It isn't one. Browsers post constantly — every login, every add-to-cart, every checkout step is a browser posting to a page. What decides how a request is judged is where it goes, not the verb it uses. That page is for people, so the request was held to what a person's browser does — and it did none of it.

Stage one went through a legitimate channel and was stopped by Magento itself: the malformed request hit an error before reaching the vulnerable code. We proved this by checking the responses — the attacker asked for two different files and got back identical bytes. Nothing was read.

Two layers. Two stages. Neither knew what it was refusing. That is what layered security is for. It is not bulletproof, and we don't pretend it is: stage one was stopped by Magento tripping over a malformed request rather than by anything we built, and a more careful attacker would get closer to the line than this one did. Holding the line once is not the goal. Holding it against the next attempt is — and that is what the changes below are for.

Making sure nothing got in

A refused request is reassuring. It isn't proof. So we swept every store against the indicators Sansec published: the poisoned report files the exploit leaves behind, the hidden temporary files it drops, the disguised background process it starts, the scheduled task it installs to survive a reboot, and connections to the attacker's download server.

All clear, on every store, with file counts to prove each scan looked somewhere real. No code of theirs ever ran.

What we changed

The instinct after an attack like this is to write a rule matching its fingerprint. Done before lunch. Very satisfying. Also wrong.

Matching known patterns cannot catch what nobody has seen yet, and a fingerprint stops working the moment someone disguises the attack slightly. So we built something that asks a different question — not is this a known attack? but is this something a legitimate client would ever send?

We measured before enforcing: thirty days, four live stores, thousands of real requests. Zero legitimate matches. That zero is why we block rather than just log.

It went live during the attack — staging first, then the two stores that had been hit, then the rest, watching each one before moving on. The attacker kept going for four hours, from addresses in three countries. The final rounds were refused in full — 45 of 45 — before reaching the shop. It has since blocked hundreds of unrelated attacks a day, including a different version of StyleSmuggler the very next night.

How we secure the stores we run

Nothing in this story was one product doing one job. It was layers — each with a single question to answer, and none of them trusted to be perfect. This is how every store on our platform is built.

The edge. Every store sits behind OpenResty — NGINX with a programmable brain — and nothing reaches Magento without passing through it. This is where the anti-bot lives: the bouncer that scores each visitor on how much it behaves like a real shopper and turns away the automated tools that don't. It is also where abusive traffic is slowed down, where a suspicious visitor is handed a puzzle only a real browser can solve, and where an address that keeps misbehaving is locked out. This is the layer that stopped stage two — without knowing what it was stopping.

The firewall. Behind the bouncer, every request — including those on the channels software uses — is inspected for what it carries. This is where the improvement from this incident lives: rules that describe what a legitimate request looks like instead of listing known attacks, so the next zero-day in this family is refused on shape, not on a name.

The application. Magento itself — kept current, hardened, and run in containers with the least access it needs, so that even a request that gets through has less it can do. This is the layer that refused stage one.

Scanning. A refused request is not proof. Every store is swept for the fingerprints an attack leaves behind — poisoned files, dropped programs, hidden processes, scheduled tasks, connections to attacker servers — and everything uploaded or stored is scanned for malware. That sweep is how we could say "nothing got in", and mean it.

Memory. Every store ships its logs to a central place the store itself cannot touch. When one of the attacked stores had already rotated away its own logs, we reconstructed the entire attack — to the second — from the copy held elsewhere. You cannot defend what you cannot see afterwards.

Routine. None of this is trusted to keep existing on its own. A regular sweep checks that every layer is present, loaded and doing its job on every store — because a rule that quietly vanished looks exactly like a rule that is working, right up until it matters.

That is the design. The bouncer catches what the firewall can't name; the firewall catches what the bouncer can't see; the application refuses what both miss; the scan proves it; the logs remember. One layer failing is a bad day. All of them failing at once is what an attacker needs — and that is what we build against.

Store identities and defence internals are deliberately omitted. Credit to Sansec for the disclosure and indicators.

StoreFrame runs and secures Magento on your own cloud — an OpenResty edge with anti-bot and firewall in front of every store, hardened containers, continuous scanning, central logs, and a human plus AI watching it. The layers above are not an upgrade; they are the platform.

See how StoreFrame secures Magento infrastructure
Laurentius Judhianto
Laurentius JudhiantoFounder, Platform Engineer

A 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.

View More
Why We Migrated All Our Customers to Mage-OS. What Is Mage-OS Anyway, Compared to Magento 2? Feature Image
5 min read
LJ
Laurentius JudhiantoFounder, Platform Engineer

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.

Self-Hosted Proof of Work with ALTCHA: A Turnstile Alternative for Magento Feature Image
8 min read
LJ
Laurentius JudhiantoFounder, Platform Engineer

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.

How to Build a Bot Score: 11 Signals That Separate Scrapers from Shoppers Feature Image
6 min read
LJ
Laurentius JudhiantoFounder, Platform Engineer

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.

How to Spot a Fake Chrome: JA4 and HTTP/2 Fingerprinting Explained Feature Image
5 min read
LJ
Laurentius JudhiantoFounder, Platform Engineer

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.

OpenResty vs NGINX, Caddy and Traefik: Choosing The Edge For Magento Feature Image
8 min read
LJ
Laurentius JudhiantoFounder, Platform Engineer

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.

Magento Anti-Bot and Anti-Scraping: A Layered Defence Guide for Self-Hosted Stores Feature Image
11 min read
LJ
Laurentius JudhiantoFounder, Platform Engineer

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.

The Perfect Agentic “Playground” for Magento Operators.

Bring your own cloud key and Claude subscription. We ship the containerized Magento platform — you keep the keys, the data, and the control.

StoreFrame management hub Console view with a Claude Code session answering questions about a Magento store