Sansec has traced malicious JavaScript loaders in 953 online stores, most of them running Magento, to a single unknown actor active since at least July 2025. This Magento store JavaScript malware hides in database content that file scanners skip and reveals itself only to real shoppers, so a clean scan report does not prove a clean store.
Key takeaways
- Sansec tied malicious JavaScript loaders in 953 online stores, mostly Magento, to one unknown actor active since July 2025.
- The loader sits in Magento's cms_block table, so file-based scans miss it, and its server hides the payload from scanners and bots.
- Sansec estimates 471 stores were breached via PolyShell (CVE-2026-48356) and 102 more via PolyShell or SessionReaper (CVE-2025-54236).
- A fully patched Magento 2.4.7-p10 store was compromised through a rogue admin account, so patching alone does not clear a store.
- The final payload is unknown, so infected merchants should plan for possible card-data exposure under PCI DSS 4.0.
What happened in the Magento store JavaScript malware campaign?
An unidentified group has planted JavaScript loaders in 953 online stores over roughly 15 months, according to Sansec, the Dutch e-commerce security firm. The Hacker News reported the findings on 26 October 2026 (Ravie Lakshmanan). The earliest infrastructure Sansec links to the campaign was first seen in July 2025, and a new loader domain went live this month.
Most victims run Magento (the open-source platform behind Adobe Commerce), though Sansec gives no exact share, so merchants on other platforms shouldn’t dismiss the report. Still, every technical detail in it is Magento-specific: the injection point, the entry flaws and the patch numbers.
Two questions remain open. Sansec has not named or attributed the operator, and it has not determined what the loader ultimately delivers to shoppers. On a storefront that takes payments, the plausible outcomes include card skimming, login theft and redirect fraud. That is our inference, not Sansec’s finding.
How does malware hidden in Magento CMS blocks reach shoppers?
The loader lives in Magento’s database, inside CMS blocks stored in the cms_block table. CMS blocks are reusable chunks of static content, such as a header promo, a footer notice or a homepage banner, that Magento inserts into storefront pages. Whatever HTML sits in a block renders for every visitor on every page that includes it.
Sansec has not said whether the attackers edited existing blocks or created new ones. Either works. An edited footer block reaches the whole site at once. A new block wired into a layout is less likely to be spotted by staff who only check the blocks they remember creating.
The injected snippet is small. It tells the shopper’s browser to fetch a script from an attacker-controlled server. As Sansec put it: “When you visit, that code makes your browser ask the group’s server what to do next.” That server then decides, visitor by visitor, what to send back.
Small does not mean harmless. A script pulled in through a script tag runs inside the store’s page with the same access as the store’s own code. It can read and rewrite checkout forms, swap payment fields or change page content, even though the file is hosted on someone else’s domain. The attacker never has to keep the real payload on the merchant’s server.
This placement is also why infected stores stay infected. CMS blocks are database rows, not PHP files, so a malware scan that walks the web root comparing files can pass a store that serves the loader on every page. The same blind spot applies to cms_page, which holds full CMS pages, and Sansec’s cleanup advice covers both tables.
Why do security scanners see nothing?
Scanners see nothing because the attacker’s server checks who is asking before it answers. In Sansec’s words: “The server first checks whether you are a real shopper or a security scanner, so scanners get nothing.” An external scanner, a crawler or an analyst testing the URL from a script gets an empty or harmless response, and the store’s report comes back green.
The infrastructure has rotated over time. Sansec has tracked five loader domains, first seen in July 2025, December 2025, March 2026, June 2026 and October 2026. We are not naming them here; Sansec’s own research carries the indicators. Five domains over 15 months looks like one operator refreshing infrastructure, not five separate campaigns.
The newest domain was registered on 6 October 2026 and already appears in the CMS blocks of 83 stores. That is about 8.7% of the total — a recent snapshot, not the full campaign. It sits behind Cloudflare and answers only script requests from genuine visitors of infected shops. Cloudflare’s presence says nothing about who runs it; legitimate services turn up in malicious infrastructure all the time.
One store Sansec examined switched its block to the new domain on 7 October, a day after registration. That timing suggests the operator still has access to infected stores and updates them one by one, or in bulk, from their side.
Two loader versions
- Version one fetches the external script and saves the payload in the browser’s localStorage. On later visits, the code runs from that local copy, even if the attacker’s domain has gone offline. localStorage has no expiry date; data stays until the site, the user or a browser reset clears it.
- Version two builds on the first and adds browser fingerprinting. It checks characteristics of the visitor’s browser to filter out bots and automated scanners, so only real shoppers receive the code.
The first variant creates an awkward cleanup problem. Removing the loader from your database stops new infections, but a returning customer’s browser may still hold the stored code. Taking the attacker’s domain down doesn’t fix that either.
From Keitaro to built-in filtering
Earlier waves routed visitors through Keitaro, a legitimate advertising tracker and analytics platform that can act as a traffic distribution system. Based on who the visitor appears to be, it returns a payload, a redirect or nothing at all.
When Sansec requested an older loader script as a Windows desktop visitor, the entire response was QWE=123;, which set a cookie marking the visitor for 24 hours and did nothing else. The newest domain drops Keitaro and builds the bot filtering into the loader itself, leaving the operator fewer moving parts to maintain.
Was this only an unpatched Magento problem?
No. Most of the infections Sansec could attribute trace back to known Magento flaws, but at least one fully patched store was compromised through a rogue administrator account.
The first case is the familiar one. A store on Magento 2.4.7-p1 had PolyShell webshells disguised as PNG images in pub/media/custom_options/quote/, sitting alongside the loader in a CMS block. “The store still lacks APSB26-73, Adobe’s PolyShell fix for supported release lines,” Sansec noted.
A file extension proves nothing about contents. A “.png” that contains PHP is a shell, and reviewing an upload folder by filename or thumbnail will miss it.
The second case matters more for owners who think they are covered. A store on Magento 2.4.7-p10 with no missing core patches was still hit. The attackers had added an administrator account and used it to inject the code, the same way a marketing team edits a banner. No vulnerability was needed at that stage.
Sansec did not say how the account was created. Stolen credentials, an earlier compromise or access through a third-party extension would all fit.
The numbers put those cases in context. Sansec estimates that 471 stores were injected through PolyShell (CVE-2026-48356), roughly half of the 953. Another 102 had files uploaded through PolyShell or SessionReaper (CVE-2025-54236); Sansec does not split that group between the two bugs.
Together that is 573 stores, about 60%, and both figures are estimates. For the remaining 380 or so, the initial access route has not been disclosed. Unpatched installs don’t stay hidden for long, as we explained in our breakdown of how attackers find vulnerable websites.
Patching PolyShell closes the door most attackers used. It does not evict anyone already inside. A patched store with an admin account nobody can identify is a compromised store.
What does an infection cost, and who decides?
The direct exposure is customer payment and account data, plus the regulatory and card-brand consequences if that data leaks. Because the final payload is unknown, the owner of an infected store cannot rule out card theft and should plan as if it happened until an investigation shows otherwise.
PCI DSS 4.0 makes this concrete. Requirements 6.4.3 and 11.6.1, mandatory since 31 March 2025, require merchants to inventory and authorize scripts on payment pages and to detect unauthorized changes to those pages as the customer’s browser receives them.
A loader that only shows itself to real shoppers is exactly the threat 11.6.1 was written for. A merchant who cannot show any monitoring of the rendered checkout will have a harder conversation with the acquiring bank after an incident.
The mechanism has a well-known precedent. The 2018 British Airways breach came down to a modified script on the airline’s own website, and the UK Information Commissioner’s Office fined the company £20 million in 2020. The 953 figure here counts stores, not shoppers or cards, and most victims are far smaller merchants. The exposure path is the same.
Questions the owner or manager should get answered this week:
- Patching: who owns Magento updates, and on what date was APSB26-73 confirmed as applied? Ask for a date, not “we update regularly.”
- Access: who holds admin accounts, including agencies, developers and former contractors? Every account should map to a named, current person.
- Monitoring: is anyone checking what the checkout actually serves to browsers, not only what sits in server files?
- Response: if an infection turns up, who calls the payment processor and who decides on customer notification? Settle that before you need it.
What should a Magento store owner check this week?
Start with database content and admin users, then files, then patches, and preserve evidence before you delete anything.
- Confirm your version. From the Magento root, run bin/magento –version and compare the exact release line against Adobe’s security bulletins, including APSB26-73. Stores in the 2.4.7-p1 class that skipped it remain exposed to PolyShell.
- Audit CMS content. Search the content of cms_block and cms_page for script tags and external hosts you don’t recognize, then compare with what your team actually published. In the admin, review Content > Blocks for entries nobody remembers creating.
- Audit administrators. List every admin account with its creation date, last login and role. Look for accounts created or roles changed around the time any block was edited.
- Inspect media folders. Check pub/media/custom_options/quote/ and other upload paths by file type and contents, not by name. Any PHP inside a media directory is a finding.
- Rotate access. Reset admin passwords and integration or API credentials, invalidate active admin sessions and require two-factor authentication for the admin panel.
- Review checkout code. Look over payment templates, layout updates and third-party payment modules, since nobody yet knows what the final payload targets.
From our cleanup work: the most common mistake we see is deleting the visible script first. Export the affected cms_block and cms_page rows, the admin user records, any webshell files and the web server logs, with timestamps, before touching them. Those timestamps are often the only way to tie a block edit to an admin login or a file upload.
And don’t keep loading a suspected loader URL from an office laptop to see what it does. Cloaking varies by IP address, headers, browser and visit history, so you will probably get nothing back, and you may have told the operator someone is looking.
If the loader was live, returning customers may still carry the stored code until they clear site data — the localStorage problem described above. Mention it in any customer notice alongside the usual advice to watch card statements. It is a communication point, not something you can fix from your server.
Finding a loader, an unknown admin or a shell means a full incident: server, database, admin accounts and integrations. Removing one PHP file leaves the database injection and the rogue account in place. Between audits, continuous monitoring such as SiteGuarding Antivirus website protection helps catch file changes, while the database and admin checks above stay on your calendar.
What is still unknown — and should the PHP2Shell flaws worry Magento owners?
Three gaps remain: the final payload, the operator’s identity and how roughly 380 stores were first breached. Until Sansec or other researchers publish more, assume the worst plausible outcome for any infected checkout.
PHP2Shell is a separate story, but it concerns every Magento owner because Magento runs on PHP. The two critical PHP remote code execution flaws (CVE-2026-109618 and CVE-2026-109619, rated CVSS 9.2) were disclosed with emergency PHP patches the week before Sansec’s report, and widespread exploitation attempts followed.
According to The Hacker News, Perplexity researcher Adel Karimi recorded what appears to be the first successful in-the-wild exploitation on honeypot servers, with commands using wget, curl or the PHP command line to fetch further payloads. No second-stage files have been retrieved so far.
Nothing links PHP2Shell to this campaign. Update PHP in the same maintenance window as your Magento patches, and if your host manages PHP, ask for the date it was updated.
FAQ
How do I know if my Magento store has malicious JavaScript?
Search the content of the cms_block and cms_page database tables for script tags or external hosts your team didn't add, and review admin accounts for ones nobody recognizes. Don't rely on an external scanner alone; this campaign's server withholds the payload from scanners.
What is a Magento CMS block malware injection?
It is malicious code stored inside a CMS block, the reusable content that Magento inserts into storefront pages. Because blocks live in the database rather than in files, the code renders for every shopper while file scans of the web root come back clean.
Can a fully patched Magento store still get hacked?
Yes. Sansec found a Magento 2.4.7-p10 store with no missing core patches that was compromised through a rogue administrator account, which the attackers used to inject the loader.
What is CVE-2026-48356 PolyShell?
PolyShell is a Magento vulnerability that Sansec estimates was the entry point for 471 of the 953 infected stores. In one documented case, attackers left webshells disguised as PNG images. Adobe fixed it for supported release lines in bulletin APSB26-73.
How do hackers hide skimmers from security scanners?
In this campaign, the attacker's server fingerprints each visitor and returns code only to what looks like a real shopper, while scanners and bots get nothing. One loader version also stores the code in the browser's localStorage so it keeps running on repeat visits.
What should Magento store owners do after a JavaScript infection?
Preserve evidence first, then remove the injected content, delete rogue admin accounts and any webshells, apply APSB26-73, and rotate all admin and integration credentials. Because the payload is unknown, contact your payment processor and prepare customer communication.
Found an unfamiliar script in a CMS block or an admin account nobody can explain? Our team can investigate, clean and lock down your store; choose a protection package and we’ll take it from there.
