MAGENTO OPERATIONS

StyleSmuggler: What the Magento Zero-Day Means for Your Store, and How to Check for It

StyleSmuggler: What the Magento Zero-Day Means for Your Store, and How to Check for It

StyleSmuggler is an unauthenticated remote code execution flaw. Sansec says it affects all current Magento Open Source and Adobe Commerce release lines; its own testing confirmed it on 2.4.7, 2.4.8 and 2.4.9, and the first known victim was compromised while fully up to date on the 2.4.6 line. Adobe has not yet confirmed which versions are affected. An attacker needs no account. They upload a booby-trapped file, send one crafted request to your GraphQL endpoint, then force a payment to fail so Magento's own failed-payment email runs their code. This post covers how the chain works, how to check whether you've been hit, what to do today, and how NoMoreSpam Pro 2.11.54 and later breaks the chain at five separate points.

What is StyleSmuggler?

StyleSmuggler is the name Sansec gave to a Magento zero-day they disclosed on 5 September 2026 and have updated since as new variants appeared. It's an object-injection bug: attacker-supplied text is turned into live PHP objects inside core Magento code that every version shares, which is why patch level makes no difference. Sansec reported active exploitation before the disclosure.

Two things make it serious. It needs no login of any kind, not admin, not customer. And the outcome is code execution on your server, not a leaked record or a defaced page. Sansec reports Adobe's next scheduled security release is 8 September 2026, and whether it closes this specific hole is not confirmed. Watch Adobe's Magento security bulletins for the authoritative patch, and treat everything below as what you do in the meantime and keep doing after.

How does the StyleSmuggler attack work?

The attack is a three-step chain, and each step bends an ordinary Magento feature. You don't need exploit code to follow it.

  1. PHP gets planted somewhere Magento will read it back. On stores that let shoppers upload a file for a custom option, that's a GIF or PNG that is also valid PHP, landing under pub/media/custom_options/quote/ like any other upload. Other variants skip the upload and instead poison a log or crash report: a request crafted so that Magento writes <?php into var/log/system.log or var/report/api/ a moment before the next step.
  2. One request to /graphql smuggles the instructions. The payload doesn't travel in the GraphQL body where you'd look for it. It sits in the URL as bracketed styles[...] parameters naming a Magento class and the uploaded file, next to a template directive. Real GraphQL clients never send parameters shaped like that.
  3. A failed payment pulls the trigger. The same request forces a card decline. Magento answers with its "Payment Transaction Failed Reminder" email, the email template runs the smuggled directive, an admin grid block hands the class name to a factory that builds whatever it's told to, and that class is one of Magento's setup-time code scanners, which includes the planted file. The result is a process disguised as [kworker/u:8:0] or fc-cache running as your Magento user, with a cron entry to bring it back.

Every piece of that is stock Magento: cart uploads, GraphQL, transactional email, the admin grid, the setup-time code scanner. Nothing here depends on a third-party module.

How do I check whether my Magento store has been hit?

Look for these on the server itself, not just in Magento. The malware installs outside the document root, so a scan of pub/ alone can come back clean on an infected box.

  • A process named [kworker/u:8:0] or fc-cache owned by your web or Magento user. Real kernel workers run as root, and a real font cache rebuild doesn't sit resident.
  • A cron entry for that user running every five minutes and pointing at ~/.local/share/.gvfsd/gvfsd-user or straight at /tmp/.kw_*, or one at 13 and 43 minutes past the hour running ~/.cache/fontconfig/fc-cache. The implant writes these directly to the cron spool file, so they restore themselves and leave nothing in syslog.
  • Files under ~/.local/share/.gvfsd/, ~/.cache/fontconfig/, /tmp/.kw_*, /tmp/.gvfsd-* or /tmp/.gvfsd_*.lock.
  • Files in var/report/ or var/log/ containing a PHP open tag, or the trigger header shape X_TRACE_ followed by ten to twelve hex characters. The hex value changes per request, so match the shape, not a value.
  • Uploads under pub/media/custom_options/quote/ that contain PHP, whatever their extension says.
  • Requests in your access logs matching styles[, styles%5B, generatorClass, with_resolved or cdnflare. On cPanel hosts these can be absent from the per-site access log and present only in the ModSecurity audit log, so check both.
  • A burst of "Payment Transaction Failed Reminder" emails your normal decline rate doesn't explain.

One hit is enough to treat the server as compromised. Stop and escalate to your host or a Magento security specialist before you change anything, so the evidence survives.

What should I do right now?

Block the entry point first, then check for an existing foothold. If you find one, preserve the evidence and rebuild rather than cleaning in place. Blocking does not undo a compromise that has already happened.

  1. Block or filter /graphql at the edge. If your storefront is Luma or Porto and you have no headless front end, returning 403 for the whole endpoint in nginx, Apache or your CDN costs you little, but test checkout before you leave it in place: some Luma setups do call GraphQL from the checkout, our own child theme's Braintree address modal among them. Hyva themes use GraphQL for several widgets, so there filter the request shape instead: reject any URL carrying styles[ or a {{ directive, and their percent-encoded forms styles%5B and %7B%7B. Edge rules usually see the raw, unnormalised request target, so a literal-only match is bypassed by encoding a single bracket.
  2. Turn guest checkout off only if you can accept the conversion hit. It blocks placing an order as a guest, not adding to a guest cart and not the file upload, so an attacker who registers an account reaches the same payment step with a few extra requests. The edge filter in step 1 is the mitigation that holds.
  3. Run the checks above, and a malware scan that covers the whole home directory rather than only pub/. Sansec's eComscan already detects this implant if you'd rather not hand-roll the checks.
  4. Harden the server with two settings that work whatever the entry point. Add proc_open, popen, exec, shell_exec, system and passthru to PHP's disable_functions for the web pool, and mount /tmp, /var/tmp and /dev/shm with noexec; on shared hosting, ask your host for the mounts. Try disable_functions on staging first, because admin features and third-party modules that shell out can break on it. This stops the binary implant this chain drops and raises the cost of the next one, but it does not stop PHP code from running. A card skimmer or a database exfiltration payload never launches a process at all. Treat it as damage limitation, not containment.
  5. If anything matches, preserve the evidence before you touch it. Copy the crontab, a process list, the implant files and the relevant access and ModSecurity logs somewhere off the server, and take a full snapshot if your host can make one. Cleaning first destroys the only record of how they got in and what they reached.
  6. Rebuild from a known-good deploy. On a confirmed compromise you can't list everything an attacker left behind, so a fresh deploy on a clean box or hosting account is the only result you can trust. Restore code from version control, and treat pub/media as untrusted until you've scanned it for PHP. The database comes with you, so check it before it does: remove admin users and integrations you didn't create, and look for injected scripts in CMS blocks and the design configuration head. Rotate every credential in app/etc/env.php, flush the Redis session database, and invalidate admin sessions and API tokens before the new box takes traffic.
  7. If you cannot rebuild, clean in this order and treat the store as still suspect afterwards: remove the cron entries, kill the process, delete the .gvfsd, fontconfig and .kw_ files, remove the injected reports and logs, quarantine the PHP-bearing uploads, then clean the crontab a second time and check it again after a full five-minute cycle. Check the database, rotate credentials and invalidate sessions as above.
  8. Apply Adobe's patch the day it lands, and keep the edge rules in place until you've confirmed it covers this chain. Our guide to securing Magento 2 covers the standing hardening that makes the next chain harder too.

How does NoMoreSpam Pro protect against StyleSmuggler?

NoMoreSpam Pro 2.11.54 and later cuts the chain at five separate points, all on by default, so a payload that slips past one layer still has nowhere to go. You'll find the control under Stores > Configuration > Moogento > NoMoreSpam Pro > Endpoint: Object-Injection Hardening, as a single level selector, and the NoMoreSpam Pro documentation covers the rest of the module's settings.

Layer What it stops
URL screening on every endpoint Rejects requests carrying bracketed styles[...] parameters on GraphQL, the storefront, REST and the admin. GraphQL additionally rejects any bracketed URL parameter, since real GraphQL clients send everything in the JSON body.
Template directive rejection At the Strict level, rejects any request whose URL or GraphQL payload contains a {{...}} directive, in plain, percent-encoded or JSON-escaped form. Valid GraphQL never contains one.
Email and widget block directive guard The {{block}} directive refuses to build admin-area block classes or anything that isn't a real block, whatever spelling or slash style the class name uses.
Grid factory and code scanner locks The admin grid's row-link factory refuses to build anything that isn't a row-link generator, and the five setup-time code scanners and readers that can include a file refuse to run outside the command line. That last lock is the same sink guard the community source patches apply, delivered as a module so it survives a Magento upgrade.
Template path and crash report hardening Block templates can't be loaded from stream wrappers or null-byte paths, and Web API crash reports have every PHP open tag broken before they're written, so a report can't be turned into an executable file.

The level is global on purpose. A Web API caller can pick which store a request runs under, so a per-store switch would have been a way to turn the guards off. Standard gives you every layer except the directive rejection, which is the one to drop to if a bespoke client of yours genuinely sends {{ in a request. Strict is the default and is what we recommend.

Hyva stores are fine on Strict. Hyva's product slider and recently-viewed widget call GraphQL over GET with the query on the URL, and neither shape trips the guards. We've verified both against live Hyva and Luma stores and pinned them as regression tests.

A few plain limits. This is a virtual patch that buys time and adds depth; it is not Adobe's fix, so apply that when it ships. If you're on a release older than 2.11.54, update first; nothing before it has these guards. It can't clean a server that was hit before you installed it, so run the checks above regardless. And blocked requests are logged at warning level in var/log/moogento_nomorespampro.log with the client IP and which marker matched, but never the full URL, so the log stays useful without collecting whatever else was in the request.

FAQ

Does StyleSmuggler affect a fully patched Magento 2.4.9?

Yes. Sansec reproduced the exploit on 2.4.7, 2.4.8 and 2.4.9, and the first known victim was fully up to date on the 2.4.6 line. The flaw sits in core code the current releases share, so version alone tells you nothing about whether you're safe. Adobe has not yet published an affected-versions list.

Can I just disable GraphQL?

If your storefront is Luma or Porto with no headless or PWA front end, mostly yes, and it's the simplest edge block. Check your own checkout first: some Luma themes call GraphQL there, including our Moogento child theme's Braintree address modal. Hyva themes and any PWA storefront use GraphQL throughout, so there you filter the request shape rather than the endpoint, or rely on a module that does.

My scanner says the store is clean. Am I safe?

Only if the scan covered the whole home directory and the crontab, not just the Magento document root. The implant lives under ~/.local/share/.gvfsd/ and /tmp, and persists through cron, so a pub/-only scan misses it entirely.

Do I still need NoMoreSpam Pro once Adobe patches this?

The five layers stay useful because they target the mechanism, not this one exploit: smuggled URL parameters, template directives in requests, and classes being built from user input. The same shapes show up in the next chain too. Apply Adobe's patch, and keep the guards on.

Thanks to Sansec for the original disclosure and research.

Recent Articles

All articles →

Get practical Magento workflow ideas.

Short notes on order handling, shipping automation, and store performance - written for teams running Magento every day.

Customer discussion

Sign in to comment

Comments are available for signed-in Moogento customers, so discussion stays useful and spam-free.