All 21 checks with why-it-matters prose, severity, and cross-references to related audits.
Without HTTPS enforcement, every byte transmitted between your server and the user travels in plaintext — session tokens, form fields, and API responses are readable by anyone on the same network. Man-in-the-middle attackers on public Wi-Fi can silently rewrite page content, inject scripts, or steal credentials before the user even knows they're on your site. PCI-DSS 4.0 Req 4.2.1 and NIST SP 800-53 SC-8 both mandate encrypted transport; a lapse here puts cardholder data directly in scope for a breach. OWASP A02 (Cryptographic Failures) flags unencrypted transport as the most straightforward path to data exposure.
Why this severity: Critical because unencrypted HTTP transmits credentials and session tokens in plaintext, enabling trivial interception on any shared network.
security-headers.transport.https-enforcedSee full patternHTTPS enforcement prevents plaintext connections, but HSTS goes further: it instructs the browser to refuse HTTP for your domain entirely for up to a year after the first visit, eliminating SSL-stripping attacks that can silently downgrade an HTTPS connection before the browser even sees it. Without a `max-age` of at least 31536000, an attacker who intercepts the first request can strip the redirect and operate in plaintext for every subsequent session. RFC 6797 defines the spec; OWASP A02 identifies the absence of HSTS as a cryptographic failure that enables credential theft.
Why this severity: High because a missing or short-lived HSTS header leaves the window open for SSL-stripping attacks that HTTPS redirects alone cannot prevent.
security-headers.transport.hsts-enabledSee full patternSession cookies without `Secure` can be transmitted over plain HTTP if a downgrade or redirect is ever triggered, handing an attacker the session token in cleartext. Cookies without `HttpOnly` are readable by any JavaScript on the page — a single XSS payload is enough to exfiltrate the token to an attacker-controlled server. Together, these two flags prevent the most common session-theft vectors. OWASP A05 (Security Misconfiguration) and A07 (Identification and Authentication Failures) both flag missing cookie security attributes as prerequisites for session hijacking. CWE-614 and CWE-1004 explicitly name the absence of `Secure` and `HttpOnly` as exploitable defects.
Why this severity: High because missing Secure or HttpOnly flags on session cookies are direct prerequisites for session hijacking via network interception or XSS.
security-headers.transport.secure-cookiesSee full patternWithout `SameSite`, browsers send cookies with every cross-origin request — including requests triggered by a third-party page that loads your API. This is the attack surface that CSRF exploits: an attacker's page silently fires a state-changing request (password change, fund transfer, account deletion) and the browser helpfully attaches the user's session cookie. `SameSite=Lax` blocks cookies on cross-origin subrequests while preserving top-level navigations; `Strict` blocks all cross-site cookie sending. OWASP A01 (Broken Access Control) and CWE-352 both identify missing SameSite as a direct enabler of CSRF attacks.
Why this severity: Medium because SameSite is a defense-in-depth CSRF control — missing it exposes state-changing endpoints to cross-site request forgery on browsers without default Lax behavior.
security-headers.transport.same-site-cookiesSee full patternWithout a Content-Security-Policy, any XSS vulnerability in your app becomes a full code execution primitive — injected scripts can exfiltrate cookies, keylog form inputs, or pivot to your users' other browser contexts. CSP is the browser-enforced last line of defense: even when input sanitization fails, a tight policy prevents injected scripts from loading external resources or executing inline. OWASP A03 (Injection) and A05 (Security Misconfiguration) both call out missing CSP as a critical gap; CWE-79 names the XSS class that a CSP directly mitigates. Without it, a single missed sanitization anywhere in your rendering pipeline becomes an account-takeover vector.
Why this severity: High because the absence of any CSP removes the last browser-enforced barrier against XSS exploitation, leaving injected scripts with unrestricted execution access.
security-headers.headers.csp-presentSee full pattern`'unsafe-inline'` in `script-src` means any `<script>` tag injected by an attacker — through XSS, a compromised third-party dependency, or a DOM mutation — runs with full page context. It effectively negates CSP's primary purpose: a policy exists but an XSS payload executes anyway. OWASP A03 (Injection) flags this as a common misconfiguration where developers add a CSP for compliance but inadvertently include `unsafe-inline` to silence warnings, creating a security theater scenario. CWE-79 (XSS) and CWE-1336 (improper neutralization) both apply. The correct fix — cryptographically random nonces per request — is supported natively by all major frameworks.
Why this severity: High because `unsafe-inline` in `script-src` defeats XSS protection even when a CSP is present, reducing it to security theater.
security-headers.headers.csp-no-unsafe-inlineSee full patternClickjacking embeds your app inside an attacker-controlled `<iframe>`, then overlays a transparent UI that tricks users into clicking buttons they can't see — authorizing transactions, enabling permissions, or deleting accounts on your behalf. The attack requires zero user credentials and is invisible to the victim. Without framing protection, any page on your site is a potential weapon: login buttons, payment confirmations, settings toggles. CAPEC-103 documents the attack pattern in detail. OWASP A05 identifies missing framing controls as a security misconfiguration. `X-Frame-Options: DENY` is a single-line fix that eliminates the entire attack surface.
Why this severity: Medium because clickjacking requires attacker-controlled page delivery but can silently authorize destructive actions on behalf of authenticated users.
security-headers.headers.x-frame-optionsSee full patternMIME-sniffing is the browser behavior where, if a server sends a response with a wrong or ambiguous `Content-Type`, the browser guesses what the content actually is and renders it accordingly. An attacker who can upload a file that looks like a script — even if it's served as `text/plain` — can trigger script execution if MIME-sniffing is allowed. CWE-430 (Deployment of Wrong Handler) and CWE-436 (Interpretation Conflict) both map to this class of confusion attack. The `nosniff` directive costs nothing to deploy and closes a class of content-confusion exploits that bypass file type restrictions on upload endpoints.
Why this severity: Medium because MIME-type confusion attacks require attacker-controlled file upload but can escalate to script execution if content-type handling is ambiguous.
security-headers.headers.x-content-typeSee full patternWithout `Referrer-Policy`, your full page URLs — including paths with user IDs, session tokens in query strings, or internal route names — are sent in the `Referer` header on every outbound link click, image load, and analytics request. This leaks internal URL structure to third-party analytics, ad networks, and CDNs. Under GDPR Article 5(1)(f), passing personally-identifiable URL fragments to third parties without consent is a data minimization violation. OWASP A01 (Broken Access Control) covers information leakage through ambient HTTP headers. CWE-200 (Exposure of Sensitive Information) directly maps to this pattern.
Why this severity: Medium because referrer leakage exposes internal URL structure and user-identifiable path data to third-party services on every navigation.
security-headers.headers.referrer-policySee full patternWithout `Permissions-Policy`, any JavaScript executing on your page — including third-party analytics scripts, embedded widgets, and compromised CDN assets — can request access to the user's camera, microphone, and geolocation without additional browser prompts. If an XSS payload fires or a third-party script is compromised, it can silently activate hardware sensors. CWE-732 (Incorrect Permission Assignment) and OWASP A05 (Security Misconfiguration) both apply to unrestricted browser API exposure. Restricting permissions you don't use follows the principle of least privilege: a payment app has no legitimate reason to access the gyroscope.
Why this severity: Low because exploiting unrestricted permissions requires additional code execution context, but the policy is trivial to add and eliminates unnecessary browser API surface.
security-headers.headers.permissions-policySee full patternWhen your app loads scripts from a CDN without Subresource Integrity hashes, you're trusting that the CDN will always serve exactly the file you expect. CDN compromises happen — an attacker who gains write access to a CDN bucket, a package registry, or a DNS record can replace `jquery.min.js` with a version that exfiltrates every form field on your page. OWASP A08 (Software and Data Integrity Failures) covers this supply chain vector directly. SLSA Level 2 requires artifact integrity verification. CWE-829 (Inclusion of Functionality from Untrusted Control Sphere) and CWE-494 (Download of Code Without Integrity Check) both map to external scripts without SRI.
Why this severity: Info because SRI primarily protects against CDN-level compromise, a low-frequency attack that requires third-party infrastructure control to exploit.
security-headers.headers.subresource-integritySee full patternWildcard CORS (`Access-Control-Allow-Origin: *`) allows any website on the internet to make authenticated API requests using the user's credentials. An attacker's page can silently read your API responses, trigger state-changing calls, and exfiltrate data — all without the user knowing. The impact depends on what your API does: for a read-only public API, wildcard CORS may be intentional; for an API that returns user data or modifies state, it is a critical data exposure. CWE-942 (Permissive Cross-domain Policy with Untrusted Domains) and OWASP A05 (Security Misconfiguration) directly apply. CWE-346 (Origin Validation Error) maps to the failure to validate the requesting origin.
Why this severity: Info because wildcard CORS becomes dangerous only when the API also handles authentication or returns user-specific data — context determines actual severity.
security-headers.headers.cors-configuredSee full patternStack traces returned to API clients expose the internal file system paths, dependency names and versions, function call chains, and sometimes SQL queries that make up your application's internals. Attackers use this reconnaissance to identify vulnerable libraries, understand data model structure, and craft targeted exploits. CWE-209 (Generation of Error Message Containing Sensitive Information) and CWE-200 (Exposure of Sensitive Information) directly describe this class of leak. OWASP A04 (Insecure Design) and A09 (Security Logging and Monitoring Failures) both apply. AI-generated codebases are particularly prone to this: the default catch-and-return-error pattern is the path of least resistance when the model is filling in error handling.
Why this severity: Critical because exposed stack traces provide attackers with dependency versions, file paths, and SQL structure — directly enabling targeted exploitation of known CVEs.
security-headers.info-exposure.no-stack-tracesSee full patternServer `X-Powered-By: Next.js` and `Server: nginx/1.24.0` headers hand attackers a pre-filled target list: they know your exact framework and server version without running a single probe, and can immediately cross-reference known CVEs. This is reconnaissance that costs the attacker nothing and costs you nothing to prevent. CWE-200 (Exposure of Sensitive Information) and CWE-497 (Exposure of System Data to Unauthorized Control Sphere) both apply. OWASP A05 (Security Misconfiguration) lists version disclosure as a baseline misconfiguration. Suppressing these headers doesn't fix vulnerabilities, but it eliminates passive fingerprinting and forces attackers to do active work.
Why this severity: Low because version disclosure is reconnaissance-only — it enables faster targeted attacks but does not directly enable exploitation on its own.
security-headers.info-exposure.no-server-versionSee full patternDefault framework error pages expose the framework name, version, and sometimes a stack trace to anyone who triggers a 404 or 500. Beyond information leakage, an app with no custom error pages signals to users (and attackers) that error cases were never designed — raising the question of what else was left to defaults. CWE-209 (Error Message With Sensitive Information) and CWE-756 (Missing Custom Error Page) both apply. OWASP A05 (Security Misconfiguration) identifies default error pages as a configuration gap. Custom error pages also prevent operational confusion: a customer who hits a raw framework 500 page is far more likely to churn than one who sees a branded, helpful message.
Why this severity: Low because default error pages primarily enable passive information gathering — the concrete risk depends on what the framework exposes in its defaults.
security-headers.info-exposure.custom-error-pagesSee full patternPublic source maps let anyone reconstruct your original pre-minified TypeScript or JavaScript from your production bundle — including business logic, API endpoint structure, internal variable names, comments, and any secrets that were inadvertently bundled. An attacker with your source maps can read your application as if they had access to your repository. CWE-540 (Inclusion of Sensitive Information in Source Code) and CWE-538 (File and Directory Information Exposure) both apply. OWASP A05 (Security Misconfiguration) lists public source maps as a common developer oversight. Next.js defaults to `productionBrowserSourceMaps: false` — enabling them is an explicit action that is easy to forget to revert after debugging.
Why this severity: High because publicly accessible source maps expose full application logic, comment strings, and internal structure — equivalent to open-sourcing your production code without intending to.
security-headers.info-exposure.no-source-mapsSee full patternA `.env` file committed to git is a permanent credential leak — even after deletion, the file lives in git history and is readable to anyone with repository access, including all future contributors, CI/CD systems, and anyone who ever clones the repo. Stripe keys, database passwords, and OAuth secrets committed to a private repo are exposed the moment the repo is accidentally made public or an employee account is compromised. OWASP A02 (Cryptographic Failures) covers secret exposure; CWE-540 and CWE-538 specifically address sensitive information in committed files. AI code generators routinely create `.env.local` files and forget to update `.gitignore`, making this one of the highest-frequency findings across AI-built projects.
Why this severity: High because secrets committed to git history are irrecoverable without rotation — a single accidental public repo exposure or account compromise exposes all credentials permanently.
security-headers.basic-hygiene.env-in-gitignoreSee full patternHardcoded secrets in source code are the most common high-severity finding in AI-built projects: the model fills in a working API key to make the code run, and the developer ships it without noticing. A Stripe secret key (`sk_live_`) hardcoded in `lib/stripe.ts` gives anyone with repo read access the ability to create charges, refund transactions, or read customer data. A hardcoded JWT secret lets an attacker forge authentication tokens. OWASP A07 (Identification and Authentication Failures) and CWE-798 (Use of Hard-coded Credentials) directly describe this class of defect. PCI-DSS 4.0 Req 8.6.2 explicitly prohibits hard-coded credentials in any system component. Secrets in git history must be rotated even after removal from the code — the history is permanent.
Why this severity: Critical because a hardcoded secret key gives anyone with repository read access full API-level access to the associated service, often with no rate limiting or geo restriction.
security-headers.basic-hygiene.no-hardcoded-secretsSee full patternDependencies that are multiple major versions behind their current release accumulate unpatched CVEs — many of them publicly documented with working exploits and CVSS scores above 9.0. React 16 shipped before multiple prototype pollution and XSS fixes present in React 18+; Next.js 10 predates authentication bypass fixes in later versions. OWASP A06 (Vulnerable and Outdated Components) is the top-ranked supply chain risk for web apps. CWE-1104 (Use of Unmaintained Third Party Components) and SSDF PW.4.1 (Identify and confirm vulnerabilities in software) directly apply. Known-compromised packages like `event-stream@3.3.6` are particularly dangerous because the malicious code runs in your build environment, not just at runtime.
Why this severity: High because critically outdated production dependencies carry known, publicly documented CVEs with working exploits that attackers can apply without any reconnaissance.
security-headers.basic-hygiene.dependency-auditSee full patternWithout a committed lock file, every deployment resolves dependency versions fresh from the registry. A package that satisfies `^1.2.3` today might resolve to `1.9.0` tomorrow after the maintainer pushes a new version — and if that version contains malicious code (as happened with `ua-parser-js`, `colors`, and `event-stream`), your production deployment installs it silently. OWASP A08 (Software and Data Integrity Failures) covers this class of dependency confusion. SLSA Level 1 requires pinned dependency declarations; SSDF PW.4.4 requires reproducible builds. CWE-829 (Inclusion of Functionality from Untrusted Control Sphere) maps to the scenario where a registry compromise affects your build.
Why this severity: Medium because missing lock files allow dependency version drift between deploys, creating a window for supply chain attacks during any deployment that resolves newer package versions.
security-headers.basic-hygiene.lockfile-presentSee full patternWithout a `security.txt`, researchers who discover vulnerabilities in your app have no official channel to report them — they either give up, post publicly, or sell the finding. RFC 9116 defines the standard that security teams, automated scanners, and responsible-disclosure platforms use to find contact information. ISO 27001:2022 A.5.5 includes coordinated vulnerability disclosure as a required control for information security management. A missing `security.txt` means a researcher who found your SQL injection is more likely to submit it to a bug bounty aggregator or post it to social media than reach you first — costing you the ability to patch quietly.
Why this severity: Info because the absence of security.txt does not create a vulnerability, but it eliminates the responsible-disclosure channel that lets you learn about real vulnerabilities before they're exploited.
security-headers.basic-hygiene.security-txtSee full patternRun this audit in your AI coding tool (Claude Code, Cursor, Bolt, etc.) and submit results here for scoring and benchmarks.
Open Security Headers & Basics Audit