Card Skimming: How to Check Your Checkout Page

By Bug Circuit Security Team
Card Skimming: How to Check Your Checkout Page

Is your own website affected? Check it free in 2 minutes.

Passive outside check only. Nothing is attacked, no signup.

Card skimming happens when a malicious script runs on your checkout page and copies card details as customers type them, and you can check for it by listing every script that loads on checkout, removing the ones you do not recognise, and locking the page down with a Content Security Policy.

This guide is for owners of small online stores (WooCommerce, Magento, Shopify, custom carts) who want a plain-English way to look at their own checkout. You will learn how a skimmer works, how to run a 15-minute checkout page skimmer check from your browser, how to review third-party scripts, and how to start a Content Security Policy safely.

What is card skimming on a website?

A card skimmer is a small piece of JavaScript (code that runs inside the visitor's browser) that sits on your checkout page. When a customer types their card number, name and address, the script quietly sends a copy to a server the attacker controls. The order still goes through, so neither you nor the customer notices.

The name Magecart is the umbrella term for this style of attack. It started with groups targeting Magento stores, and now describes web skimming in general, on any platform. Attackers do not break into your bank. They plant a few lines of code where customers type their card.

There are two common ways the code gets there:

  • Your own site is changed. An attacker uses a stolen admin password, an outdated plugin or a vulnerable extension to add a script to your theme, footer or database settings.
  • A script you already trust is changed. Many stores load code from other companies (chat widgets, analytics, ad pixels, A/B testing tools). If one of those providers is compromised, the bad code reaches your checkout without you touching anything.

The second route is why "my site is patched" is not a complete answer. Your checkout is only as safe as every script it loads. OWASP covers this in its Third Party JavaScript Management Cheat Sheet.

Does your payment setup change the risk?

Yes. Where the card number is actually typed matters a lot.

Payment setupWhere the card is typedSkimmer risk on your page
Redirect to a hosted page (for example Stripe Checkout, PayPal)On the provider's own domainLower. Card fields are not on your page. A script could still redirect shoppers to a fake page, so check your scripts anyway.
Embedded provider fields (iframes, such as Stripe Elements)In a frame from the providerLower, but the page around the frame is still yours. Scripts can alter the page or add fake fields.
Card fields built into your own pageOn your domainHighest. Any script on the page can read what is typed.

If you can choose, a hosted or iframe-based payment form reduces what a skimmer can reach. It does not remove the need to review your scripts.

On Shopify, checkout is hosted by Shopify and you cannot freely edit its code, so your focus is the apps, pixels and theme code you have installed. On WooCommerce and Magento, you control much more, which also means more to check.

How to do a checkout page skimmer check in 15 minutes

You need Chrome, Edge or Firefox and a test product. Do not enter a real card. Stop at the payment step, or use your payment provider's documented test mode.

  1. Add a product to the cart and go to the checkout page, as a normal customer would.
  2. Open developer tools: press F12 (or Ctrl+Shift+I, Cmd+Option+I on Mac).
  3. Open the Console tab and paste this to list every script on the page:
[...document.scripts].map(s => s.src || '(inline script)').join('\n')
  1. Paste this to list every frame on the page:
[...document.querySelectorAll('iframe')].map(f => f.src || '(no src)').join('\n')

Note: Chrome, Edge and Firefox block pasting into the Console until you type allow pasting and press Enter. This is a safety feature, so the commands above are not broken. Type it once, then paste again.

  1. Open the Network tab, tick the JS filter, right-click the column header and enable Domain, reload the page, then sort by Domain. (In Firefox, use the Domain column that shows by default.) This also shows scripts that load other scripts.
  2. Repeat on the cart page, the order-confirmation page and any step where address or card data is entered.

These lists only show what loads in your browser right now. A skimmer might only appear for some visitors or only on the payment step, so treat a clean result as good news, not proof.

What to look for in the script list

Write down every domain. Then sort each into one of three piles: I know what this is, I think I know, and no idea.

  • Your own domain and your CDN. Normal.
  • Payment provider domains. Normal, if they match the provider's documentation exactly.
  • Analytics, ads, chat, reviews. Normal on many stores, but ask whether each one needs to be on the checkout page at all.
  • Lookalike domains. Names that resemble a real service with a small change, such as an extra word, a different ending or swapped letters. Treat these as suspicious.
  • Inline scripts full of unreadable text, or code using eval( or atob( (a function that decodes hidden text). Some legitimate tools use these too, so look closer rather than panic.
  • Card-like fields you did not build, or scripts loaded from a domain registered recently for no clear reason.

For anything in the no idea pile, search the domain name along with your platform. Then find where it comes from (see below). If you cannot explain a script, remove it or ask your developer to.

Find where unknown scripts come from

WooCommerce / WordPress

  • Review Plugins > Installed Plugins and delete anything unused or abandoned.
  • Check your theme's header.php, footer.php and any "header and footer scripts" plugin for code you did not add.
  • If you have WP-CLI access, verify core files and plugins from WordPress.org against their official checksums:
wp core verify-checksums
wp plugin verify-checksums --all

Any file reported as modified or unexpected deserves a closer look.

Magento / Adobe Commerce

  • Go to Content > Design > Configuration, edit your store view, and check HTML Head > Scripts and Style Sheets and the footer's Miscellaneous HTML. These are common hiding spots because they are editable in the admin panel.
  • Check System > Permissions > All Users for admin accounts you do not recognise, and System > Permissions > Locked Users if relevant.

Shopify

  • Review Settings > Apps and remove apps you no longer use.
  • Check Settings > Customer events for custom pixels.
  • Look in your theme code (Online Store > Themes > Edit code) for unfamiliar <script> tags.

Reduce the third-party scripts you load

Every extra script is one more company whose security you depend on. A simple rule works well: checkout should load only what is needed to take payment. Move marketing pixels, heat maps and chat widgets to other pages if you can.

For scripts you must keep:

  • Keep a short written list: what it is, who supplies it, why it is there, who approved it.
  • Where a provider supports it, use Subresource Integrity (an integrity attribute that makes the browser refuse a file if it changes). This only works for files that never change, so it suits fixed library files, not most vendor widgets. See MDN's Subresource Integrity guide.
  • Re-check the list after every plugin, theme or app change.

If you take card payments, note that PCI DSS v4.x (currently 4.0.1) requires you to manage and monitor scripts on payment pages (requirements 6.4.3 and 11.6.1). These requirements have been mandatory since 31 March 2025. Ask your payment provider or acquirer what applies to your setup. You can read the standard at the PCI Security Standards Council.

Set a Content Security Policy for your checkout

A Content Security Policy (CSP) is a header your server sends that tells the browser which sources it may load scripts from and where the page may send data. If a skimmer tries to load from, or send data to, a source you did not allow, the browser blocks it. It is one of the better defences here, and the OWASP CSP Cheat Sheet explains it well.

Two sets of directives matter most here:

  • script-src limits where scripts can load from.
  • connect-src, form-action and a tight default-src/img-src limit where the page can send data, which makes it much harder for a skimmer to send stolen data out, though not impossible.

Start in report-only mode. A strict policy can break your checkout if you miss a domain. Report-only mode logs problems in the browser console without blocking anything. Here is an example for a store using Stripe. Replace the Stripe entries with the domains your own provider documents (see Stripe's CSP guidance):

Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' https://js.stripe.com; frame-src https://js.stripe.com https://hooks.stripe.com; connect-src 'self' https://api.stripe.com; form-action 'self'; base-uri 'self'; object-src 'none'

On nginx, add it inside the relevant server or location block:

add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' https://js.stripe.com; frame-src https://js.stripe.com https://hooks.stripe.com; connect-src 'self' https://api.stripe.com; form-action 'self'; base-uri 'self'; object-src 'none'" always;

Careful with nginx inheritance. If a location block has any add_header line of its own, it replaces all add_header lines inherited from the server block instead of adding to them. If you put the CSP in a location block, repeat your other headers there too, or you may silently lose them. Also make sure that block is the one that actually serves your checkout pages, or the CSP will not apply where you expect.

Then:

  1. Load checkout and open the Console. Lines starting with [Report Only] Refused to load... name each source your policy would block.
  2. For each one, decide: needed (add the exact domain) or not needed (remove the script).
  3. Repeat until the console is quiet on every checkout step.
  4. Rename the header to Content-Security-Policy to enforce it. Test a full order in test mode right away.

A few honest limits:

  • Avoid 'unsafe-inline' in script-src if you can. It lets any inline script run, which weakens the protection a lot.
  • A CSP cannot protect you from a script on a domain you allowed, if that provider is compromised. That is why the script review above still matters.
  • Some platforms (including Shopify's hosted checkout) do not let you set your own headers on checkout. In that case, focus on removing unneeded apps and scripts.

You can use the free security headers tool to see whether your site sends a CSP and other useful headers.

If you find something you cannot explain

  1. If the script looks malicious, take checkout offline or switch payments off (maintenance mode, or pause the payment method) so no more cards are exposed.
  2. Contact your payment provider or acquirer, since card-data exposure may come with steps you must follow.
  3. Do not delete the script straight away. Take a screenshot and copy the code, so you have evidence.
  4. Change admin, hosting and database passwords, and turn on two-factor login.
  5. Remove the script and find how it got there (an old plugin, an unknown admin user, a changed file).
  6. Update everything before you put checkout back online.

Our website hacked guide walks through cleanup in more detail.

Where a human review fits

A quick browser check catches the obvious things. A manual audit looks at the whole site: outdated software, weak admin access, exposed files, missing headers and how a skimmer could realistically get in. If you want a first look at no cost, try the free website security check.

Key takeaways

  • Card skimming (Magecart-style attacks) means malicious JavaScript on checkout copies card details while orders keep working normally.
  • List every script and frame on your cart and checkout pages using the console commands above, and remove anything you cannot explain.
  • Keep checkout lean: load only what is needed for payment, and keep a written list of who supplies each script.
  • Start a Content Security Policy in report-only mode, fix what it flags, then enforce it. Treat it as one layer, not a guarantee.
  • Use a hosted or iframe payment form where you can, so card numbers are not typed on your own page.

Next step

If you would rather have a person look, our Circuit audit is $49 one-time. A security engineer manually reviews your whole site, including your checkout, and sends a written report with severity, evidence and exact fixes. It is a focused small-site audit, not an enterprise pentest or a compliance certification. See pricing for details.

Want certainty, not guesswork?

A real human security engineer audits your whole site by hand and sends a full report: every issue, its severity, and the exact fix. From $49, with a 14-day money-back guarantee.

See pricing

Frequently asked questions

What is Magecart?
Magecart is the common name for attacks that plant JavaScript skimmers on online checkout pages to copy card details. It began with groups targeting Magento stores and now describes web skimming on any platform. The code runs in the customer's browser, so the order still completes and nothing looks wrong.
How do I check my checkout page for a card skimmer?
Open your checkout in a browser, press F12, and list every script and iframe that loads using the Console and Network tabs. Look for domains you do not recognise, lookalike names, or heavily scrambled inline code. Then trace each unknown script to its plugin, app or theme file and remove what you cannot explain.
What is a content security policy for a checkout page?
It is a header that tells the browser which sources may load scripts and where the page may send data. On checkout, the key rules are script-src, connect-src and form-action. Start with Content-Security-Policy-Report-Only so you can find missing domains before you enforce it.
Can a content security policy stop card skimming?
It can block skimmers that load from, or send data to, a source you have not allowed, which makes many attacks harder. It cannot stop a script from a domain you allowed if that provider is compromised, and loose settings like unsafe-inline weaken it. Use it together with script reviews and updates.
Is Shopify checkout safe from skimmers?
Shopify hosts and controls its checkout, which limits what code you can add there, and that reduces the places a skimmer can hide. Your risk comes mostly from the apps, pixels and theme code you install. Remove unused apps, review custom pixels and keep staff accounts protected with two-factor login.

Keep reading

See what attackers see, for free

Run the free passive check on your website. No login, no impact on your site, results in seconds.

Ready for the full manual audit? See pricing

Published by Bug Circuit. Written with AI assistance and reviewed for accuracy before publishing.