StyleSmuggler Magento 2 Zero-Day: How to check, mitigate and clean an affected store<

On September 5, 2026, Sansec disclosed StyleSmuggler, a Magento Open Source and Adobe Commerce zero-day vulnerability that allows unauthenticated remote code execution.

Attacks started on September 4 and exploitation is active. Sansec reproduced the complete attack chain on Magento 2.4.7, 2.4.8 and 2.4.9. Their first confirmed victim was running Magento 2.4.6-p15 with the recent July and August security patches already installed. Check more detailed information at Sansec site.

The attack works in two stages. Malicious PHP is first injected into Magento-controlled data such as report or log files. Magento is then made to process that data through its template system and execute the injected code.

At the time of writing, there is no official Adobe patch for StyleSmuggler. Adobe's next scheduled security release is September 8, but it is not yet confirmed whether it will include a fix.

If you manage a Magento server, there are three separate jobs:

  • Check whether the server is already compromised.
  • Prevent another StyleSmuggler request from reaching the vulnerable code.
  • If compromised, preserve evidence, remove the malware and audit everything the Magento system user could access.

Blocking GraphQL does not clean an already compromised server.

1. Check whether the Magento server is already compromised

Start with read-only checks. Do not immediately reboot the machine, delete files or redeploy Magento.

Check for fake kernel worker processes

One of the clearest indicators observed in affected systems is a process disguised as:

[kworker/u:8:0]

Run:

ps -eo pid,user,rss,args --no-headers | awk '$4 ~ /^\[/ && $2 != "root"'

A real Linux kernel worker runs as root. A process with a kernel-looking name such as [kworker/u:8:0] running as your Magento system user is highly suspicious.

A broader check is:

ps -eo pid,user,comm,args | grep -i kworker

Do not treat every kworker process as malware. Normal Linux servers have many legitimate kernel workers. What matters is the owner, PID, memory usage and executable behind the process.

Sansec specifically lists [kworker/u:8:0] running as part of the StyleSmuggler infection chain.

Check cron persistence

The malware observed in this campaign creates persistence using cron.

Check your current user's crontab:

crontab -l

Then search specifically for known patterns:

crontab -l 2>/dev/null | grep -Ei 'gvfsd|\.kw_'

A known malicious entry looks similar to:

*/5 * * * * exec /home/USER/.local/share/.gvfsd/gvfsd-user

Sansec observed gvfsd-user being restarted every five minutes.

Check known dropped-file locations

Run:

ls -la ~/.local/share/.gvfsd/ /tmp/.kw_* /tmp/.gvfsd-* 2>/dev/null

Known locations include:

~/.local/share/.gvfsd/gvfsd-user
~/.local/share/.gvfsd/.gvfsd_<random>.lock
/tmp/.kw_<random>

An important detail here is that the malware is installed outside the Magento document root.

A malware scan limited to /pub, /public_html or the Magento project directory can therefore report the store as clean while the implant continues to run from the user's home directory.

Check Magento report and log files

Observed variants used Magento's own files during the first stage of exploitation.

Check both var/report and var/log:

grep -rl 'X_TRACE_\|<?php' var/report/ var/log/ 2>/dev/null

Do not check only var/report. Different observed variants have written payloads into different locations.

Check web server access logs

Adjust the path to the access log for your server:

grep -acE 'styles(\[|%5B)|generatorClass|with_resolved|cdnflare' /path/to/access.log

You can also inspect matching requests:

grep -aE 'styles(\[|%5B)|generatorClass|with_resolved|cdnflare' /path/to/access.log

Sansec lists malicious requests to /graphql with styles[...] parameters among the observed indicators.

Unexpected bursts of Magento's Payment Transaction Failed Reminder emails are another useful signal. The victim does not have to open the email—the malicious code executes while Magento renders it.

2. If you find a suspicious process, inspect it before killing it

Do not immediately run kill -9.

First record what the process is doing.

Assume the suspicious PID is 7908:

PID=7908

Inspect it:

ps -fp "$PID"

Check the executable:

ls -l /proc/$PID/exe
readlink -f /proc/$PID/exe

Check its current working directory:

ls -l /proc/$PID/cwd

Check files opened by the process:

lsof -nP -p "$PID"

Check its network connections:

ss -tpn | grep "pid=$PID,"

or:

lsof -nP -i -a -p "$PID"

Don't look only for external connections

This became particularly important during our own investigation.

On one affected server the suspicious kworker process did not expose an obvious external command-and-control connection. Instead, the process had several established connections to the Magento server's own Redis instance.

