# Security headers

> Check a site's HTTP security headers, see how each header is scored and what the A+ to F grade means, and fix the common findings.

Source: https://docs.vigilbase.com/tools/security-headers

The Security Headers Checker fetches a URL and grades the HTTP security headers in its response: Content-Security-Policy, Strict-Transport-Security, X-Frame-Options and seven more. It is non-intrusive and needs no sign-up. Run it at [vigilbase.com/tools/security-headers](https://vigilbase.com/tools/security-headers).

## Run a check

:::steps
1. **Enter a URL or domain.** If you leave out the scheme, `https://` is assumed.
2. **Complete the security check** and run the scan.
3. **Read the result.** Each header shows its value, a status and a recommendation.
4. **Email the report, optionally.** Enter a work email under the result. See [Report by email](https://docs.vigilbase.com/tools#report-by-email).
:::

The scanner reads the final response. If the site answers with a bot verification challenge or an HTTP error status, the check stops and assigns no grade.

## How each header is scored

Each header gets a score out of 10 and a weight. A missing header scores 0.

| Header | Weight | Full marks | Points lost |
| --- | --- | --- | --- |
| Content-Security-Policy | 20 | A policy with no weaknesses | `'unsafe-eval'` 4, `'unsafe-inline'` for scripts 3, a script wildcard `*` 2, `data:` in script sources 2, no `default-src` 1, no `frame-ancestors` 1 |
| Strict-Transport-Security | 20 | `max-age` of a year or more with `includeSubDomains` and `preload` | `max-age` under a year 3, and under a day 3 more; no `includeSubDomains` 1; no `preload` 1 |
| X-Frame-Options | 10 | `DENY` (10) or `SAMEORIGIN` (9) | `ALLOW-FROM` scores 6; another value scores 2 |
| X-Content-Type-Options | 10 | `nosniff` | Another value scores 2 |
| Referrer-Policy | 10 | `no-referrer` (10) or `strict-origin-when-cross-origin` (9) | Other strict values score 8; `unsafe-url` and `no-referrer-when-downgrade` score 5 |
| Permissions-Policy | 10 | Present, starting at 8 | Allowing `camera` or `microphone` for every origin 2 each, `geolocation` 1 |
| Cross-Origin-Opener-Policy | 5 | `same-origin` (10) | `same-origin-allow-popups` scores 8, `unsafe-none` 4 |
| Cross-Origin-Embedder-Policy | 5 | `require-corp` (10) | `credentialless` scores 8, `unsafe-none` 4 |
| Cross-Origin-Resource-Policy | 5 | `same-origin` (10) | `same-site` scores 9, `cross-origin` 5 |
| X-XSS-Protection | 5 | Not set, or `0` | `1; mode=block` scores 8 |

X-XSS-Protection is deprecated, so leaving it out is the recommended state and counts as full marks. For Permissions-Policy, the older `Feature-Policy` header is read when Permissions-Policy is absent.

A CSP weakness counts only when it affects scripts: `'unsafe-inline'` in `style-src` does not, and `'unsafe-inline'` is ignored when the same directive has a nonce, a hash or `'strict-dynamic'`, as browsers do. When a site sends several CSP headers, a script weakness counts only if every policy allows it.

## How the grade is calculated

The weighted header scores add up to a score out of 100.

| Grade | Score |
| --- | --- |
| A+ | 90 or more |
| A | 80-89 |
| B | 65-79 |
| C | 50-64 |
| D | 35-49 |
| F | Below 35 |

Findings get a severity from the header's importance: a missing CSP or HSTS header is high, a missing X-Frame-Options, X-Content-Type-Options, Referrer-Policy or Permissions-Policy is medium, and the cross-origin headers are low.

The status is **Vulnerable** for grade F or more than three high-severity findings, **Warnings** for grade C or D or any high-severity finding, and **Secure** otherwise.

## Fix common findings

:::accordion
### Content-Security-Policy missing
Add a policy with `default-src` as a fallback and `frame-ancestors`. Start as `Content-Security-Policy-Report-Only` to test it. The [CSP generator](https://docs.vigilbase.com/tools/csp) builds one.

### Content-Security-Policy contains 'unsafe-inline' or 'unsafe-eval'
Replace `'unsafe-inline'` with nonces or hashes, and remove `'unsafe-eval'`. The [CSP evaluator](https://docs.vigilbase.com/tools/csp) explains each weakness in detail.

### Strict-Transport-Security missing or short
Send `Strict-Transport-Security: max-age=31536000; includeSubDomains` once every subdomain serves HTTPS. Check preload readiness with the [HSTS checker](https://docs.vigilbase.com/tools/hsts-checker).

### X-Frame-Options missing
Send `X-Frame-Options: DENY`, or `SAMEORIGIN` if your own pages frame each other.

### X-Content-Type-Options missing
Send `X-Content-Type-Options: nosniff`.

### Referrer-Policy missing
Send `Referrer-Policy: strict-origin-when-cross-origin` or a stricter value.

### Permissions-Policy missing
Turn off features you do not use, for example `Permissions-Policy: camera=(), microphone=(), geolocation=()`.
:::

## Run it from code

The check is on the anonymous [Agent API](https://docs.vigilbase.com/tools/developers/agent-api) and in the [CLI](https://docs.vigilbase.com/tools/cli/commands):

```bash
npx @vigilbase/cli headers https://example.com
```
