HardStacked
Share:

HTTP headers · security grades

Microsoft scores an F, my blog scores an A: what a security grade really measures

2026-07-20 · HardStacked · 7 min read

On July 20, 2026 we ran three domains through securityheaders.com, the free scanner that grades a site's HTTP response headers from A+ down to F. The results, in order: microsoft.com got an F. facebook.com got an A. And this blog, a static site with no team, no budget and no backend, also got an A.

The tempting headline is « small blog beats Microsoft at security ». That headline is wrong, and the ways in which it is wrong are more useful than the grades themselves. Each of those three letters has a reason behind it, and none of the reasons is « this company forgot ».

1. The badge measures one axis, not your security

First, what the scanner actually does. It sends one request and reads the response headers: Content-Security-Policy, Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy. Six lines of text the server attaches to every page it serves. That is the entire exam.

It does not test whether the server is patched. It does not see the authentication, the firewall, the internal network, the people, or what happens after you log in. A site can serve six perfect headers in front of an unpatched application, and a site with an F can sit on an infrastructure your bank would envy. The grade measures the headers axis, all of the headers axis, and nothing but the headers axis.

So no, our A does not mean this blog is « more secure » than Microsoft. It means something narrower and still interesting: on this one measurable axis, the giant fails, and understanding why tells you how the web is actually built.

The habit

When someone shows you a security badge, any badge, ask what axis it measures before you let it impress you. A grade you cannot explain is marketing; a grade you can explain is data.

2. Why microsoft.com fails: the F is a business decision

Microsoft employs some of the best security engineers alive. Their homepage still serves no Content-Security-Policy worth grading. How?

Load microsoft.com with the network tab open and count what arrives: telemetry, advertising tags, A/B testing frameworks, multiple CDNs, embedded widgets. Dozens of scripts from dozens of third-party domains, managed by different teams on different release cycles. A strict CSP is a whitelist: every one of those sources would have to be enumerated, kept current, and would break the page the day a marketing team adds a tag the security team never heard about.

Faced with that, the owners of a marketing homepage make a rational call: no strict CSP. The F is not ignorance. It is the visible cost of a page built on dozens of third parties, accepted by people who decided the tracking stack was worth more than the header. You will find the same F on a large share of the corporate web, for the same reason.

The habit

Read an F on a giant as a compromise, not a scandal. But read an F on a security vendor's own site as a real signal: this is the one industry where the compromise is the message.

3. Why facebook.com passes: nonces, the trick a static site cannot copy

Facebook's homepage carries as many scripts as Microsoft's, yet it serves a strict CSP and earns its A. The difference is a mechanism called a nonce, and it only works if your pages are generated by a server, per request.

On every single page load, the server invents a fresh random token and does two things with it: it stamps the token on every legitimate script tag, and it announces the same token in the CSP header.

# regenerated on every request, different every time Content-Security-Policy: script-src 'nonce-8Kfx2mQ...' <script nonce="8Kfx2mQ..."> ... </script> ← runs: token matches <script> evil() </script> ← blocked: no token

The browser executes only the scripts wearing today's token. A script injected by an attacker was not there when the server stamped the page, so it carries no nonce and dies silently. The whitelist problem disappears: you no longer enumerate trusted domains, you mark trusted scripts, thousands of them if needed. Meta was one of the earliest large-scale CSP deployments, and this machinery is what their grade rests on.

The catch: a nonce must be unique per request, which requires a backend rendering each page. A static site like this one serves the same bytes to everyone; a « static nonce » would be a password taped to the door. Whatever a static site does, it will be a different path, which brings us to ours. But first, the most interesting line in Facebook's scan.

4. The header Facebook will not tighten, and why

Scan facebook.com and look past the grade at the detail: the weak spot is Referrer-Policy, the header that controls how much of the current URL leaks to the next site you click through to. This blog serves strict-origin-when-cross-origin; Facebook's policy is looser. The engineers who built the nonce machinery above could obviously ship a strict referrer policy before lunch.

