Network & Monitoring
Security Headers Grader
Grade HTTP security headers (HSTS, CSP, XFO, and more) for any URL from the edge
Fetch any URL from Cloudflare's edge and score its security headers with pass/warn/fail guidance.
Features
- Grades HSTS, CSP, clickjacking protection,
X-Content-Type-Options,Referrer-Policy,Permissions-Policy, andCross-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
GET /grade
Prop
Type
Example Request
curl "https://your-worker.workers.dev/grade?url=https://www.cloudflare.com"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
{
"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
400- Missing or invalidurl(INVALID_URL)502- Fetch failed (FETCH_ERROR)
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
- 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
Use in your project
Copy these files into an existing Worker. Prefer Deployment to try the full experiment first. Source: apps/experiments/security-headers-grader.
DependenciesNoneBindingsNonePlatformFetch API
import { FETCH_TIMEOUT_MS, USER_AGENT } from "../constants/defaults";import { headersToRecord } from "./url";export type FetchHeadersResult = | { ok: true; url: string; headers: Record<string, string>; method: "HEAD" | "GET" } | { ok: false; error: string };function shouldRetryWithGet(status: number): boolean { return status === 405 || status === 501 || status === 400 || status === 403;}async function fetchWithMethod( url: string, method: "HEAD" | "GET", signal: AbortSignal): Promise<Response> { return fetch(url, { method, redirect: "follow", signal, headers: { "User-Agent": USER_AGENT }, });}/** * Fetches response headers using HEAD, falling back to GET when needed. */export async function fetchResponseHeaders(url: string): Promise<FetchHeadersResult> { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS); try { let method: "HEAD" | "GET" = "HEAD"; let response = await fetchWithMethod(url, method, controller.signal); if (shouldRetryWithGet(response.status)) { method = "GET"; response = await fetchWithMethod(url, method, controller.signal); } clearTimeout(timeoutId); return { ok: true, url: response.url || url, headers: headersToRecord(response.headers), method, }; } catch (e) { clearTimeout(timeoutId); const message = e instanceof Error ? e.message : "Unknown error"; return { ok: false, error: message }; }}Deployment
Deploy
Follow the deployment wizard. No bindings or secrets required.
Test your deployment
curl "https://your-worker.workers.dev/grade?url=https://example.com"Local Development
cd apps/experiments/security-headers-grader
npm install
npm run devcurl "http://localhost:8787/grade?url=https://www.cloudflare.com"Cloudflare Features Used
- Workers - Edge compute runtime
- Fetch API - HEAD/GET requests from the edge
- Edge network - Low-latency header inspection