8

PricingBlog
All posts
engineering

Anatomy of a Magento Card Skimmer: How Injected JavaScript Steals Cards — and Why Uptime Checks Miss It

2026-09-09 · Byte8 Team

Share

A Magento store can be fully up, fast, and passing every uptime check while quietly sending each customer's card number to a criminal. Nothing looks broken. Orders complete, pages load in 400ms, the status page is green — and card data is being copied at the moment it's typed.

That's a card skimmer. It's one of the most common and most damaging things that happens to a Magento store, and it's built from the ground up to be invisible. This post walks through exactly how a skimmer gets in, what the injected code does, why traditional monitoring can't see it, and how to catch and remove one.

What is a Magento card skimmer?

A Magento card skimmer — a form of Magecart or digital skimming attack — is malicious JavaScript injected into a store's frontend that reads payment and personal details from the checkout form and sends them to an attacker-controlled server. The customer sees a normal checkout. The order goes through. The card just gets stolen on the way.

The important part for anyone running a store: a skimmer doesn't break anything visible. It adds a small, silent listener to a page that's otherwise working perfectly. The store keeps returning HTTP 200, the page stays fast, and no PHP exception is ever thrown. Detection is hard precisely because, by every conventional signal, the store looks healthy.

How a card skimmer gets into a Magento store

The attacker's goal is simple: get their JavaScript to execute on your checkout page. Magento offers several routes to that, and most of them live in the database rather than in your codebase — which is why redeploying from clean git often doesn't remove a skimmer.

  • core_config_data. Magento has admin fields whose contents are rendered into every page: the "Miscellaneous HTML" boxes (header/footer), the head includes, tracking-script fields. A single row in core_config_data can inject a script store-wide. This is the single most common Magento skimmer vector.
  • CMS blocks and pages. A widget or static block that appears on many pages — a footer block, a promo banner — is edited to carry the payload. It renders wherever the block is placed.
  • Layout XML and theme templates. After a server or admin compromise, the attacker edits .phtml templates or layout XML directly to add a <script> tag. File-level, so it survives cache flushes but not a clean redeploy.
  • A compromised admin account or extension. The entry point for most of the above: a reused admin password with no 2FA, or a vulnerable third-party extension that allows content to be written. Recent unauthenticated RCE flaws have let attackers skip the login step entirely.
  • A third-party or CDN script (supply chain). A legitimate external script the storefront already loads — analytics, a chat widget, a tag manager — is swapped at its source. The store's own database is untouched, which makes this variant especially sneaky.

The attack, step by step

Step 1 — Get in

The attacker gains write access to content: a guessed or phished admin login, an exploited extension, or in the worst case remote code execution on the server. No 2FA on even one admin account is often all it takes.

Step 2 — Inject the skimmer

They add a few lines of JavaScript to one of the injection points above — most often a core_config_data field or a CMS block, because those render site-wide and don't require touching the filesystem. The payload is usually obfuscated so it doesn't read as "skimmer" to a casual glance.

Step 3 — Harvest at checkout

The script waits for the checkout page. Many skimmers check the URL and only activate on /checkout to reduce their footprint. They read the payment and address fields — card number, expiry, CVV, name, billing address — either by watching keystrokes or by scraping the form just before submit.

Step 4 — Exfiltrate

The harvested data is sent to an attacker-controlled domain, frequently one that mimics a real service (a lookalike of a CDN, analytics, or font host) so it blends into normal network traffic. Exfiltration often rides on an image request or a fetch to a domain that looks innocuous in a list of third-party calls.

Step 5 — Stay hidden

Good skimmers are quiet. They throw no errors, add no visible latency, and often re-inject themselves from a second foothold if the first is cleaned. The store keeps working normally, which is the whole point — the longer it looks healthy, the longer the cards keep flowing.

Why uptime checks — and even APM — are blind to it

This is the part that catches teams out. Every conventional monitoring signal says the store is fine, because a skimmer doesn't touch any of them.

signal                         what it sees          skimmer detected?
----------------------------   -------------------   -----------------
uptime / HTTP check            200 OK, page loads    no
response-time / APM            fast, ~400ms          no
error-rate / exceptions        none thrown           no
synthetic checkout             order completes       no (order still works)
server / infra metrics         normal load           no

An uptime monitor asks "did the page respond?" — it did. An APM tool asks "is it fast, and is the code healthy?" — it is. Even a synthetic checkout that drives a real browser will complete the order, because the skimmer doesn't stop the purchase — it rides alongside it. The failure isn't availability or performance. It's integrity: the page is serving code it shouldn't. Nothing built to watch "is it up?" or "is it fast?" is built to notice that.

How to detect a card skimmer on your Magento store