We identified the Redis endpoint with:

lsof -nP -iTCP:21113

The same Redis process was listening on that port while the suspicious kworker process was connected to it.

You can also identify what is listening on a suspicious port with:

ss -ltnp | grep ':21113'

Replace 21113 with the port found in your connection output.

This matters because an infected server may show no suspicious outbound connection at all. The malware may communicate through services already available to the Magento account, including Redis.

3. Preserve evidence before cleaning the server

If the previous checks indicate compromise, save the state before changing it.

Create a private incident directory:

Q=~/incident-$(date +%Y%m%d-%H%M)
mkdir -p "$Q"
chmod 700 "$Q"

Save the running process list:

ps -eo pid,ppid,user,lstart,rss,args > "$Q/processes.txt"

Save the suspicious process information:

ls -l /proc/$PID/exe /proc/$PID/cwd > "$Q/proc-links.txt" 2>&1
ls -l /proc/$PID/fd/ > "$Q/proc-fds.txt" 2>&1
cat /proc/$PID/status > "$Q/proc-status.txt" 2>&1

If the executable has already been deleted from disk, /proc/$PID/exe may still contain the running binary.

Copy it before killing the process:

cp /proc/$PID/exe "$Q/implant.bin" 2>/dev/null

Hash it:

sha256sum "$Q/implant.bin"

Save cron:

crontab -l > "$Q/crontab.txt" 2>&1

Save network connections:

(ss -tanp 2>/dev/null || netstat -tanp 2>/dev/null) > "$Q/connections.txt"

Save relevant Magento and web server logs before modifying them:

cp -a var/log "$Q/magento-log"
cp -a var/report "$Q/magento-report"
cp -p /path/to/access.log "$Q/access.log"

Do this before running Composer or redeploying Magento. A deployment can replace modified files and timestamps that would otherwise help establish what happened.

Also avoid rebooting at this stage. /proc/<pid>/exe can be the only remaining copy of a malware binary that deleted its original file after starting.

4. Block new StyleSmuggler attacks

Once evidence is preserved, block the attack path while continuing the investigation.

Before disabling GraphQL, verify whether the store actually uses it.

Headless and PWA storefronts depend on it. Some Magento themes and third-party integrations may also use GraphQL.

Check recent traffic:

grep -c '"POST /graphql' /path/to/access.log

A zero does not absolutely prove GraphQL is unused, but it is a useful first check.

Option 1: Cloudflare

If the store uses Cloudflare, an edge rule is usually the quickest option.

Create a WAF/custom rule matching:

http.request.uri.path eq "/graphql"

and set the action to:

Block

If your setup also accepts a trailing slash, block both:

/graphql
/graphql/

Blocking at Cloudflare has the advantage that malicious GraphQL requests never reach the Magento server.

Option 2: Nginx

For a Magento installation that does not need GraphQL:

location ^~ /graphql {
return 403;
}

Validate the configuration before reloading:

nginx -t

Verify:

curl -I https://YOURSTORE/graphql

You should receive 403.

Option 3: Apache

For Apache with rewrite rules:

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/graphql/?$ [NC]
RewriteRule ^ - [F,L]

Verify afterwards:

curl -I https://YOURSTORE/graphql

Again, the expected result is 403.

You may also see advice to disable GraphQL using Magento's module system.

First inspect GraphQL modules:

bin/magento module:status | grep -i GraphQl

The obvious command would be:

bin/magento module:disable Magento_GraphQl

We consider this the least recommended approach.

Magento_GraphQl is a base Magento module and many GraphQL modules depend on it. Depending on the Magento version and installed extensions, Magento may refuse to disable it because of dependencies.

Do not solve that by blindly running:

bin/magento module:disable Magento_GraphQl --force

on a production store.

For emergency containment, blocking /graphql at Cloudflare, Nginx or Apache is simpler, easier to reverse and does not modify Magento's module dependency graph.

5. Apply the community StyleSmuggler mitigation

Blocking /graphql is useful emergency containment, but there is also a community source patch maintained by DISREXM

This is not an Adobe patch.

The mitigation changes three Magento DI code scanners so they can only execute from PHP CLI. Normal setup:di:compile execution happens through CLI, while web execution through the vulnerable path is blocked.

The patch has been tested by its authors against Magento 2.4.6 through 2.4.9. However, it was produced quickly during an active incident and has not undergone the same review process as an Adobe security patch.

Test it before production deployment.

