Question explained · gr.AI

Do security headers matter for AI visibility?

by Cătălin Popa · updated 2026-10-28

No. Nobody has ever shown that an AI engine prefers you because your security policies are configured correctly, and we are not going to pretend they are a ranking factor.

They are something else. A signal about who runs the site and how seriously, checkable by anyone in two seconds, without asking permission from anyone. And in the case of an agency selling technical audits, it is the first thing an informed client tests.

What they actually do, briefly

  1. 01

    Content-Security-Policy

    Tells the browser where it may load scripts, styles, images and fonts from. Anything not on the list does not run.

    Without it
    Any script slipped into the page, through a compromised plugin or an unsanitised field, runs with your full privileges.

  2. 02

    Strict-Transport-Security

    Forces the browser to use HTTPS for your domain, even if someone types the address without the s.

    Without it
    The first request goes out over HTTP and can be intercepted before the redirect.

  3. 03

    X-Frame-Options

    Stops another site from loading your pages in an invisible frame with its own buttons placed on top.

    Without it
    Someone can overlay your interface on theirs, and the user's clicks land wherever they want.

  4. 04

    X-Content-Type-Options

    Stops the browser guessing a file's type. If the server says it is an image, it stays an image.

    Without it
    A user-uploaded file declared as an image can be reinterpreted as a script.

  5. 05

    Referrer-Policy

    Limits how much of the current page's address travels onward when the user clicks through to another site.

    Without it
    Internal addresses, sometimes with identifiers in them, end up in someone else's logs.

  6. 06

    Permissions-Policy

    Explicitly closes what you do not use: camera, microphone, geolocation, payments, USB.

    Without it
    A third-party script can request permissions your site has no reason to touch.

Muzeul CFR, starting from “nothing loads from outside”

The strictest policy in the portfolio, and the simplest to explain. It starts with default-src 'none', which means that by default nothing is allowed to load. Then only what is needed is opened, one item at a time.

default-src 'none';
script-src 'self'; style-src 'self'; img-src 'self';
font-src 'self'; media-src 'self'; connect-src 'self';
frame-src https://www.openstreetmap.org;
base-uri 'none'; form-action 'none'; frame-ancestors 'self';
upgrade-insecure-requests

One single exception, for the OpenStreetMap map on the contact page. Otherwise scripts, styles, images and fonts come only from the site's own domain. form-action 'none' means no page can submit a form anywhere, which is correct for a site that has no forms.

Coral Baby, a single script allowed by fingerprint

Just as tight, with one difference worth explaining. The site needs an inline script, and instead of opening the gate for all inline scripts, the policy allows exactly one, identified by its cryptographic fingerprint.

script-src 'self' 'sha256-tHd4qJ0R/vQfI0CbRTiL3XGSi+Tun7VhOcDbx08aLKA='

Change one character in the script, the fingerprint no longer matches and the script no longer runs. The cost is that any change requires regenerating the fingerprint. The gain is that there is no side door through which a foreign script can execute.

What we fixed on our own site

Until 27 August 2026, gr-ai.ro had a single security header, and an incomplete one at that. We were asking clients for something we did not have ourselves.

HeaderBeforeNow
Content-Security-Policymissingfull policy
X-Content-Type-Optionsmissingnosniff
X-Frame-OptionsmissingSAMEORIGIN
Referrer-Policymissingstrict-origin-when-cross-origin
Cross-Origin-Opener-Policymissingsame-origin
Permissions-Policymissingcamera, microphone, geolocation, payments, USB
Strict-Transport-Securitymax-age onlyincludeSubDomains, preload
Access-Control-Allow-Origin* across the whole siteonly on /badge/

The last row is the one that bothered us most. Access-Control-Allow-Origin: * came from the platform, appeared on every response including robots.txt, and we had not put it anywhere in the code. It was not a security hole, because Access-Control-Allow-Credentials was missing, so it did not permit authenticated reads. It was simply visible sloppiness. Now it is narrowed down to /badge/, the only place it is genuinely needed, because the badge is loaded from client sites.

Why we did not go all the way

Our policy keeps 'unsafe-inline' on scripts and styles, which is weaker than what cezic.ro has. The explanation is not that we forgot.

The site is built on Next.js, which emits inline hydration scripts on every page. We counted twenty-two. The clean version requires a nonce generated on every request, and the nonce requires middleware. Middleware makes every request dynamic and loses the static cache the site's current speed depends on.

It would have meant trading a security improvement for a real speed regression, on a site that sells itself as fast and easy for machines to read. We chose to keep the weaker policy and write down why, instead of displaying a good score bought at a hidden cost.

On cezic.ro the problem does not arise, because there is no hydration there. A static site can have a clean script-src 'self'. A site with an application cannot, except at the cost described above.

How to check in two seconds, on any site

You need no tool at all. One command shows you everything a server sends, including your supplier's:

curl -sSI https://site-ul-tau.ro | grep -iE "content-security|strict-transport|x-frame|x-content|permissions-policy|referrer-policy"

Every missing line is a line of configuration nobody wrote. All six can be put in place in an afternoon and require no change to the site's content.

Share this article

Further reading