You can look for a skimmer by hand today. The checks that matter most:

  • Read core_config_data for script content. Query the config fields that render to the frontend (the Miscellaneous HTML and head-include paths) and look for any <script> you didn't put there, or references to external domains you don't recognise.
  • Audit CMS blocks and pages. Scan block and page content for inline scripts and unfamiliar external src domains, especially in site-wide footer/header blocks.
  • List every external script your storefront loads, particularly on the checkout page, and confirm each domain is one you trust. A lookalike domain (a near-miss of a real CDN or analytics host) is a red flag.
  • Diff your templates against clean git. If layout XML or .phtml files differ from what's committed, something wrote to the filesystem.
  • Deploy a Content-Security-Policy and watch its reports. A CSP in report-only mode will tell you when a page tries to load or exfiltrate to an unexpected domain — a strong tripwire for skimmers.
  • Check whether the injection only fires on checkout. Many skimmers are URL-gated, so comparing the scripts loaded on a product page versus the checkout page can surface a payload that only appears where the cards are.
The catch with all of these is that they're point-in-time. A skimmer injected the day after your last manual audit runs for weeks before the next one. Integrity is not a thing you check once; it's a thing that has to be watched.

How Pulsar detects injected skimmers

This is exactly the gap Pulsar is built to close, and it does it in two ways that matter here.

Content-integrity monitoring. Pulsar's content-integrity collector reads the places skimmers actually hide — core_config_data and CMS content — and flags injected <script> tags, unexpected external script domains, and known skimmer signatures. Because it reads Magento's own stored content rather than just fetching the page, it catches the database-resident injection that's invisible from the outside. It runs continuously, so a script added an hour ago is caught in the next check, not at the next manual audit.

A first-class "compromised" status. Most monitoring tools only know two states: up and down. But a skimmed store is up — that's the problem. Pulsar treats compromised as its own status, separate from the uptime SLA, so a store that's serving customers perfectly while leaking cards doesn't hide behind a green "100% uptime" number. A skimmer is a security incident, and it's surfaced as one.

A note on honesty, because this category is still maturing: content-integrity monitoring catches the common Magento vector — code injected into your store's content — extremely well. A skimmer loaded through a compromised third-party script lives outside your database, which is why watching your external script sources (and running a CSP) matters alongside it. No single check is a silver bullet; defence in depth is the point.

How to remove a skimmer and keep it out

Finding it is half the job. Removing it cleanly and closing the door is the other half.

  • Remove the injected code at the source — the core_config_data row, the CMS block, or the template file. Redeploying from clean git fixes file-level injections but not database ones, so check both.
  • Assume the admin credentials are compromised. Reset all admin passwords and enforce 2FA on every account, no exceptions.
  • Patch and audit the entry point. Apply outstanding Magento security patches, review third-party extensions, and check for unauthorised admin users, integration tokens, and API keys created during the breach window.
  • Rotate secrets if there was server access. If the compromise reached the filesystem, treat app/etc/env.php — database credentials and the encryption key — as stolen, and rotate accordingly.
  • Add a Content-Security-Policy to constrain which domains can run scripts and receive data, turning the next attempt into a blocked, reported event.
  • Monitor content integrity continuously so the next injection is caught in minutes, not at the next quarterly audit — or the next chargeback.

Common questions

Can a Magento card skimmer be detected by uptime monitoring? No. A skimmer doesn't affect availability — the store stays up, the checkout still completes, and every HTTP response is a healthy 200. Uptime monitoring asks whether the page responded; the skimmer doesn't stop it from responding. Detecting a skimmer requires watching the integrity of what the page serves, not whether it serves.

Where do skimmers hide in Magento? Most often in the database: core_config_data fields that render site-wide (the Miscellaneous HTML and head-include boxes) and CMS blocks or pages. Less commonly in layout XML or .phtml templates after a filesystem compromise, or in a third-party script loaded from a compromised external source.

Why doesn't redeploying from clean git remove the skimmer? Because the most common injection points are in the database, not the codebase. A clean redeploy overwrites files but leaves core_config_data and CMS content untouched, so a database-resident skimmer survives it. You have to clean the content, not just the code.

Is a card skimmer the same as being "hacked and down"? No — and that's what makes it dangerous. A skimmed store is fully operational. It's compromised and up at the same time, which is why monitoring that only distinguishes up from down misses it entirely, and why a compromised store needs its own status.

How fast should a skimmer be detected? As close to immediately as possible — every hour it runs is more stolen cards and more liability. That's the argument for continuous content-integrity monitoring over periodic manual audits: the window between injection and detection is exactly the window in which customers get hurt.

A skimmer is the clearest example of why "is the site up?" is the wrong question. The store is up. It's fast. It's green on every dashboard built to measure availability and performance — and it's stealing cards. Watching the store's integrity, and treating a compromise as its own first-class state, is how you see the failure that every other tool is built to miss.

See how Pulsar monitors Magento →


Enjoyed this? Share it with your team.

Share