They have not, and the likely reason is not technical. The referrer is attribution data: it tells the destination which page, which link, which campaign produced the click. For an advertising business, that data is not exhaust, it is inventory. A strict referrer policy would burn a little of their own product to buy a little of your privacy. We cannot see Meta's internal decisions from the outside; we can observe which header stayed loose at a company with every resource to tighten it, and that the loose one is the header their business model feeds on.

This is the actual lesson of the whole exercise: a site's security posture reflects its incentives at least as much as its competence. Microsoft's F is the cost of a tracking stack. Facebook's A stops exactly where the ad business begins. And a site with no data to sell can afford strictness everywhere, for free.

The habit

Before judging a site's configuration, ask what its owner earns from the gaps. A weak header at a company that profits from the weakness is not an oversight, and no audit will « fix » it.

5. How a static site earns an honest A

Our A costs one file. Cloudflare Pages, like most static hosts, reads a _headers file at the root of the deployment and attaches its lines to every response. Ours declares the six headers, and you can check what any site really serves, including this one, from any terminal:

$ curl -sI https://hardstacked.net | grep -iE 'security|frame|referrer|permissions|content-type-o' strict-transport-security: max-age=31536000; includeSubDomains content-security-policy: default-src 'self'; ... permissions-policy: camera=(), microphone=(), geolocation=(), ... referrer-policy: strict-origin-when-cross-origin x-content-type-options: nosniff x-frame-options: DENY

The reason the CSP can be strict is that the site is boring, in the best sense: no CDN, no external fonts, no tag manager, the fonts embedded in one CSS file, the favicon inlined. Almost everything resolves to 'self'. The two exceptions are earned and explicit: the contact form posts to its relay, and the analytics beacon reports home. Nothing else gets in.

One honest limit: our CSP allows 'unsafe-inline' scripts, because the page carries two small inline scripts and no backend to stamp nonces on them. That single allowance is what separates our A from an A+. The A+ route for a static site is hashing every inline script into the header, and every future edit to a script silently breaks the page until the hash is recomputed. For a site maintained by hand, we chose the grade that survives its owner: a durable A over a fragile A+.

The habit

If your site is static, the F-to-A trip is one file and one afternoon, and the largest part of the work is knowing exactly what your pages load. Inventory first, whitelist second, then let the browser console tell you what you missed.

Four ways to read a security grade

  1. Know the axis. The badge grades response headers, nothing else. Never quote it as a verdict on a site's overall security, yours or anyone's.
  2. Grade the incentives, not just the site. An F on a marketing giant is a compromise; an A that stops at the ad-revenue header is a business model showing through.
  3. Match the mechanism to the architecture. Nonces need a backend; static sites whitelist. Copying a giant's CSP onto the wrong architecture just breaks pages.
  4. Prefer the grade you can maintain. A durable A beats a fragile A+ the day you edit a script and forget the hash. These letters also expire: our three scans are dated July 20, 2026, and big sites change their headers, so re-scan before you quote anyone's grade, including ours.

What the three grades say together

One scanner, one afternoon, three letters: an F that is really a business decision, an A built on machinery a small site cannot copy, with a hole shaped exactly like an ad model, and an A that costs one file because the site behind it has nothing to sell but its configuration. The letters are shallow. The reasons are the whole story, and the reasons are always the same question: who profits from this gap staying open?

The deeper lesson

We are a security shop, so our incentives point the same way yours do: nothing we sell depends on your configuration staying weak. That alignment is exactly what the big platforms cannot offer, and it is verifiable, not a slogan. Scan hardstacked.net yourself, right now, on the same scanner.

The same philosophy drives HardVps: it applies a reviewed hardening baseline to your server, captures every original file first, and verifies any restore byte-exact by SHA-256. Strictness you can roll back is strictness you will actually deploy.

See what HardVps does →

On a Raspberry Pi? Start free with audit-pi, our open-source security audit.

Share: