Network & Monitoring
Security Headers Grader
Grade HTTP security headers (HSTS, CSP, X-Frame-Options, and more) for any URL - security header audit 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