Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Audit a target's HTTP security headers — CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, and the Cross-Origin trio (COOP, COEP, CORP). Use when: SOC2 / PCI auditor flagged "missing security headers" or a Mozilla Observatory grade is below B, OR you need HSTS preload eligibility for chrome://net-internals. Threshold: any missing required header on production HTML response, HSTS max-age below 31536000s (preload requirement), CSP with 'unsafe-inline' or 'uns
.claude/skills/jeremylongshore-checking-http-security-headers/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-09 | ✗→✓ | ▲ Improved | 23% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 94% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 29% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 17% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 4% | 0% |
HTTP response headers are the cheapest defense-in-depth layer most web apps ship. Each header closes one specific attack class — HSTS forces HTTPS, CSP blocks script injection, X-Frame-Options blocks clickjacking, etc. Missing headers don't break the app; they just leave the attack class open. This skill probes for the presence + value correctness of the canonical security-relevant headers.
| Finding | Severity | Threshold | Affected control | |---|---|---|---| | HSTS header missing | HIGH | No Strict-Transport-Security on HTTPS response | OWASP A05:2021 | | HSTS max-age below preload threshold | MEDIUM | max-age under 31536000s (1y) | hstspreload.org | | HSTS includeSubDomains missing for preload | LOW | preload directive without includeSubDomains | hstspreload.org | | CSP header missing | HIGH | No Content-Security-Policy header | OWASP A03:2021 | | CSP allows unsafe-inline | MEDIUM | script-src or style-src includes 'unsafe-inline' | OWASP A03:2021 | | CSP allows unsafe-eval | MEDIUM | script-src includes 'unsafe-eval' | OWASP A03:2021 | | CSP frame-ancestors AND X-Frame-Options both missing | HIGH | Clickjacking open | CWE-1021 | | X-Content-Type-Options:nosniff missing | MEDIUM | MIME-sniff attack open | OWASP A05:2021 | | Referrer-Policy missing or unsafe-url | MEDIUM | Cross-origin URL leakage | OWASP A05:2021 | | Permissions-Policy missing | LOW | Camera/mic/geo permissions unrestricted | Permissions Policy spec | | Server: header discloses version | LOW | nginx/1.18.0 → fingerprintable | CWE-200 | | Cache-Control public on authenticated response | HIGH | Shared cache may serve user A's response to user B | CWE-525 |
text"Do you have authorization to perform header testing on this target? I need confirmation before proceeding."
bashpython3 ${CLAUDE_PLUGIN_ROOT}/skills/checking-http-security-headers/scripts/check_headers.py \ https://example.com \ --authorized
Options:
Usage: check_headers.py URL [OPTIONS]
Options:
--authorized Attest authorization (required for non-local)
--output FILE
--format FMT json | jsonl | markdown (default: markdown)
--min-severity SEV (default: info)
--timeout SECS Per-probe timeout (default: 10)
--authenticated Treat as authenticated endpoint (stricter Cache-Control gate)HIGH = open exploitable class (no HSTS = MITM downgrade open; no CSP = XSS class wide open; no clickjacking guard = UI-redress attacks). MEDIUM/LOW = posture hardening.
auditing-cors-policy (#3) — CSP and CORSinteract; certain CSP directives need matching CORS headers.
references/PLAYBOOK.md § HSTSpreload checklist.
User: "Observatory gives us a D. What's missing?"
bashpython3 ${CLAUDE_PLUGIN_ROOT}/skills/checking-http-security-headers/scripts/check_headers.py \ https://example.com \ --authorized \ --format markdown
The Markdown report groups by severity; map each finding to the PLAYBOOK.md snippet for the target server type. Observatory grade typically moves D → B after addressing all HIGH findings.
User: "We want to submit to hstspreload.org. Is our HSTS config ready?"
bashpython3 ${CLAUDE_PLUGIN_ROOT}/skills/checking-http-security-headers/scripts/check_headers.py \ https://example.com \ --authorized --min-severity low
Look for "HSTS max-age below preload threshold" and "includeSubDomains missing" — both must clear before submission, OR hstspreload.org will reject.
User: "We had a Cache-Control bug last quarter where authenticated responses got cached publicly. Audit /api/ to make sure it's fixed."
bashpython3 ${CLAUDE_PLUGIN_ROOT}/skills/checking-http-security-headers/scripts/check_headers.py \ https://api.example.com/me \ --authorized --authenticated
The --authenticated flag bumps Cache-Control posture from MEDIUM to HIGH and adds a check for Cache-Control: public (forbidden on authenticated content).
JSON / JSONL / Markdown. Exit codes 0 / 1 / 2 per lib/report.py.
(JSON APIs use a subset of headers).
references/THEORY.md — Per-header reasoning, attack-class mappingreferences/PLAYBOOK.md — Config snippets per server type for eachrequired header
../analyzing-tls-config/references/AUTHORIZATION.md — Active-scanauthorization
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-09 | fail→pass | 9,919 | 3,934 | -60% | 1 | 1 | 0% | 1,655 | 2,032 | +23% | 0 | 0 | — |
case-01 | fail→fail | 8,767 | 13,006 | +48% | 1 | 1 | 0% | 774 | 3,317 | +329% | 0 | 0 | — |
case-02 | fail→fail | 18,893 | 13,312 | -30% | 1 | 1 | 0% | 1,384 | 2,750 | +99% | 0 | 0 | — |
case-03 | fail→fail | 13,901 | 11,530 | -17% | 1 | 1 | 0% | 807 | 2,105 | +161% | 0 | 0 | — |
case-04 | pass→pass | 9,137 | 7,416 | -19% | 1 | 1 | 0% | 1,808 | 2,606 | +44% | 0 | 0 | — |
case-05 | pass→pass | 14,106 | 7,208 | -49% | 1 | 1 | 0% | 1,311 | 2,494 | +90% | 0 | 0 | — |
case-06 | pass→pass | 12,222 | 5,642 | -54% | 1 | 1 | 0% | 1,901 | 1,881 | -1% | 0 | 0 | — |
case-07 | pass→pass | 23,827 | 5,763 | -76% | 1 | 1 | 0% | 2,095 | 2,313 | +10% | 0 | 0 | — |
case-08 | fail→pass | 19,883 | 11,465 | -42% | 1 | 1 | 0% | 1,366 | 2,644 | +94% | 0 | 0 | — |
case-10 | fail→pass | 9,044 | 2,502 | -72% | 1 | 1 | 0% | 1,374 | 1,777 | +29% | 0 | 0 | — |
case-11 | fail→pass | 8,980 | 2,734 | -70% | 1 | 1 | 0% | 1,446 | 1,699 | +17% | 0 | 0 | — |
case-12 | fail→pass | 10,016 | 2,558 | -74% | 1 | 1 | 0% | 1,673 | 1,740 | +4% | 0 | 0 | — |
case-13 | pass→pass | 11,850 | 2,043 | -83% | 1 | 1 | 0% | 1,237 | 1,639 | +32% | 0 | 0 | — |
case-14 | pass→pass | 11,841 | 5,838 | -51% | 1 | 1 | 0% | 1,950 | 2,167 | +11% | 0 | 0 | — |
case-15 | fail→fail | 9,721 | 13,019 | +34% | 1 | 1 | 0% | 745 | 2,735 | +267% | 0 | 0 | — |
case-16 | pass→pass | 15,101 | 4,730 | -69% | 1 | 1 | 0% | 2,655 | 1,766 | -33% | 0 | 0 | — |
case-17 | pass→pass | 10,050 | 2,635 | -74% | 1 | 1 | 0% | 1,715 | 1,778 | +4% | 0 | 0 | — |
case-18 | pass→pass | 12,766 | 7,269 | -43% | 1 | 1 | 0% | 2,241 | 2,053 | -8% | 0 | 0 | — |
case-19 | pass→pass | 11,815 | 3,385 | -71% | 1 | 1 | 0% | 2,152 | 1,872 | -13% | 0 | 0 | — |
case-20 | fail→fail | 20,231 | 9,730 | -52% | 1 | 1 | 0% | 1,986 | 2,903 | +46% | 0 | 0 | — |
case-21 | fail→fail | 7,430 | 6,349 | -15% | 1 | 1 | 0% | 1,296 | 2,381 | +84% | 0 | 0 | — |
case-22 | fail→fail | 8,931 | 8,619 | -3% | 1 | 1 | 0% | 1,475 | 2,747 | +86% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +23 percentage points is the difference between those two pass rates over the 22 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.