PCI DSS v4.0 for Laravel Developers: What You Actually Need to Implement
PCI DSS v4.0 became mandatory in March 2025. If your Laravel application touches payment card data, you need to know exactly which of the 12 PCI requirements apply to you and what they mean in PHP terms. This guide cuts through the compliance jargon.
PCI DSS v4.0 became mandatory on March 31, 2025 when PCI DSS v3.2.1 was retired. If your Laravel application handles, stores, or transmits payment card data, you need to know what changed, what is required of you specifically, and how to implement it in PHP.
The Payment Card Industry Data Security Standard is enforced by the card brands (Visa, Mastercard, Amex, Discover) through contractual obligations with your payment processor. Non-compliance can result in significant fines, mandatory audits, and ultimately the termination of your ability to accept card payments. This is not a standard you can ignore.
This guide covers what PCI DSS v4.0 requires in technical terms, which requirements matter most for Laravel web applications, and what you need to implement before your next assessment.
What PCI DSS Is and Why v4.0 Matters
PCI DSS defines security requirements for any organisation that stores, processes, or transmits cardholder data. Cardholder data includes the Primary Account Number (PAN — the 16-digit card number), cardholder name, expiration date, and service code. Sensitive Authentication Data (SAD), which includes CVV2, magnetic stripe data, and PINs, has even stricter rules and must never be stored after authorisation.
Version 4.0 was published in March 2022 and became the only active version on March 31, 2025. The key changes from v3.2.1 include:
- More flexibility through the Customised Approach. Organisations can now implement alternative controls that achieve the intent of a requirement, rather than following the prescriptive defined approach. This requires more documentation and risk analysis but allows modern architectures.
- Expanded MFA requirements. MFA is now required for all administrative access to the cardholder data environment (CDE), not just remote access.
- New web skimming controls (Req 6.4.3 and 11.6.1). Payment page script management and tamper detection are now explicitly required.
- Targeted risk analysis. Many requirements now allow flexibility if you perform a documented risk analysis to justify your implementation approach.
- Password complexity changes. Minimum password length increased to 12 characters for new implementations.
For Laravel developers, the most significant new requirements are the web skimming controls and the expanded MFA mandate.
Scoping: How to Reduce Your PCI DSS Surface Area
The most important PCI DSS decision you make is architectural: how much of your Laravel application is in scope?
Your PCI scope includes all system components that store, process, or transmit cardholder data, plus any systems that can impact the security of those components. The larger the scope, the more controls you must implement and evidence.
The best way to reduce scope is to never touch card numbers. Use a hosted payment page or embedded payment widget from your processor:
- Stripe Checkout / Stripe Elements: Cardholder data goes directly to Stripe's servers via JavaScript loaded from Stripe's CDN. Your Laravel backend receives a token or PaymentIntent ID, not a card number.
- Braintree Drop-in UI / Hosted Fields: Same model — card data goes to Braintree directly.
- PayPal Hosted Solution / Spreedly: Payment pages hosted entirely off your infrastructure.
With this architecture, your Laravel application handles tokens, not PANs. This limits your CDE to potentially just the pages that load the payment widget and the backend endpoints that call the processor's API.
Tokenisation architecture for Laravel:
// What your Laravel controller handles — a Stripe PaymentIntent, never a card number
public function processPayment(PaymentRequest $request): JsonResponse
{
$paymentIntent = $this->stripeService->confirm(
paymentIntentId: $request->validated('payment_intent_id'),
customerId: $request->user()->stripe_customer_id,
);
if ($paymentIntent->status === 'succeeded') {
Order::create([
'user_id' => $request->user()->id,
'stripe_payment_id' => $paymentIntent->id, // Token, not card data
'amount_cents' => $paymentIntent->amount,
'currency' => $paymentIntent->currency,
]);
}
return response()->json(['status' => $paymentIntent->status]);
}
With this approach, no card numbers, expiry dates, or CVV codes ever reach your PHP application. Your PCI scope is dramatically reduced.
The 12 PCI DSS Requirements: What Matters for Laravel
PCI DSS has 12 top-level requirements organised around the goal of protecting cardholder data.
Requirement 1 — Install and maintain network security controls. Firewalls must restrict traffic to what is necessary. For Laravel on AWS or similar, this means your security groups must not expose database ports to the internet, and your application servers should not be directly internet-accessible if you use a load balancer. Document your network topology including all in-scope systems.
Requirement 2 — Apply secure configurations. All system components must have vendor defaults changed (default passwords, default configs). For Laravel, this means removing the default password migration password hashing method if you were using bcrypt rounds lower than 12, ensuring APP_ENV=production is set, and confirming APP_DEBUG=false.
Requirement 3 — Protect stored account data. This is the core data protection requirement. The rule is simple: never store the full PAN if you can avoid it. If you must store it, it must be rendered unreadable using strong cryptography. CVV2 and SAD must never be stored after authorisation, ever. In Laravel terms: if you are storing card numbers, every row in that table must use strong field-level encryption, and your key management must be documented.
Requirement 4 — Protect cardholder data with strong cryptography during transmission. All transmission of cardholder data over open networks must use TLS 1.2 or higher. Configure nginx to reject TLS 1.0 and 1.1 connections. Add HSTS headers. This applies to your API calls to payment processors too — verify that your Stripe/Braintree PHP SDK is not downgrading TLS.
Requirement 6 — Develop and maintain secure systems and software. This is the most extensive requirement for Laravel developers.
6.2 — Software development processes: Your development process must include security training for developers, review of code changes for security vulnerabilities, and separation of development and production environments.
6.3.3 — Patch management: All software components must be protected from known vulnerabilities by applying security patches. For PHP and Laravel, this means a defined SLA for applying security patches. A common approach is critical patches within 30 days, other security patches within 90 days.
6.4.1 — Web application protection: Web-facing applications must be protected either by a Web Application Firewall (WAF) that detects and blocks web-based attacks, or by a validated security assessment that confirms no exploitable vulnerabilities exist. A WAF is the practical choice for most Laravel applications.
6.4.3 — Payment page script management (NEW in v4.0): All scripts loaded by your payment pages must be authorised. You must maintain an inventory of every script, justify why it is needed, and verify its integrity. For external scripts, use Subresource Integrity (SRI):
<!-- In your payment page Blade template -->
<script
src="https://js.stripe.com/v3/"
integrity="sha384-[hash-from-stripe]"
crossorigin="anonymous">
</script>
For scripts you control, add integrity checks or use Content Security Policy (CSP) to whitelist allowed sources:
// In your middleware
$nonce = base64_encode(random_bytes(16));
$response->headers->set(
'Content-Security-Policy',
"script-src 'nonce-{$nonce}' https://js.stripe.com; object-src 'none';"
);
Requirement 7 — Restrict access to system components and cardholder data by business need to know. Least-privilege access to your CDE. In Laravel, use role-based access control and ensure only authorised roles can access payment-related routes and data. Audit your Gate and Policy definitions for anything touching card data.
Requirement 8 — Identify users and authenticate access to system components.
8.3 — MFA for all non-console administrative access: MFA is now required for any access to the CDE's administrative interface. If your admin panel is in scope (touches or can affect cardholder data systems), MFA is required for all admins.
8.3.6 — Password length: Minimum 12 characters for new implementations. Update your validation rules:
// app/Http/Requests/Auth/RegisterRequest.php
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'confirmed', Password::min(12)->mixedCase()->numbers()],
];
}
Requirement 10 — Log and monitor all access to system components and cardholder data. All access to CDE systems must be logged. Logs must capture: user ID, type of event, date/time, success or failure, origin, and identity of affected data. Logs must be retained for at least 12 months, with the most recent 3 months immediately available.
Implement a dedicated PCI logging channel:
// config/logging.php
'pci_audit' => [
'driver' => 'daily',
'path' => storage_path('logs/pci-audit.log'),
'level' => 'info',
'days' => 366, // 12+ months retention
],
Log every access to payment-related endpoints:
// Middleware for PCI-scoped routes
Log::channel('pci_audit')->info('cardholder_data_access', [
'user_id' => auth()->id(),
'event_type' => 'read',
'resource' => 'payment_methods',
'ip' => request()->ip(),
'user_agent' => request()->userAgent(),
'result' => 'success',
'timestamp' => now()->toIso8601String(),
]);
Requirement 11 — Test security of systems and networks regularly. Quarterly external vulnerability scans by an Approved Scanning Vendor (ASV). Annual penetration tests covering both network and application layers. Change-and-tamper detection for payment pages (NEW in v4.0 — Req 11.6.1).
Laravel-Specific Implementations
Dependency Management for PCI (Requirement 6.3.3)
PCI DSS requires a defined patching SLA. Integrate composer audit into your CI/CD pipeline:
# .github/workflows/security.yml
name: Security Audit
on: [push, pull_request, schedule]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: composer install --no-interaction --prefer-dist
- name: Run security audit
run: composer audit --no-dev
Document your patching SLA in your security policy: "Critical vulnerabilities (CVSS 9.0+) will be patched within 14 days. High vulnerabilities (CVSS 7.0–8.9) will be patched within 30 days." Then actually adhere to it — auditors will compare your audit findings against your deployment dates.
Web Application Firewall Requirements (Requirement 6.4.1)
For payment-scoped Laravel applications, a WAF is the practical choice over ongoing security assessments. Options:
- Cloudflare WAF: Layer 7 protection with OWASP rule sets, easy to enable for any Laravel app
- AWS WAF: Integrates with CloudFront and ALB, fine-grained rule control
- Nginx ModSecurity: Self-hosted WAF, more configuration required
Whichever you choose, document in writing that a WAF is in place, what ruleset it uses, and who is responsible for rule updates.
Logging and Monitoring Requirements (Requirement 10)
Beyond logging, Requirement 10.7 requires that failures of critical security controls are detected, reported, and responded to promptly. Configure alerts for:
// Log all authentication failures to a monitored channel
protected function sendFailedLoginResponse(Request $request): void
{
Log::channel('pci_audit')->warning('authentication_failure', [
'email' => $request->input('email'),
'ip' => $request->ip(),
'timestamp' => now()->toIso8601String(),
]);
throw ValidationException::withMessages([
'email' => [trans('auth.failed')],
]);
}
Feed your security log channel into a monitoring system (Datadog, New Relic, CloudWatch Logs with metric filters) and set up alerts for patterns like more than 10 authentication failures per IP per minute.
Vulnerability Scanning and Penetration Testing (Requirement 11)
ASV Scans (external, quarterly): Use a PCI Security Standards Council Approved Scanning Vendor. Examples include Trustwave, Qualys, SecurityMetrics, and Tenable. These quarterly scans check your internet-facing systems for known vulnerabilities and must result in a clean (passing) scan to submit with your SAQ or ROC.
Internal scans (quarterly): Use a tool like Nessus, OpenVAS, or Rapid7 InsightVM to scan your internal systems. These can be run by your own security team.
Penetration testing (annual): PCI requires penetration tests at both the network layer (infrastructure) and application layer. The application-layer test should include OWASP Top 10 testing specifically against your payment flows: SQL injection, XSS in payment pages, broken authentication, IDOR on payment records, and business logic issues like price manipulation.
After significant changes — a major Laravel upgrade, a new payment integration, a new server environment — penetration tests must be repeated for the changed components.
SAQ vs ROC: Which Applies to Your Laravel Application
Self-Assessment Questionnaires (SAQs) are for merchants and service providers that do not require a full on-site audit by a Qualified Security Assessor.
| SAQ Type | When It Applies | Requirements |
|---|---|---|
| SAQ A | All cardholder data functions outsourced; no electronic storage, processing, or transmission of CHD on your systems; card-not-present merchants only | ~22 requirements |
| SAQ A-EP | Partially outsourced; your server directly loads the payment page but doesn't handle card data | ~190 requirements |
| SAQ B | Standalone dial-out terminals only; no electronic storage | ~41 requirements |
| SAQ C | Payment application systems connected to the internet; no electronic storage of CHD | ~140 requirements |
| SAQ D (Merchants) | Merchants not eligible for other SAQs; all other merchant card acceptance channels | ~300+ requirements |
| SAQ D (Service Providers) | Service providers eligible to complete an SAQ | ~300+ requirements |
For most Laravel SaaS applications:
- Using Stripe Elements / Braintree Hosted Fields: SAQ A (if your server doesn't directly serve the payment page JavaScript) or SAQ A-EP (if your server renders the page that loads the payment widget).
- Your own payment form that calls a processor API: SAQ D — your server touches card data.
- You are a SaaS provider whose customers use payment features: SAQ D (Service Providers) — you are a service provider.
The distinction between SAQ A and SAQ A-EP matters significantly for Laravel developers. If your Blade template renders the <script src="https://js.stripe.com/v3/"> tag, and that page is served by your PHP application, you are likely SAQ A-EP rather than SAQ A. Consult your QSA or acquiring bank to confirm which applies.
Report on Compliance (ROC): Large service providers (processing more than 300,000 transactions annually) and companies specifically required by their acquirer to undergo a full audit must complete a ROC with a QSA rather than an SAQ. This is a full on-site assessment.
How External Monitoring Supports PCI Compliance Evidence
PCI DSS Requirement 11 is explicitly about testing and monitoring, and continuous external monitoring directly satisfies the detective control requirements. For Requirement 11.6.1 (change and tamper detection for payment pages), you need evidence that your payment pages are monitored for unauthorised modifications.
External monitoring also generates the evidence trail that ASV scans and annual assessments need as context. When an assessor asks "how do you know your external attack surface is clean between quarterly ASV scans?" — continuous monitoring is the answer.
StackShield monitors your external attack surface daily, detecting configuration regressions, newly exposed services, certificate issues, and security header changes that could affect PCI scope. Run a free scan to see what your ASV would find today, and fix it before your next quarterly assessment.
Conclusion
PCI DSS v4.0 is more detailed than its predecessor, but the core philosophy is unchanged: reduce the cardholder data you touch, protect what you do touch, monitor continuously, and test regularly.
For Laravel developers, the practical priorities are:
- Architect to SAQ A or SAQ A-EP scope using hosted payment widgets
- Implement dependency auditing in CI/CD
- Configure comprehensive audit logging for all CDE access
- Set up WAF protection on payment-related routes
- Implement the new v4.0 script integrity requirements on payment pages
- Schedule quarterly ASV scans and annual penetration testing
- Document everything — controls only count if you can evidence them
The compliance requirement is real, but it is also an engineering quality floor. An application that meets PCI DSS requirements is one that is well-monitored, well-patched, and access-controlled. Those are properties worth having for reasons beyond compliance.
Is your Laravel app exposed right now?
34% of Laravel apps we scan have at least one critical issue. Most teams don't find out until something breaks. Our free scan checks your live application in under 60 seconds.
Frequently Asked Questions
Do I need to be PCI compliant if I use Stripe or Braintree?
Yes, but using Stripe or Braintree dramatically reduces your compliance burden. When you use these providers with their hosted payment fields (Stripe Elements, Stripe Checkout, Braintree Drop-in UI), cardholder data never touches your servers and your Laravel application is never in the data flow. This limits your PCI scope to SAQ A — the smallest scope possible. You still need to comply with SAQ A requirements, which include ensuring your payment pages are served over HTTPS, your site has no malicious scripts, and you have a relationship with a PCI-compliant payment provider. You still must complete and submit an SAQ annually. Using Stripe does not mean you have zero PCI obligations, but it reduces them to a manageable level.
What is the difference between SAQ A and SAQ D for Laravel applications?
SAQ A applies when all cardholder data functions are fully outsourced to a PCI-compliant third party (like Stripe Checkout or Braintree Drop-in UI) and your Laravel application never sees raw card numbers. SAQ A has 22 requirements and is the most lightweight. SAQ A-EP applies when you use a third-party payment page but your server directly loads or renders that page (for example using JavaScript you control). It has more requirements including vulnerability scanning. SAQ D applies when you handle, store, or transmit cardholder data in your own system — for example if you accept card numbers via your own form or store them in your database. SAQ D encompasses all 12 requirement domains and over 300 individual controls. The difference is enormous. Always architect to achieve SAQ A if at all possible.
What are the PCI DSS penalties for non-compliance?
PCI DSS is a contractual standard enforced by card brands (Visa, Mastercard) through your payment processor and acquiring bank, not a law with direct government penalties. Non-compliance penalties are set by the card brands and can include fines from your acquirer ranging from $5,000 to $100,000 per month until you achieve compliance. If you experience a breach while non-compliant, fines escalate significantly — Visa and Mastercard can assess your acquirer $5,000 to $500,000 per incident, which they pass on to you. You may also be required to hire a Qualified Security Assessor (QSA) for all future assessments rather than self-assessing. In extreme cases, card brands can terminate your ability to accept card payments entirely.
How often do I need to run vulnerability scans for PCI compliance?
PCI DSS Requirement 11 mandates two types of scans. Internal vulnerability scans must be performed quarterly and after significant changes to your network environment. External vulnerability scans must be performed quarterly by an Approved Scanning Vendor (ASV) — a company that is certified by the PCI Security Standards Council. ASV scans check your externally facing infrastructure for known vulnerabilities. Penetration tests must be performed annually and after significant infrastructure or application changes. The penetration test covers both network and application-layer testing. For web applications specifically, Requirement 6.4 also requires that a web application firewall or application vulnerability testing be performed continuously.
Does PCI DSS v4.0 change anything about what Laravel developers need to do?
Yes, v4.0 introduced several requirements that directly affect web application developers. Requirement 6.4.3 now mandates that all payment page scripts (including third-party JavaScript) are explicitly authorised and their integrity is verified — typically via Subresource Integrity (SRI) hashes. Requirement 11.6.1 requires a change- and tamper-detection mechanism to alert personnel to modifications on payment pages. Requirement 12.3.2 requires a targeted risk analysis for customised approach controls. Multi-factor authentication requirements (Requirement 8) were expanded and are now mandatory for all non-console administrative access to the cardholder data environment, not just remote access. These are not aspirational changes — they were mandatory as of March 31, 2025.
Other Compliance Guides
ISO 27001 for Laravel Applications: Controls, Annex A, and What Developers Must Implement
ISO 27001:2022 defines 93 Annex A controls across four domains. This guide maps the technological controls that directly affect Laravel developers to specific implementations: access control, authentication, logging, cryptography, secure development, and continuous monitoring.
20 min readHIPAA Technical Safeguards for Laravel Applications Handling PHI
If your Laravel application stores or processes Protected Health Information, you need specific technical safeguards. This guide covers the HIPAA Security Rule requirements that PHP developers must implement, with Laravel-specific code examples.
22 min readSOC 2 Compliance for Laravel Applications: A Technical Implementation Guide
SOC 2 Type II compliance requires documented, auditable controls for security, availability, and confidentiality. This guide maps SOC 2 Trust Service Criteria to specific Laravel configurations and tells you exactly what evidence auditors will ask for.
Stay Updated on Laravel Security
Get actionable security tips, vulnerability alerts, and best practices for Laravel apps.