For an already running server:

cd /path/to/magento
patch -p1 --forward \
< patches/magento/magento2-base/stylesmuggler-di-scanner-guard.patch

Then compile:

bin/magento setup:di:compile

Verify the patch:

grep -c 'StyleSmuggler mitigation' \
setup/src/Magento/Setup/Module/Di/Code/Scanner/ArrayScanner.php

Then check storefront, checkout and Admin normally.

For Composer-based deployments, add the patch through composer-patches so that a future composer install does not silently replace the modified Magento source.

Remove or review the community workaround once Adobe releases an official fix.

6. Clean an infected server

Mitigation stops another attack. It does not remove the existing implant.

The cleanup order matters.

6.1 Remove cron persistence first

Edit the user's crontab:

crontab -e

Remove suspicious entries referring to:

gvfsd
.kw_

Verify:

crontab -l | grep -Ei 'gvfsd|\.kw_'

The command should return nothing.

Do this before killing the malware process. Otherwise cron can simply start another copy.

6.2 Kill the malicious process

Once persistence has been removed:

kill "$PID"

Check:

ps -p "$PID"

If the process refuses to exit:

kill -9 "$PID"

Then repeat the non-root kernel-process check:

ps -eo pid,user,rss,args --no-headers | awk '$4 ~ /^\[/ && $2 != "root"'

It should return nothing suspicious.

6.3 Remove known malware files

After preserving copies:

rm -rf ~/.local/share/.gvfsd/
rm -f /tmp/.kw_* /tmp/.gvfsd-* 2>/dev/null

Check again:

ls -la ~/.local/share/.gvfsd/ /tmp/.kw_* /tmp/.gvfsd-* 2>/dev/null

6.4 Remove poisoned Magento files

Find suspicious files again:

grep -rl 'X_TRACE_\|<?php' var/report/ var/log/ 2>/dev/null

Do not simply delete everything before preserving evidence.

Once copies have been saved, remove affected report files and clean injected log content as appropriate for the installation.

7. Check for other persistence and backdoors

Removing gvfsd-user does not prove the server is clean.

The attacker had code execution as the Magento system user and could write anywhere that user had permission.

Check other cron mechanisms

crontab -l 2>/dev/null
sudo crontab -l 2>/dev/null

Check system cron:

ls -la /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/ \
/etc/cron.weekly/ /etc/cron.monthly/ 2>/dev/null
cat /etc/crontab 2>/dev/null

Check timers:

systemctl list-timers --all 2>/dev/null
systemctl --user list-timers --all 2>/dev/null

Check user systemd units:

ls -la ~/.config/systemd/user/ 2>/dev/null

Check SSH access

Inspect:

cat ~/.ssh/authorized_keys

Every key should be accounted for.

Also check timestamps:

ls -la ~/.ssh/

Check shell startup files

Search for obvious downloaders and persistence:

grep -nE 'curl|wget|base64|/tmp/\.|gvfsd|kworker' \
~/.bashrc ~/.bash_profile ~/.profile ~/.zshrc ~/.bash_login 2>/dev/null

Check PHP persistence

Look for PHP configuration that automatically executes another file:

grep -rn 'auto_prepend_file\|auto_append_file' \
.user.ini .htaccess /etc/php*/ 2>/dev/null

Look for PHP files uploaded into media:

find pub/media -type f -name '*.ph*' 2>/dev/null

And recently modified PHP files:

find app vendor pub \
-type f -name '*.php' -newermt '30 days ago' 2>/dev/null

8. Compare the Magento filesystem with known-good code

If the project is stored in Git:

git status --short

Then:

git diff --stat

Find untracked PHP/PHTML files:

git ls-files --others --exclude-standard \
| grep -E '\.(php|phtml)$'

Anything unexpected in:

app/code
vendor
pub
setup

needs investigation.

Do not assume that reinstalling vendor/ alone solves the problem. The malware process runs as the Unix site user and is not limited to Magento PHP code.

9. Check Magento database content

The attacker could access the same database credentials available to Magento.

Check Admin users:

SELECT
user_id,
username,
email,
created,
logdate,
is_active
FROM admin_user
ORDER BY created DESC;

Look for unknown or recently created accounts.

Check integrations:

SELECT
integration_id,
name,
created_at,
status
FROM integration;

Check recent OAuth tokens:

SELECT *
FROM oauth_token
ORDER BY created_at DESC
LIMIT 20;

Check configuration for obvious JavaScript injection:

