← Back to Rubens Design

Magento 2 Security Case Study

Magento 2 Security Sweep: Webshell Upload Contained Before It Became a Breach

Client: UK Magento retailer · Platform: Magento 2.4.8-p5 · Area: Server security, media uploads, guest cart abuse

Malware sweepNginx hardeningQuote cleanupFilesystem lockdown

Summary

A routine Magento 2/server security sweep uncovered malicious executable files inside pub/media/custom_options/quote. The files presented as tiny GIF images, but contained PHP webshell behaviour designed to execute attacker-supplied code and copy uploaded files onto the server.

The important part: public execution was blocked before the payloads could be used. The sweep then removed the payloads, cleaned poisoned cart/quote records from the database, hardened Nginx, and locked the abused upload directory so the attack could no longer land files there.

What was found

The first sweep found PHP files in Magento runtime/media locations where PHP should not exist:

find pub/media var generated -type f -name "*.php" -print

pub/media/custom_options/quote/l/1/l1dygcly.php
pub/media/custom_options/quote/g/e/get.php
pub/media/custom_options/quote/s/t/static.php

Further checks showed the same pattern repeating through guest quote records. The payloads were being attached to basket data as if they were product custom option file uploads.

What the files were designed to do

The files used image headers such as GIF89a or PNG-like content to look harmless, then embedded PHP. The behaviour included:

Plain English: this was a grappling hook. If executable access had been allowed, it could have become a backdoor.

Containment

Every discovered payload URL was tested publicly and confirmed as blocked:

curl -I https://example.co.uk/media/custom_options/quote/1/7/173index.php

HTTP/2 403

Nginx directives were added to block executable extensions in public runtime areas and deny access to abused media paths:

location ~* ^/(media|static|var|generated)/.*\.(php|phtml|phar|pht|php3|php4|php5|php7|php8|inc)$ {
    return 403;
}

location ^~ /media/custom_options/ {
    deny all;
    return 403;
}

Database cleanup

The malicious uploads were also referenced in Magento quote data. Those poisoned guest quote records were identified and removed from the quote tables so abandoned carts could not retain references to the payloads.

SELECT COUNT(*) AS bad_quote_refs
FROM quote_item_option
WHERE value LIKE '%.php%'
   OR value LIKE '%.phtml%'
   OR value LIKE '%.phar%'
   OR value LIKE '%.pht%'
   OR value LIKE '%.php7%'
   OR value LIKE '%.php8%'
   OR value LIKE '%.inc%';

Final prevention

The Magento store did not use product custom option file uploads, so the abused directory was moved to quarantine, recreated empty, and made non-writable:

mv pub/media/custom_options /quarantine/custom-options-full-2026-06-08/custom_options
mkdir -p pub/media/custom_options/quote
chmod 555 pub/media/custom_options
chmod 555 pub/media/custom_options/quote

The write test failed exactly as required:

echo "test" > pub/media/custom_options/quote/write-test.txt
Permission denied

Result

Executable media files
Removed and quarantined
Public payload access
Blocked with HTTP 403
Poisoned quote refs
Cleaned to zero
Abused upload destination
Locked read-only

Business value

This is the kind of incident that can stay invisible until it becomes expensive. A successful webshell can lead to stolen customer data, payment trust issues, SEO spam, blacklisting, emergency rebuilds, lost trading time and reputational damage.

The fix was not just “delete a few dodgy files”. It required understanding Magento quote storage, media permissions, Nginx routing, Cloudflare behaviour, and safe production cleanup.

Takeaway

Security is not one magic module. It is layers: find the payload, block execution, clean the database, harden the server, and remove unused attack surfaces. In this case, the best final fix was simple and old-school: if the store does not use product custom option file uploads, the directory should not be writable. Brick up the door nobody needs. 🧱

Talk to Rubens Design Read the admin save case study

Was this case study useful?