# Security Headers Grader (/docs/experiments/security-headers-grader)



Fetch any URL from Cloudflare's edge and score its security headers with pass/warn/fail guidance.

## Features [#features]

* Grades HSTS, CSP, clickjacking protection, `X-Content-Type-Options`, `Referrer-Policy`, `Permissions-Policy`, and `Cross-Origin-Opener-Policy`
* Returns a numeric score (0–100) and letter grade (A–F)
* Uses HEAD with GET fallback when origins reject HEAD
* Stateless; no bindings required

## API Reference [#api-reference]

### GET /grade [#get-grade]

<TypeTable
  type="{
  url: {
    description: &#x22;The target URL (must be http or https)&#x22;,
    type: &#x22;string&#x22;,
    required: true,
  },
}"
/>

#### Example Request [#example-request]

```bash
curl "https://your-worker.workers.dev/grade?url=https://www.cloudflare.com"
```

#### Success Response [#success-response]

**`url`** `string`

Final URL after redirects

**`score`** `number`

Average score from 0–100 across all checks

**`grade`** `string`

Letter grade: `A`, `B`, `C`, `D`, or `F`

**`checks`** `array`

Per-header results with `header`, `status` (`pass` | `warn` | `fail` | `missing`), `detail`, and `recommendation`

**`headers`** `object`

Raw response headers as lowercase key/value pairs

```json
{
  "url": "https://www.cloudflare.com/",
  "score": 71,
  "grade": "C",
  "checks": [
    {
      "header": "Strict-Transport-Security",
      "status": "pass",
      "detail": "max-age=31536000; includeSubDomains; preload",
      "recommendation": "Looks good"
    }
  ],
  "headers": {
    "strict-transport-security": "max-age=31536000; includeSubDomains; preload"
  }
}
```

#### Error Codes [#error-codes]

* `400` - Missing or invalid `url` (`INVALID_URL`)
* `502` - Fetch failed (`FETCH_ERROR`)

## Use Cases [#use-cases]

* Audit security headers before launching a site
* Compare header posture across environments
* Teach Workers fetch + header analysis patterns
* Generate actionable remediation tips for missing headers

## Limitations [#limitations]

* Scoring is heuristic, not a formal compliance audit
* Does not execute or fully validate CSP policy correctness
* Only inspects response headers visible to the edge fetch

## Deployment [#deployment]

<Steps>
  <Step>
    ### Click the deploy button [#click-the-deploy-button]

    [![Deploy to Cloudflare Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/shrinathsnayak/cloudflare-experiments/tree/main/apps/experiments/security-headers-grader)
  </Step>

  <Step>
    ### Deploy [#deploy]

    Follow the deployment wizard. No bindings or secrets required.
  </Step>

  <Step>
    ### Test your deployment [#test-your-deployment]

    ```bash
    curl "https://your-worker.workers.dev/grade?url=https://example.com"
    ```
  </Step>
</Steps>

## Local Development [#local-development]

```bash
cd apps/experiments/security-headers-grader
npm install
npm run dev
```

```bash
curl "http://localhost:8787/grade?url=https://www.cloudflare.com"
```

## Cloudflare Features Used [#cloudflare-features-used]

* **[Workers](https://developers.cloudflare.com/workers/)** - Edge compute runtime
* **[Fetch API](https://developers.cloudflare.com/workers/runtime-apis/fetch/)** - HEAD/GET requests from the edge
* **[Edge network](https://developers.cloudflare.com/workers/reference/how-workers-works/)** - Low-latency header inspection

## Next Steps [#next-steps]

<Cards>
  <Card title="Response Headers" href="/docs/experiments/response-headers">
    Dump raw response headers without scoring
  </Card>

  <Card title="CORS Preflight Tester" href="/docs/experiments/cors-preflight-tester">
    Simulate browser CORS preflight OPTIONS requests
  </Card>
</Cards>
