skills/security-compliance/secure-checkout/SKILL.md
Harden your checkout against attacks with HTTPS enforcement, Content Security Policy headers, input sanitization, and card data tokenization
npx skillsauth add finsilabs/awesome-ecommerce-skills secure-checkoutInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Payment pages are the highest-value target for attackers — a single XSS vulnerability can lead to Magecart-style card skimming attacks that steal thousands of card numbers. Securing checkout requires enforcing TLS everywhere, implementing strict Content Security Policies (CSP) to prevent script injection, using payment tokenization to minimize PCI scope, and removing non-essential third-party scripts from payment pages. The good news: Shopify and BigCommerce handle most of this infrastructure automatically. WooCommerce merchants need to configure hosting and install security plugins. Custom storefronts require implementing all of these controls from scratch.
| Platform | HTTPS / TLS | CSP Headers | Payment Tokenization | Third-Party Script Control | |----------|-------------|-------------|---------------------|---------------------------| | Shopify | Automatic — Shopify provisions and renews SSL certificates | Shopify manages checkout CSP; your theme pages need review | Shopify Payments and all gateway integrations use tokenization | Use Shopify's Script Manager and Customer Events to control what loads on checkout | | WooCommerce | Your hosting responsibility — install SSL from Let's Encrypt or your host | Your server responsibility — configure via hosting or plugin | Determined by your gateway choice (Stripe Elements = SAQ A-EP) | WordPress plugin and theme scripts load globally; use conditional loading to exclude checkout | | BigCommerce | Automatic — BigCommerce provisions SSL and enforces HTTPS | BigCommerce manages checkout CSP for hosted checkout | Handled by your payment gateway choice through BigCommerce checkout | BigCommerce Script Manager controls third-party script placement | | Custom / Headless | Your infrastructure responsibility | Your application responsibility — implement per-request CSP with nonces | Implement with Stripe Elements or Braintree Drop-in UI | Full control and full responsibility — must implement explicitly |
Shopify's hosted checkout is one of the most secure available — it runs on Shopify's own domain (checkout.shopify.com or your custom domain with SSL), uses Shopify Payments tokenization, and is protected by Shopify's CDN and WAF.
HTTPS enforcement:
Third-party scripts on checkout: Shopify's checkout extension model (Checkout Extensibility) limits what can run on the checkout page — this is by design for PCI compliance.
Theme security review:
document.cookie, localStorage, or fetch on cart/checkout pages — these are red flags if you did not add them intentionallyAdmin account security (reduces attack surface):
WooCommerce checkout security depends almost entirely on your hosting configuration and payment gateway. Your hosting provider is responsible for TLS, and the gateway you choose determines whether card data ever touches your server.
Step 1 — Force HTTPS on your store:
Step 2 — Choose a payment gateway that keeps card data off your server:
Step 3 — Install security plugins:
Step 4 — Remove scripts from checkout pages: WooCommerce loads all active plugins on every page by default. Use Asset CleanUp Pro ($25 one-time) or add conditional PHP to prevent non-essential scripts from loading on checkout:
Go to WooCommerce → Settings → Advanced and verify:
WP_DEBUG must be false in wp-config.php in production)Step 5 — Configure SSL security headers via hosting or plugin:
BigCommerce's hosted checkout is PCI-DSS Level 1 certified and handles TLS, CSP, and payment tokenization automatically when you use a supported gateway.
HTTPS enforcement:
Controlling third-party scripts:
Checkout payment security:
Admin account security:
For custom storefronts, you implement all checkout security controls. The three most critical are: payment tokenization (so your server never sees card numbers), strict CSP on payment pages (to prevent Magecart injection), and HTTPS with security headers.
Payment tokenization with Stripe Elements (SAQ A-EP):
// Client-side: Stripe handles card data in an iframe — your code never sees card numbers
const stripe = await loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!);
const elements = stripe.elements({ clientSecret });
const paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');
// On submit: Stripe handles card capture; your server receives only a paymentIntentId
const { error, paymentIntent } = await stripe.confirmPayment({
elements,
confirmParams: { return_url: `${window.location.origin}/order-confirmation` },
});
// Your server confirms via paymentIntentId — never a card number
HTTPS and security headers (Next.js example):
// next.config.ts
export default {
async headers() {
return [
{
source: '/(.*)',
headers: [
{ key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=(), payment=()' },
],
},
{
// No caching on checkout; no indexing by search engines
source: '/checkout(.*)',
headers: [
{ key: 'Cache-Control', value: 'no-store, no-cache, must-revalidate' },
{ key: 'X-Robots-Tag', value: 'noindex' },
],
},
];
},
};
Content Security Policy with per-request nonces (prevents Magecart):
// middleware.ts — generate a new nonce per request; static nonces can be bypassed
export function middleware(request: NextRequest) {
const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
const csp = [
`default-src 'self'`,
`script-src 'self' 'nonce-${nonce}' https://js.stripe.com`,
`style-src 'self' 'nonce-${nonce}'`,
`frame-src https://js.stripe.com https://hooks.stripe.com`,
`connect-src 'self' https://api.stripe.com`,
`img-src 'self' data: https:`,
`object-src 'none'`,
`base-uri 'self'`,
`form-action 'self'`,
`upgrade-insecure-requests`,
`report-uri /api/csp-report`,
].join('; ');
const response = NextResponse.next();
response.headers.set('Content-Security-Policy', csp);
response.headers.set('x-nonce', nonce); // Pass to layout for script nonce attributes
return response;
}
CSP violation monitoring:
// app/api/csp-report/route.ts — log violations; alert on checkout page violations
export async function POST(req: NextRequest) {
const body = await req.json();
const violation = body['csp-report'];
await logger.warn('CSP Violation', {
documentUri: violation['document-uri'],
violatedDirective: violation['violated-directive'],
blockedUri: violation['blocked-uri'],
});
// A CSP violation on a payment page may indicate an active Magecart attack
if (violation['document-uri']?.includes('/checkout')) {
await alertSecurityTeam('CSP violation on checkout page', violation);
}
return new NextResponse(null, { status: 204 });
}
Server-side input validation with Zod:
import { z } from 'zod';
const checkoutSchema = z.object({
email: z.string().email().max(255),
name: z.string().min(1).max(200).regex(/^[\p{L}\p{M}\s\-'.]+$/u),
address: z.string().min(1).max(500),
city: z.string().min(1).max(100),
postalCode: z.string().min(1).max(20),
country: z.string().length(2), // ISO 3166-1 alpha-2
});
export async function POST(req: NextRequest) {
const body = await req.json();
const result = checkoutSchema.safeParse(body);
if (!result.success) {
return NextResponse.json({ errors: result.error.flatten() }, { status: 400 });
}
// Proceed with validated data only
}
'unsafe-inline' to script-src defeats the entire purpose of CSPopenssl dgst -sha256 -binary script.js | openssl base64npm audit and use Snyk or Dependabot; a compromised npm package in your checkout bundle is as dangerous as a Magecart injection| Problem | Solution |
|---------|----------|
| CSP breaks Stripe Elements iframes | Add https://js.stripe.com and https://hooks.stripe.com to frame-src; check Stripe's CSP documentation for the current complete allowlist |
| 'unsafe-inline' added to unblock styles | Use nonces for inline styles instead; 'unsafe-inline' invalidates CSP protection for that directive entirely |
| TLS certificate expired | Use Let's Encrypt with auto-renewal (Certbot) or a managed certificate from your CDN; Shopify and BigCommerce auto-renew — only WooCommerce/custom stores require manual renewal |
| Analytics scripts loading on checkout pages | Add a conditional check in your analytics initialization that skips loading on /checkout routes; on Shopify use Customer Events placement settings |
| Third-party chat widget with access to payment fields | Remove chat widgets from checkout pages entirely; no legitimate support use case requires reading payment form values |
tools
Let shoppers save products to a wishlist, share it with friends, and get notified when saved items come back in stock or drop in price
development
Build a themeable storefront with design tokens and CSS custom properties that supports white-labeling, multi-brand variants, and dark mode
development
Speed up product discovery with instant search suggestions, fuzzy typo matching, and category-aware results powered by Algolia or Elasticsearch
development
Build a mobile-first storefront with thumb-friendly navigation, sticky add-to-cart buttons, and touch-optimized components for high mobile conversion