8 September 2026
Dave

Watching the Scripts Your Site Loads

Web skimmers and formjacking are the most common ways e-commerce sites get robbed. Our latest audit update now scans for hidden script loaders and obfuscated URLs to catch these threats before they do damage.

Crawl report email alert flagging a suspicious script on 2 pages
The alert lands in the subject line and tops the crawl report body, before the summary.

Watching the Scripts Your Site Loads

Most attacks on a small business website don't deface the homepage or take the site down. They do the opposite: they keep everything looking completely normal, and quietly add one small script that reads the card number out of your checkout form and posts it somewhere else. The site owner finds out weeks later, from their payment processor.

This release adds a check for exactly that. Every audit — basic or advanced — now reads the inline scripts embedded in each page and looks for the tell-tale signs of a hidden loader. If it finds one, it doesn't bury it in the report: it shouts.


The threat, briefly

The pattern has a name — Magecart, or more generally a web skimmer or formjacking — and it's been the most common way e-commerce sites get robbed for years. It doesn't need a clever exploit. An out-of-date plugin, a reused admin password, a compromised theme from a dodgy download site — any of those is enough to let someone add a few lines of JavaScript to your pages.

Those few lines are written to be unreadable. The real payload — the address the stolen card details get sent to — is never in plain sight. It's base64-encoded, or assembled from character codes at runtime, or (in the newest variants) fetched from a blockchain contract so there's no fixed server to block. The loader decodes all of that when the page runs, then adds a fresh <script> tag pointing at the real skimmer. To anyone reading the page source, it's a wall of gibberish sitting next to what looks like a normal analytics snippet.

That "looks like analytics" part is deliberate. A lot of these loaders wrap themselves in fake Google Tag Manager boilerplate, because site owners see dataLayer and gtm.start and move on.


What the check looks for

The scanner reads each inline <script> on the page and scores it against a set of signals. No single signal is damning on its own — plenty of legitimate code uses atob once, or base64-encodes a small image. It's the combination that gives a hidden loader away:

  • Encoded strings that decode to a URL or a list of URLs. This is the strongest signal. A legitimate script that needs a URL just writes the URL. One that hides its URLs inside base64 blobs is hiding them for a reason.
  • Repeated decode calls — several atob()s in one short block, JSON.parse(atob(...)), hex-to-bytes loops, String.fromCharCode arrays.
  • Building and injecting a <script> element at runtimecreateElement('script'), setting its src, appending it to the page. This is how the loader pulls in the actual skimmer after it's decoded the address.
  • A dynamic import() of a computed value rather than a fixed module path.
  • Client-side decryption of an embedded payloadcrypto.subtle with PBKDF2 / AES-GCM and a hard-coded key. A browser almost never has a legitimate reason to decrypt something it's carrying around with it.
  • Escape-encoded string literals — long runs of \x6d\x61\x69\x6c... where readable text would do.
  • A GTM/analytics disguise wrapped around any of the above — counted only when something else has already fired, as a confidence bump.

Each match adds weight. Past a threshold, the script is flagged. The two near-conclusive signals — an encoded string that decodes to a URL, and runtime <script> injection — carry enough weight to trip the alert on their own.

The check is conservative by design. It runs against the raw inline code, it ignores non-JavaScript <script> blocks (JSON-LD structured data, import maps, templates), and the thresholds are set so that a normal Google Tag Manager container, a Cloudflare email-obfuscation snippet, or a page's config object won't set it off. The goal is that when you get the alert, it means something.


How it alerts

A skimmer is an act-now finding, so it's treated as one.

In the subject line. The crawl report email leads with it, ahead of everything else:

🚨 SECURITY: suspicious script on 2 pages — Crawl Report — example.com (40 pages, 1 broken)

You see it in the inbox list without opening anything.

In the report body. A red alert block sits at the top of the email, above the summary: what was found, which pages it was found on (listed in full), and a direct link to the detail. There's a matching row in the Issues table, and in the results viewer it appears as its own Security › Suspicious scripts group — red, not amber — with the exact list of markers that fired and a snippet of the offending code so you can see what you're dealing with.

Everywhere the report goes. The console output and the webhook payload carry the same count, so an automated pipeline can act on it too.


Why this belongs in a regular audit

The scripts running on your site are the part most likely to change without you touching anything. Your own code sits still between deployments. Third-party scripts — the analytics tag, the chat widget, the reviews embed, the payment library — update themselves, and each one is a piece of code from someone else's server that runs with full access to your pages, your forms and your customers' keystrokes. When one of those providers is compromised, or when someone slips an extra script in through a plugin you'd forgotten about, nothing on the surface looks different.

That's the case for checking it on a schedule rather than once. A monitored site runs this check on every crawl, so a script that wasn't there last week and is there now — decoding URLs and injecting tags — gets caught on the next run and lands in your inbox with a klaxon on it, instead of turning up in a chargeback report a month later.

It won't catch everything. A skimmer loaded from an external file the audit can't read, or one injected only after a real browser runs the page, can still slip past this first pass. But the cheap, common, high-volume case — an obfuscated loader sitting in the page's own HTML — is now something every audit looks for, and something you'll hear about the moment it appears.

Ready to start your own audit?

Drop in your URL and email to request an audit and a 7 day trial.

Run a free audit