Blog: Hardening Calmony Pay with HTTP Security Headers
Hardening Calmony Pay with HTTP Security Headers
v1.0.23 · Infrastructure Security · SEC-12
Payment APIs are high-value targets. Even when the business logic is solid, missing HTTP response headers can hand an attacker a surprisingly cheap set of footholds — MIME confusion, frame injection, or a plain HTTP request smuggled past TLS. In v1.0.23 we closed all of those gaps at the infrastructure layer.
What we shipped
A single configuration change to next.config.ts now emits five security headers on every response from the Calmony Pay API:
// next.config.ts (simplified)
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=()',
},
],
},
];
},
Header by header
Strict-Transport-Security
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
This is the most critical header for a payment API. HSTS tells browsers to refuse any non-HTTPS connection for the next two years (63,072,000 seconds). The includeSubDomains directive extends that guarantee to every subdomain. The preload flag opts the domain into browser-vendor HSTS preload lists, meaning protection applies even on a user's very first request — before they have ever seen an HSTS response.
Without HSTS, SSL-stripping attacks on public Wi-Fi can silently downgrade an HTTPS session to HTTP, exposing API keys and card data in transit.
X-Frame-Options
X-Frame-Options: DENY
Prevents any page served by Calmony Pay from being embedded in a <frame>, <iframe>, or <object>. Clickjacking attacks work by placing a transparent iframe over a legitimate page and tricking users into clicking UI elements they cannot see. For a payment flow, this could be used to capture card submissions. DENY is the most restrictive value and is appropriate for an API that has no legitimate embedding use-case.
X-Content-Type-Options
X-Content-Type-Options: nosniff
Instructs browsers not to guess the MIME type of a response — they must use exactly what the server declares in Content-Type. Without this, a browser might interpret a JSON API response containing angle brackets as HTML and execute embedded scripts, a vector sometimes called content-type confusion XSS.
Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin
Controls what ends up in the Referer header when the API responds with a redirect or when a browser navigates away. With strict-origin-when-cross-origin, only the origin (scheme + host + port) is sent for cross-origin requests — never the full path or query string. This prevents internal route names, API paths, or any query parameters from leaking to third-party analytics or CDN logs.
Permissions-Policy
Permissions-Policy: camera=(), microphone=(), geolocation=()
Explicitly disables access to the device camera, microphone, and geolocation APIs for every browsing context served by the API. This is a defence-in-depth measure: even if a script injection were to occur, it could not silently access hardware sensors.
Compliance context
The HSTS and X-Frame-Options controls are directly relevant to PCI-DSS requirements around data transmission security and UI redress protection. The full set also satisfies the default findings of common automated security scanners (OWASP ZAP, Qualys SSL Labs, Mozilla Observatory), reducing noise in penetration-test reports.
Verifying the headers
You can inspect the headers on any API response with curl:
curl -I https://api.calmonypay.com/
Or check the full security score on Mozilla Observatory.
This change is part of the ongoing SEC control implementation track. No API behaviour was modified; this is a pure infrastructure hardening release.