Django PCI DSS Checklist for Apps That Take Payments
A PCI DSS checklist for Django apps accepting card payments: minimize scope with hosted payment fields or redirects, never store card data, secure the pages that load payment scripts, protect against script tampering, manage access, logging, vulnerability scanning, and SAQ evidence.
Problem statement
Your Django app takes card payments, and the payment provider asks you to complete a PCI DSS Self-Assessment Questionnaire (SAQ). Which requirements apply depends almost entirely on whether card data ever touches your servers. Using hosted payment pages or embedded fields from Stripe, Adyen, Braintree, or similar keeps you in the smallest scope, but PCI DSS 4.0 added requirements for the pages that load payment scripts. This checklist helps engineering teams keep scope small and meet the remaining controls.
- Use hosted checkout or provider iframes/elements so card numbers go straight to the provider (SAQ A or A-EP scope).
- Never log, store, or transmit card numbers, CVVs, or track data through Django; scrub them from logs and error reports.
- Protect payment pages: a strict Content Security Policy, an inventory of scripts, and tamper detection (PCI DSS 4.0 requirements 6.4.3 and 11.6.1).
- Secure the environment: patched dependencies, MFA for admin and infrastructure access, TLS everywhere, and logging of administrative actions.
- Run quarterly external vulnerability scans if your SAQ requires them, and keep evidence for each answer.
Checklist
Scope reduction
- Card data entered only in provider-hosted pages or iframes (Stripe Checkout or Elements, Adyen Drop-in, Braintree Hosted Fields).
- No card numbers in Django forms, models, logs, or database, ever; tokens or payment method IDs only.
- Webhooks from the provider verified by signature; webhook payloads contain no full card data.
- SAQ type confirmed with the payment provider or acquirer (A for fully hosted redirects or iframes, A-EP if your page controls the payment form's surroundings).
Payment page security (PCI DSS 4.0)
- Inventory of every script loaded on payment pages, with justification for each.
- Content Security Policy restricting scripts to your domain and the provider, with violation reporting.
- Subresource Integrity or equivalent controls for third-party scripts where possible.
- Change and tamper detection for payment page headers and scripts (monitoring service or scheduled checks).
Access control and authentication
- Unique accounts and MFA for Django admin, cloud consoles, CI/CD, and servers.
- Least-privilege roles; payment-related admin actions (refunds, payouts) limited to specific staff.
- Strong password policy and lockout (django-axes or similar) for staff accounts.
- Prompt removal of access for departing staff, with periodic reviews.
Secure development and patching
- Dependencies pinned and scanned (pip-audit, Dependabot); critical patches applied within defined timelines.
- Code review for changes to payment flows and templates of payment pages.
DEBUG = False, security headers, andcheck --deployclean in production.- Secrets (provider API keys, webhook secrets) in a secrets manager, rotated after staff changes or leaks.
Logging, monitoring, and testing
- Logs of admin actions, authentication events, and payment-related operations, retained per policy (at least a year, with recent months readily available).
- Alerts on suspicious activity: many failed payments, refund spikes, admin logins from new locations.
- Quarterly external vulnerability scans by an approved scanning vendor if your SAQ requires them.
- Annual review of the SAQ and evidence collection.
Explanation
PCI DSS protects cardholder data. Its scope covers every system that stores, processes, or transmits that data, plus systems that can affect its security. Hosted payment fields and redirects keep card numbers entirely within the provider's environment, so your Django app never handles them and only a small subset of requirements applies. PCI DSS 4.0 recognized that attackers inject skimming scripts into payment pages, so even SAQ A merchants must control and monitor the scripts on pages that host payment forms.
Edge cases / notes
- Phone orders. Staff typing card numbers into your admin brings systems into scope; use the provider's virtual terminal instead.
- Saved cards. Store provider tokens or payment method IDs, never card numbers or CVVs.
- Logs and Sentry. Make sure request bodies and headers on payment-adjacent endpoints are scrubbed.
Next steps
- Handle provider events with Deploy Django Stripe Webhooks in Production.
- Lock down payment pages with Configure Content Security Policy in Django.
- Prepare launch with the Django E-commerce Launch Checklist.
FAQ
Do I need PCI compliance if I use Stripe?
Yes, but usually at the smallest scope (SAQ A) when you use Stripe Checkout or Elements and never handle card data.
Can I store card numbers in my Django database?
Avoid it. Store provider tokens instead; storing card data puts your whole environment in full PCI scope.
What did PCI DSS 4.0 change for small merchants?
It added requirements to manage and monitor scripts on payment pages, even for hosted or iframe integrations.
Who decides my SAQ type?
Your acquirer or payment provider confirms it based on your integration.