Build1 publisher2 min readPublished
A skimmer in Magento's Miscellaneous HTML field survives a redeploy from clean git
The injected JavaScript only adds an event handler, so HTTP checks, response times and exception logs all stay clean, and the most common hiding place is a database row that no rebuild from git replaces.
The Engineer · Build desk

What happened
- A dev.to walkthrough describes a Magento card skimmer as JavaScript injected into the storefront that reads payment and personal details from the checkout form and sends them to an attacker-controlled server.
- According to the post, orders complete, pages load in 400ms and the status page stays green while each customer's card data is copied at the moment it is typed.
- A single row in core_config_data can inject a script store-wide through the Miscellaneous HTML boxes, head includes and tracking-script fields, which the post calls the most common Magento skimmer vector.
- Most of the injection routes are database content rather than code, which is why redeploying from clean git often does not remove the skimmer.
- Harvested fields leave the browser on an image request or a fetch to a domain that mimics a CDN, an analytics service or a font host, so it blends into normal third-party traffic.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint No amount of tuning turns availability monitoring into a skimmer detector, because the payload adds a listener without changing a status code, a latency figure or an exception log. The evidence has to be collected from the browser.
- decision Incident response order changes. A team that redeploys first gets a clean build and keeps the payload if it sits in a config row, so the database content has to be diffed before anyone declares the store clean.
- exposure The swap-at-source variant puts every tag vendor the storefront loads inside the checkout's trust boundary, because their origin can be changed without touching anything the merchant owns.
Everything the payload does is a read. It takes keystrokes as they are typed, or scrapes the checkout fields just before submit: card number, expiry, CVV, name, billing address [4]. The harvested data goes out on an image request or a fetch to a lookalike of a CDN, an analytics service or a font host [6]. No PHP exception is thrown, and the response time does not move [3].
Then count where the payload can physically sit. Two of the four places are database content: a row in `core_config_data`, whose Miscellaneous HTML boxes, head includes and tracking-script fields render into every page [5], and a CMS block or widget placed across the store [7]. One is on disk, a `.phtml` template or layout XML edited after an admin or server compromise, which survives a cache flush [8]. One is on someone else's server, a legitimate third-party script the storefront already loads, swapped at its source [9]. A rebuild from clean git replaces the files and leaves the other three [1].
Cleanup order follows from that count. A team that redeploys first gets a green build and keeps the skimmer whenever the payload is in a config row, and dev.to's walkthrough calls that the single most common vector, though the post does not say what data ranks it first [5] [1].
The supply-chain variant is harder on anyone diffing their own content. The store's database is never touched [9], so a diff of config rows, CMS blocks and templates comes back clean while the checkout page is still executing the attacker's code [2].
Uptime checks were built to answer whether the page loads, and they answer it correctly [15]. What changes when a skimmer lands is on the client: the set of scripts the browser executes on the checkout URL, and the set of hosts those scripts contact [3].
Two more details shape verification after removal. Many skimmers check the URL and activate only on `/checkout` to reduce their footprint [13], so reading the homepage source proves nothing about `/checkout` [4]. And skimmers often re-inject from a second foothold once the first is cleaned [10]. The entry point the post describes is ordinary: a reused admin password with no 2FA on a single account, or a third-party extension that allows content to be written, and recent unauthenticated RCE flaws have let attackers skip the login step entirely [11] [12].
What to watch
- Published Magento cleanup postmortems that say which injection point actually held the payload, which would test the claim that core_config_data leads.
- Whether unauthenticated Magento RCE flaws keep removing the admin-login step from this chain.
- Storefront tag vendors publishing integrity guarantees for their hosted scripts, since the swap-at-source variant never touches store content.