1.What a security header is
When a browser opens your app, the server sends the page plus a few lines of extra information, such as “X-Frame-Options: DENY”. These lines are HTTP headers. Visitors never see them, but the browser reads every one.
A security header asks the browser to be stricter: run no scripts from unknown places, do not show this page inside another site, always use an encrypted connection. Without it, the browser uses a looser default, and nothing visibly breaks. Security headers protect your visitors in their browser. They do not protect your database.
2.The five headers that matter for a small app
MDN, Mozilla’s reference for web developers, rates each of these fixes for impact and difficulty.
| Header | What it blocks | MDN’s rating |
|---|---|---|
| Content-Security-Policy (CSP) | Scripts from places you did not list. If an attacker slips code into your page (cross-site scripting, or XSS), the browser refuses to run it. | High impact, high difficulty |
| frame-ancestors (part of CSP) or X-Frame-Options | Other sites showing your page inside a hidden frame to trick a signed-in user into clicking your buttons (clickjacking). | High impact, low difficulty |
| Strict-Transport-Security (HSTS) | Unencrypted visits. The browser remembers to use HTTPS for your domain and does not let users click past a certificate error. | High impact, low difficulty |
| X-Content-Type-Options: nosniff | The browser guessing a file’s type, so a file you serve as plain text cannot run as a page or a script. | Low impact, low difficulty |
| Referrer-Policy | Full page addresses leaking to other sites, with any private paths or codes in them. | Low impact, low difficulty |
Content-Security-Policy
CSP is the strongest of the five and the hardest to get right: a strict policy can block your own fonts, analytics or database calls until you list them. MDN advises testing a policy first with the Content-Security-Policy-Report-Only header, which reports problems instead of blocking. A CSP is a second layer of defense. It does not replace cleaning what users type. Each part of a CSP works on its own, so you can start with framing protection alone.
Framing protection
In clickjacking, another site loads your page in an invisible frame and puts its own button in the same place as one of yours, so the user’s click lands in your app, signed in as them. Without a header, the browser lets any site embed your page. MDN advises setting both frame-ancestors and X-Frame-Options, as real headers: frame-ancestors is not supported in a meta tag, and X-Frame-Options in a meta tag has no effect.
HSTS, nosniff and Referrer-Policy
HSTS makes the browser switch every visit to your domain to HTTPS, for as many seconds as its max-age says. Send it only when your whole site works on HTTPS.
X-Content-Type-Options has one value, nosniff, and MDN says all sites should send it. It matters most when users upload files: it stops an uploaded text file from running as a web page. See Can anyone upload files to your app at your cost?
Referrer-Policy decides how much of your page address other sites learn. Today’s default, strict-origin-when-cross-origin, tells them only your domain. The default was looser before, so set it yourself.
3.What CORS is, and the one mistake to avoid
Under the same-origin policy, a page from one origin (the protocol, domain and port, such as https://yourapp.com) cannot read answers from another. This stops a bad website from reading a user’s webmail while they are signed in.
CORS (Cross-Origin Resource Sharing) is how your server makes exceptions. The Access-Control-Allow-Origin header names the sites whose pages may read the answer. Access-Control-Allow-Credentials: true lets those pages read answers to requests that carry the user’s cookies.
The mistake: every site, with cookies
The value * (any site) does not work with cookies: the browser blocks the answer. One way around this is to copy back whatever origin the request names, and allow cookies. Then a page on any website can read what your app shows a signed-in user. MDN warns against exactly this. Its fix:
- If other sites must read your app with cookies, check the request’s origin against a fixed list and name only that site in the answer, with Vary: Origin, which tells caches that the answer depends on the asking site.
- If your data is public and needs no cookies, * is fine, without Access-Control-Allow-Credentials.
- Otherwise, send neither header.
Access-Control-Allow-Origin: https://www.yourapp.com
Access-Control-Allow-Credentials: true
Vary: OriginCORS is a browser rule, not a lock on your data. MDN describes CORS as the system that decides whether browsers block a page’s code from reading another site’s answers. A stranger does not need a browser. Our free check is a program on a server, and it found Tidybook’s reviews table open to anyone (below). Your database rules protect your data. See My Supabase public key is visible. Is that a problem?
4.How serious a missing header is
On 1 November 2026, LidTight’s free check ran on Tidybook, our demo app built with Lovable. It reported this finding as medium: “Some browser protections are switched off · Missing: content security policy, protection against framing”. Its note says these settings “are quick to turn on.”
The same run rated Tidybook’s reviews table critical: 12 rows with first names, emails and phone numbers, readable without signing in. An open table gives your customers’ data to anyone, today. A missing header leaves visitors open to tricks such as clickjacking, or removes a second layer against injected scripts. Fix your tables first (see What can a stranger see in your app?), then add the headers.
What the free check covers: it looks for HSTS, CSP, nosniff and framing protection on the page at the link you enter. It checks that each header is there, not how strict it is, and it skips Referrer-Policy. For CORS, it asks your page, and the read-only endpoints it finds in your code, as if from another website. It reports an app that copies that site back and allows cookies: high when the app signs in with cookies, low when it does not. The Tidybook run reported no CORS finding.
5.How to check your own site for free
- Open MDN HTTP Observatory, Mozilla’s free header checker, enter your app’s domain and click Scan. It gives a grade and a fix for each problem, with a link to MDN’s guide for it.
- Open your app in your browser and open the developer tools: Ctrl + Shift + I or F12 on Windows, ⌘ + ⌥ + I on a Mac.
- Click the Network tab and reload the page. The tools record requests only while they are open.
- Click the request for your page’s address, open the Headers tab and read Response Headers. Look for the five names above.
- If your app shows a CORS error, open the Console tab. MDN says only the console shows what went wrong.
- Run our free check to see the headers next to what matters more: open tables, secret keys in your code and files that should not be public.
Anyone can scan any domain with Observatory, and each domain’s scan history is public, its FAQ says. The same FAQ says an A+ grade does not mean a site is secure: Observatory does not test for things like outdated software or SQL injection.
6.How to set headers on your host
These are the hosts whose official docs we checked on 1 November 2026.
| Host | Where to set headers | Watch out |
|---|---|---|
| Netlify | A file named _headers in your publish folder, or a headers section in netlify.toml | Not applied to pages made by functions, such as server-rendered pages. Those must send their own headers. |
| Cloudflare Pages | A file named _headers in your static files folder, often public/ | Not applied to responses from Pages Functions or server-rendered frameworks. Set the headers in that code. |
| Vercel | A headers list in vercel.json | Applies to static files and functions, matched by path. |
A starting _headers file for Netlify or Cloudflare Pages:
/*
Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Strict-Transport-Security: max-age=63072000Its CSP line only controls who may frame your page, so it cannot block your scripts. Grow the policy later, with Report-Only first. To show your app inside another site of yours, list that site in frame-ancestors. The max-age value, two years, is the one MDN recommends.
Lovable hosting. We found no custom header setting in Lovable’s hosting, publishing and security docs. Lovable apps created from 13 May 2026 use server-side rendering, so if you move one to Netlify or Cloudflare Pages, set its headers in code, not only in _headers.
If you cannot set headers at all, a CSP can go in a meta tag. Framing protection cannot, so ask your host for it. For the rest of your launch checks, see Before you go live: a security checklist.