PCI-DSS 4.0 Req 4.2.1 prohibits transmitting PANs over end-user messaging technologies or unprotected open networks; Req 4.1 requires a targeted risk analysis for any TLS configuration below 1.2. Transmitting cardholder data over HTTP or TLS 1.0/1.1 exposes it to BEAST, POODLE, and CRIME class attacks — protocol-level attacks that allow passive decryption. CWE-319 (Cleartext Transmission) is exploitable at any network vantage point on the path. OWASP A02 (Cryptographic Failures) and NIST SC-8 both require encryption in transit as a baseline control. Incomplete enforcement — HSTS present but no redirect from port 80 — leaves a real downgrade path.
Critical because cardholder data sent over unencrypted or downgraded TLS connections can be intercepted in transit by any network-position attacker, directly violating PCI-DSS 4.0 Req 4.2 and exposing PANs.
Enforce HTTPS at the infrastructure layer, not just in application code. Set HSTS with a max-age of at least 31536000 and add an explicit HTTP-to-HTTPS redirect so there is no cleartext fallback path. For Next.js on Vercel, add to next.config.js:
const securityHeaders = [
{ key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' }
];
For nginx, set ssl_protocols TLSv1.2 TLSv1.3; and include a listen 80 block that returns 301 before any content is served. Use Let's Encrypt via Certbot or your hosting provider's managed certificates (AWS ACM, Vercel auto-TLS) for automatic renewal — manual certificates expire silently.
ID: ecommerce-pci.cardholder-data.tls-enforced
Severity: critical
What to look for: Count all TLS/HTTPS enforcement signals across the project. Check for at least 1 of: HSTS header configuration (Strict-Transport-Security), HTTP-to-HTTPS redirect middleware, ssl_protocols directive in nginx/proxy config, or hosting platform HTTPS enforcement (vercel.json, netlify.toml). Count certificate management references (certbot, acme, Let's Encrypt, ACM). Enumerate all reverse proxy or load balancer configs and check TLS version settings.
Pass criteria: At least 2 of the following TLS enforcement signals are present: (1) HSTS header with max-age of at least 31536000, (2) HTTP-to-HTTPS redirect in middleware or proxy, (3) ssl_protocols TLSv1.2 TLSv1.3 or equivalent in proxy config, (4) hosting platform with automatic HTTPS (Vercel, Netlify). Certificate management is in place (at least 1 reference to auto-renewal or managed certificates). Report the count of enforcement signals found.
Fail criteria: Fewer than 2 TLS enforcement signals found, or TLS version explicitly allows < 1.2, or certificates are self-signed without documented understanding of risk.
Skip (N/A) when: Project is development-only (no deployment config, no hosting platform config, no payment routes) or uses no network communication.
Detail on fail: Specify the TLS issue. Example: "Only 1 TLS signal found (HSTS header). No HTTP-to-HTTPS redirect configured. TLS enforcement incomplete." or "Reverse proxy in nginx.conf accepts TLS 1.0 via ssl_protocols TLSv1 TLSv1.1 TLSv1.2"
Remediation: Enforce HTTPS site-wide. For Next.js on Vercel:
// vercel.json
{
"env": {
"NEXT_PUBLIC_ENFORCE_HTTPS": "true"
},
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Strict-Transport-Security",
"value": "max-age=63072000; includeSubDomains; preload"
}
]
}
]
}
For Express/Node:
app.use((req, res, next) => {
if (req.header('x-forwarded-proto') !== 'https') {
res.redirect(`https://${req.header('host')}${req.url}`);
} else {
next();
}
});
// Or use middleware like helmet
import helmet from 'helmet';
app.use(helmet.hsts({ maxAge: 63072000 }));
For nginx:
server {
listen 80;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_certificate /etc/ssl/certs/cert.pem;
ssl_certificate_key /etc/ssl/private/key.pem;
}
Use Let's Encrypt (via Certbot) or your hosting provider's managed certificates (Vercel, AWS ACM) for automatic renewal.