Back to blog

    June 22, 2026

    WooCommerce security checklist: what changes when customer money is involved

    The day you turn on WooCommerce, your WordPress site stops being a website and becomes a payment system. Same admin panel, same plugins, same backups — but now every security mistake has a credit card number attached to it. The hardening checklist that worked fine for a marketing site is no longer enough.

    This guide walks through what actually changes when you sell things online, and what to do about it. No jargon dumps. Just the stuff that matters when real money and real customer data are flowing through your site.

    Why WooCommerce is a different security problem

    A brochure site that gets hacked is a bad day. You restore from backup, clean up, move on. Maybe Google flags you for a week.

    A WooCommerce store that gets hacked is a different category of problem:

    • Customer credit card data may be exposed (or stolen in real time via a skimmer)
    • Personally identifiable information (PII) — names, addresses, phone numbers, order histories — sits in your database
    • You may be on the hook for PCI compliance violations, chargebacks, and breach notification costs
    • Your payment processor can freeze or terminate your merchant account
    • Customers who got skimmed at your store are not coming back

    The threat model is different because the attacker's payoff is different. Hacking a plumber's WordPress site gets you a place to host phishing pages. Hacking a WooCommerce store gets you live card data you can sell within hours. You are a more interesting target the moment you start taking payments.

    Everything below assumes you've already done the basics: strong admin passwords, 2FA on every admin account, automatic plugin updates, a real web application firewall, and offsite backups. If you haven't, start there. This post covers what comes after.

    Payment page integrity: protecting the checkout itself

    The most dangerous attack against a WooCommerce store isn't ransomware or defacement. It's a card skimmer — a tiny piece of JavaScript injected into your checkout page that quietly copies card numbers as customers type them and ships the data off to an attacker's server. Customers complete their purchase. Orders come through normally. Nothing looks wrong until your processor calls you about a fraud cluster three months later.

    Two technical controls make this attack much harder.

    Content Security Policy (CSP)

    A CSP is an HTTP header that tells the browser which domains are allowed to run scripts on your page. If an attacker injects a <script src="https://evil-skimmer.com/..."> tag, a properly configured CSP makes the browser refuse to load it.

    A starter CSP for a WooCommerce checkout using Stripe might look like:

    Content-Security-Policy: default-src 'self';
      script-src 'self' https://js.stripe.com https://www.google.com/recaptcha/;
      frame-src https://js.stripe.com https://hooks.stripe.com;
      connect-src 'self' https://api.stripe.com;
      img-src 'self' data: https:;
      style-src 'self' 'unsafe-inline';
    

    CSPs are fiddly. Every plugin that loads a script from a CDN you didn't whitelist will break. The right approach is:

    1. Start in Content-Security-Policy-Report-Only mode so violations are logged but not blocked
    2. Watch the reports for a week, whitelist the legitimate sources
    3. Switch to enforcement mode

    Subresource Integrity (SRI) on payment scripts

    SRI is a hash attached to a <script> tag. The browser computes the hash of the file it downloads and refuses to run it if the hash doesn't match. If an attacker compromises a third-party script you depend on, SRI catches it.

    <script src="https://js.stripe.com/v3/"
            integrity="sha384-[hash]"
            crossorigin="anonymous"></script>
    

    The catch: payment providers like Stripe deliberately don't publish stable SRI hashes for their main JS files because they update them frequently. So SRI is most useful for your own bundled checkout JS and any non-payment third-party scripts you load on checkout pages (analytics, chat widgets, etc.). The principle to internalize: anything that loads on your checkout page is part of your payment system. Audit it like one.

    A practical rule I'd give any store owner: nothing loads on the checkout page that isn't required for checkout. No chat widgets. No pop-up tools. No A/B testing scripts. No marketing pixels unless your provider explicitly supports PCI-compliant integration. Every extra script is another way in.

    PCI scope: SAQ-A vs SAQ-D and why it matters

    PCI DSS — the Payment Card Industry Data Security Standard — applies to anyone who accepts card payments. There are different "Self-Assessment Questionnaires" (SAQs) depending on how you handle card data. Two of them matter for WooCommerce stores.

    SAQ-A: you're using a hosted payment solution

    This is what you want. Card data never touches your server. The customer enters their card number into an iframe or hosted field served directly by Stripe, Square, PayPal, or another processor. Your server only sees a token.

    Setups that qualify for SAQ-A include:

    • Stripe Checkout (full redirect to Stripe's page)
    • Stripe Elements when configured correctly (iframe-based)
    • PayPal Standard / PayPal Buttons
    • Square hosted checkout

    SAQ-A is roughly 20 questions. You're affirming basic things: you have policies, you use strong passwords, you don't store card data, your hosted payment provider is PCI-certified. Annual self-assessment, no on-site audit.

    SAQ-D: you're touching card data

    If card numbers ever pass through your server — even just in transit, even briefly — you're in SAQ-D territory. This includes:

    • Custom payment forms that POST card details to your server and then forward them
    • Some older "direct" gateway integrations
    • Anything that puts the card field in your page's DOM without an iframe

    SAQ-D is ~330 questions. You need network segmentation, quarterly external vulnerability scans by an Approved Scanning Vendor, file integrity monitoring, formal change control, written policies, employee training records, and a security incident response plan. This is real compliance work and real ongoing cost. Most small businesses should not be in SAQ-D scope.

    What to do

    Confirm which SAQ applies to your setup. Open your checkout, right-click on the card number field, inspect element. If it's inside an <iframe> pointing at your payment provider's domain, you're likely SAQ-A. If it's a regular <input> field on your own domain, talk to your developer immediately — you may be in scope you didn't know about.

    I am not a Qualified Security Assessor. For an authoritative answer about your specific setup, ask your payment processor's compliance team. They have a clear interest in helping you stay SAQ-A.

    Customer data: what's in your database and who can see it

    Even if you never store card numbers, a WooCommerce database is a goldmine. The wp_wc_orders and related tables hold names, billing addresses, shipping addresses, phone numbers, email addresses, purchase history, IP addresses, and sometimes notes from customers. A breach of just that data is enough to trigger state breach notification laws and destroy customer trust.

    Limit who can see orders

    By default, anyone with the Shop Manager role can view all orders and export them. If you have five people with admin access "because it's easier," five people can download your entire customer list. Three things to do:

    1. Audit your user list this week. Anyone who doesn't need access — remove. Anyone who only needs to fulfill orders — give them Shop Manager, not Administrator.
    2. Disable the order export feature for non-admin roles. A plugin like User Role Editor lets you remove the export capability from Shop Manager.
    3. Turn on 2FA for every account with order access. Not optional.

    Be careful with order exports

    The default WooCommerce CSV export dumps everything: full addresses, phone numbers, emails, order totals. Where does that file go? Someone's laptop Downloads folder? Emailed to a bookkeeper? Uploaded to a marketing tool?

    A leaked customer CSV is a breach. Treat exports like cash:

    • Export only the columns you actually need
    • Delete the file when you're done
    • Never email customer data; use a shared drive with access controls
    • Don't upload customer lists to random third-party tools without checking their data handling

    PII in server logs

    This one gets missed all the time. Web servers log every request, including URLs. WooCommerce REST API endpoints, AJAX calls, and admin URLs can include customer IDs, order IDs, and sometimes email addresses as query parameters. Those logs sit on your server (and often get shipped to log aggregators) in plain text.

    A few things to check:

    • Does your hosting provider rotate and delete logs on a reasonable schedule? (30–90 days is typical)
    • Are logs included in your backups? If yes, they're now in more places.
    • If you use an external log service like Papertrail or Loggly, is that service in your data processing agreement?
    • Are debug logs (WP_DEBUG_LOG) ever enabled in production? They should not be. Debug logs capture far more than access logs and routinely include PII.

    In wp-config.php, production should always have:

    define( 'WP_DEBUG', false );
    define( 'WP_DEBUG_LOG', false );
    define( 'WP_DEBUG_DISPLAY', false );
    

    The plugin surface: WooCommerce's biggest weakness

    WordPress has the largest plugin ecosystem of any CMS. WooCommerce has the largest plugin ecosystem on top of WordPress. The average store I look at runs 25–40 plugins: payment gateways, shipping calculators, tax plugins, subscription managers, product add-ons, reviews, email marketing integrations, abandoned cart recovery, analytics. Each one is code from a third party running with full access to your database and your checkout.

    On the WordPress site I cleaned for a Southern California contractor, the initial compromise came in through a plugin vulnerability that a prior contractor had "fixed" by deleting the visible spam posts. The backdoor was still there, regenerating content on a schedule. The plugin was outdated by about eighteen months. The fix wasn't just removing the malware — it was rebuilding the plugin inventory from scratch.

    Quarterly plugin audit

    Put a recurring calendar event every three months. For every active plugin:

    1. Is it still maintained? Check the plugin's WordPress.org page or vendor site. "Last updated" more than 12 months ago is a red flag. No updates in 24 months means abandoned.
    2. Are there known CVEs? Search the plugin name at wpscan.com/plugins. If there are unpatched vulnerabilities, replace it.
    3. Do you actually use it? If not, delete it (don't just deactivate — deactivated plugin code still sits on disk and can still be exploited if a directory traversal flaw exists elsewhere).
    4. Who is the developer? A plugin from a known company with a support team is different from a single-developer hobby project. Both can be fine; both can be risky. The point is to know.

    Document the result. A simple spreadsheet with plugin name, version, last-update date, vendor, purpose, and audit notes is enough. After a year, you'll have a real picture of what's running on your site.

    Premium plugin licenses

    Expired licenses on premium plugins are a quiet disaster. The plugin keeps working, but stops receiving updates — including security patches. Auto-renew every license tied to a production WooCommerce site, and check renewals annually.

    Monitoring: the signals that mean something bad is happening

    Most stores have zero monitoring beyond uptime checks. They find out they were hacked when a customer complains, Google flags them, or the bank calls. Better signals exist if you watch for them.

    Card testing attacks: failed payment spikes

    Fraudsters use compromised WooCommerce stores (and stolen card lists) to test cards in bulk. They run thousands of $1–$5 transactions to figure out which stolen cards still work, then sell or use the working ones elsewhere.

    What it looks like:

    • Sudden spike in checkout traffic with no marketing campaign behind it
    • Dozens or hundreds of failed payments in a short window
    • Many small-dollar successful orders to similar-looking addresses, often international
    • Traffic concentrated in unusual hours

    What to do about it:

    • Enable reCAPTCHA or hCaptcha on checkout
    • Set a rate limit on the checkout endpoint (Cloudflare or your WAF can do this)
    • Turn on your processor's fraud rules — Stripe Radar, for example, has free baseline rules that catch obvious card testing
    • Watch your payment processor dashboard weekly, not just monthly

    If a card testing attack hits you and your processor sees the spike in failures, they may increase your authorization fees or, in bad cases, freeze your account. Catching it in the first hour matters.

    New admin user creation

    One of the first things an attacker does after gaining access is create a backup admin account. This is one of the highest-signal events on a WordPress site, and almost no one watches for it.

    Two ways to detect it:

    1. An activity log plugin (WP Activity Log, Simple History) that emails you when a new user with admin or shop_manager role is created
    2. A WP-CLI cron job that compares the user list against a known-good baseline and alerts on changes

    Either works. Doing neither is a mistake.

    File integrity monitoring

    If a plugin file changes and you didn't update anything, that's a problem. File integrity monitoring (FIM) tools like Wordfence, Sucuri, or a custom solution based on file hashes will tell you. For WooCommerce stores, this is closer to a requirement than a nice-to-have. Configure it to specifically watch:

    • /wp-admin/
    • /wp-includes/
    • Your active theme directory
    • All plugin directories
    • wp-config.php
    • .htaccess and any nginx config you control

    Outbound traffic

    Skimmers exfiltrate data by making outbound HTTP requests from the browser, not from your server. But many backdoors do make outbound calls from the server (to command-and-control, or to download additional payloads). If your hosting provider gives you any visibility into outbound connections, look at it. Connections to IPs you don't recognize, especially to known malicious-IP lists, are a clear signal.

    Pulling it together

    A secure WooCommerce store isn't one big thing. It's a stack of small habits:

    • Lock down the checkout page itself — CSP, SRI, no extra scripts
    • Know which PCI SAQ applies to you and stay in SAQ-A scope if at all possible
    • Treat customer data as the regulated asset it is, including in logs and exports
    • Audit your plugin inventory every quarter
    • Watch for the specific attack patterns that target stores: card testing, new admins, file changes

    None of this is exotic. All of it is the kind of thing that quietly doesn't get done because no one owns it. If you're running a store that does meaningful revenue and you've never had any of this reviewed by someone whose job it is to think about it, that's the gap to close.

    If you want a hands-on review of your WooCommerce setup — checkout integrity, plugin audit, monitoring setup, and the boring-but-critical configuration work — that's exactly what the Site Hardening service is for. For ongoing coverage (quarterly audits, monitoring, incident response on retainer), the Security Retainer covers it. Both are described at thewizrdz.io/#security, and the contact form is at the bottom of the page if you'd rather just talk through your specific situation first.

    Need help with what this post covers? I do this for a living.

    Book a free 15-min site audit