SELECT
config_id,
scope,
scope_id,
path,
LEFT(value, 300)
FROM core_config_data
WHERE value LIKE '%<script%'
OR value LIKE '%eval(%'
OR value LIKE '%atob(%'
OR value LIKE '%fromCharCode%';

Check recently modified CMS blocks:

SELECT identifier, update_time
FROM cms_block
WHERE update_time > NOW() - INTERVAL 30 DAY
ORDER BY update_time DESC;

And CMS pages:

SELECT identifier, update_time
FROM cms_page
WHERE update_time > NOW() - INTERVAL 30 DAY
ORDER BY update_time DESC;

These queries are not StyleSmuggler signatures. They are simply useful places to look for persistence or injected storefront JavaScript after a server compromise.

10. Check Redis and invalidate sessions

Redis deserves special attention in this incident.

First check Magento's Redis configuration:

grep -nA40 "'cache'" app/etc/env.php
grep -nA30 "'session'" app/etc/env.php

Identify:

  • Redis host
  • port or socket
  • cache database
  • page-cache database
  • session database

Then inspect connections:

lsof -nP -iTCP:<REDIS_PORT>

or:

ss -tnp | grep ':<REDIS_PORT>'

If you found a suspicious PID earlier:

ss -tpn | grep "pid=$PID,"

If Redis is used for customer/admin sessions, invalidate the session database after containment.

For example:

redis-cli -h <HOST> -p <PORT> -n <SESSION_DB> FLUSHDB

Use FLUSHDB against the specific Magento database rather than blindly running:

redis-cli FLUSHALL

especially on shared hosting or a Redis instance used by multiple applications.

Flushing the Magento session database logs out customers and administrators. After a server compromise, that is desirable because existing authenticated sessions must be treated as potentially exposed.

11. Rotate credentials

Once the malware and persistence have been removed, assume secrets readable by the Magento Unix user may have been exposed.

At minimum review and rotate:

  • Magento Admin passwords
  • database credentials
  • Magento integration/API tokens
  • OAuth tokens
  • SSH keys accessible to the site user
  • deployment keys
  • payment-provider credentials
  • SMTP credentials
  • ERP, CRM and fulfillment API credentials
  • CDN and third-party service credentials
  • secrets stored in deployment configuration

Inspect app/etc/env.php carefully.

Do not simply replace Magento's crypt/key value manually on a production store. Magento uses this key to encrypt stored configuration values. If the key is considered exposed, encrypted secrets need a controlled rotation/re-encryption procedure.

Also invalidate active Admin sessions after changing Admin credentials.

Credentials should be rotated after containment. Changing passwords while the attacker still has active execution on the server can simply expose the new credentials as well.

12. Verify that the server stays clean

Repeat the original checks.

Processes

ps -eo pid,user,rss,args --no-headers | awk '$4 ~ /^\[/ && $2 != "root"'

Cron

crontab -l | grep -Ei 'gvfsd|\.kw_'

Malware files

ls -la ~/.local/share/.gvfsd/ /tmp/.kw_* /tmp/.gvfsd-* 2>/dev/null

Magento reports and logs

grep -rl 'X_TRACE_\|<?php' var/report/ var/log/ 2>/dev/null

Network connections

lsof -nP -i -a -u "$USER" 2>/dev/null

Look specifically for unexpected long-running processes communicating with Redis or external hosts.

GraphQL

If GraphQL was disabled:

curl -sk -o /dev/null -w '%{http_code}\n' \
'https://YOURSTORE/graphql'

Expected:

403

Storefront

curl -sk -o /dev/null -w '%{http_code}\n' \
'https://YOURSTORE/'

Expected:

200

If the suspicious process or cron entry reappears, another persistence mechanism still exists.

What Magento store owners should do now

If you run Magento 2:

  1. Check the server for compromise now — processes, cron, Magento logs and access logs.
  2. Block /graphql if your store does not use it, or apply the community mitigation.
  3. If indicators are found, preserve evidence before deleting anything.
  4. Remove malware, cron persistence and any additional backdoors.
  5. Audit Magento files, database, Redis, SSH access and credentials.
  6. Rotate exposed credentials and invalidate active sessions.
  7. Run the checks again after cleanup.
  8. Install the official Adobe fix as soon as it becomes available.

The main point is simple: blocking GraphQL prevents another StyleSmuggler request, but it does not clean an already compromised Magento server.

Treat a confirmed infection as compromise of the Magento Unix account, not just as a malicious PHP file inside the Magento installation.