← Methodology library
Methodology · HTTP Posture Grade

An absolute grade for your HTTP security headers — not a drift check.

Cipherwake's Trust Diff catches what changed between deploys. The Posture Grade catches what was never set right in the first place. Strict SSL-Labs-style rubric, A+ → F, with the per-finding remediation copy your AI coder can paste directly.

1. What we measure

The posture grade evaluates the HTTP response headers your origin returns on a homepage GET / request. Specifically:

That's the entire scope. We do not grade TLS configuration here — TLS lives in the Decryption Blast Radius score. We do not grade headers on subpaths, only the apex homepage response. If a header is set on /app but not /, we grade the / response.

2. How we measure it

One HTTPS request to https://<domain>/ using the SSRF-pinned safeHttpsFetch helper (same redirect-loop pattern used across Cipherwake probes; max 2 redirects, https-only, cycle detection). Response headers are parsed via lib/httpHeaders.ts, which has been GPT-R10 adversarially reviewed for CSP directive-aware parsing (specifically: directive splitting, source-list parsing, and the frame-ancestors / X-Frame-Options overlap).

The grade is computed deterministically by lib/postureGrade.ts. There is no LLM in the path — every grade is reproducible from the response headers alone. The same input always produces the same output.

3. How it scores

Each finding has a fixed deduction. Deductions sum, then a threshold ladder converts the total to a letter:

Per-finding deductions

FindingDeductionWhy this weight
Content-Security-Policy missing2.0The single biggest XSS-mitigation gap; no browser-level fence on inline scripts.
HSTS missing2.0First-request HTTPS downgrade vector; SSL-strip is trivial without HSTS.
CSP wildcard source (*)1.5Effectively no CSP — any host can load scripts. Worse than misconfigured.
CSP 'unsafe-inline'1.0Re-enables the XSS class CSP exists to block. Common in legacy migrations.
CSP 'unsafe-eval'1.0Re-enables eval()-class injection. Required by some bundlers; flag is honest signal.
HSTS max-age < 1 year1.0Short TTL means browser forgets HTTPS preference quickly; partial protection only.
X-Frame-Options missing (AND no CSP frame-ancestors)1.0Clickjacking unmitigated. Either header alone counts as covered.
X-Content-Type-Options missing1.0MIME-sniffing-driven XSS still possible in older browsers; cheap fix.
Referrer-Policy missing1.0Defaults leak full URL to third-party requests; PII exposure risk on URL-encoded params.
HSTS no preload directive0.5Pre-load list inclusion is the strongest form; valuable but not catastrophic without it.
Permissions-Policy missing0.5Lower-impact than CSP; restricts powerful browser APIs (camera, mic, geolocation).
x-powered-by header present0.5Tech-stack disclosure helps attacker target known CVEs. Cheap to strip.
server header reveals version0.5Same class as x-powered-by; bare product name is fine, version string is not.

Letter-grade thresholds

Total deductionsLetterDecisionMeaning
0A+passAll headers present, no unsafe directives, no leaks.
≤ 0.5ApassOne minor finding (e.g. missing Permissions-Policy or x-powered-by).
≤ 1.5BreviewOne real gap or several minor ones. Worth fixing, not catastrophic.
≤ 3.5CreviewMultiple real gaps, OR one critical header missing (CSP or HSTS alone).
≤ 6.5DblockBoth CSP and HSTS missing, OR equivalent severity, but at least one header is still working. AI coder should stop announcing.
> 6.5FblockEssentially no browser-level defenses. Most of the rubric failing.

Score field (0–100)

For convenience the grade also reports a posture_score between 0 and 100, computed as max(0, 100 - (deductions / 8.5) * 100). A+ = 100. The denominator 8.5 is the sum of every deduction that can fire when a site has the worst possible configuration — so the score is true partial credit. A site that has valid HSTS preload set but is missing CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and Permissions-Policy still scores in the high-20s (≈ 29), not zero — because the HSTS preload is posture work that was done correctly. The letter and decision are the load-bearing outputs; the score is the chart-it-over-time signal.

How ship_decision relates to posture (default vs --strict-posture)

The CIPHERWAKE_AI_GUARD_RESULT block emits four related fields:

The strict mode fixes what would otherwise be a footgun: a site with no drift since last scan but F-grade absolute posture would emit ship_decision=pass under the drift-only default, and an AI coder following the original protocol ("pass → announce") would ship an F-posture site. With --strict-posture, the same site emits ship_decision=block.

The reason --strict-posture is opt-in rather than the default: most AI-coded Next.js / Vite / SvelteKit deploys grade B/C/D out of the box (no explicit security headers shipped by the framework). Defaulting to worst-of-both would make the AI Coder Protocol stop + ask the user on every PR for stable sites that didn't get worse — friction tax without proportional safety win. The strict gate is the right behaviour for production-critical deploys, but it has to be opted into. New installs are encouraged to pass --strict-posture; existing integrations keep their drift-only semantic.

Calibration anchor (2026-06-03)

A representative deploy of socialideagen.vercel.app (a real AI-coded preview lacking the full posture surface) produces:

posture_grade=F
posture_score=8
posture_decision=block
posture_missing=csp,hsts,x_frame_options,x_content_type_options,referrer_policy
posture_leaks=x_powered_by
posture_findings_count=6
posture_fixes_count=1

This is the empirical lower-bar for "a brand-new Next.js deploy with no security work done." It informs the rubric calibration: a fresh-vanilla deploy lands at F, not at B/C. Customers landing at C or worse are not at parity with their framework's defaults — there is real fix work to do.

4. What this tool does NOT claim

5. Limitations + try it

Limitations

Try it

# From any terminal, no signup, no API key:
npx pqcheck deploy-check <your-domain> --ai

# The CIPHERWAKE_AI_GUARD_RESULT block at the end of stdout will include:
#   posture_grade=A+|A|B|C|D|F
#   posture_score=0..100
#   posture_decision=pass|review|block
#   posture_missing=<comma-separated header keys>
#   posture_leaks=<comma-separated leak keys>
#   posture_findings_count=N
#   posture_fixes_count=N
#   scope_note=ship_decision=pass means public trust surface stable. Does NOT verify app functionality.

Or scan any HTTPS domain to see the posture grade alongside the Decryption Blast Radius score:

npx pqcheck cipherwake.io

The fix snippets — what's in report.posture.fixes

Every JSON scan response includes report.posture.fixes — an array of ready-to-paste remediation snippets keyed to the findings actually triggered on your site. We ship templates for:

These are intended for AI-coder paste — your Claude Code / Cursor / Aider session reads posture_fixes_count from the guard block, fetches the report.posture.fixes array from the JSON, and applies the snippet that matches your detected stack. The snippets are versioned alongside this methodology page.

Lineage + relationship to other Cipherwake checks

The posture grade is the absolute counterpart to two existing checks:

A complete Cipherwake check on a deploy is: posture grade (absolute baseline) + trust diff (drift since last deploy) + DBR (TLS health) + optional Site Guards (config-driven runtime). Each surfaces a different failure mode.

Continuous monitoring — posture_regression + cert_expiring

For watched domains (Tier 2 monitoring), the server-side monitor cron emits two new alert types backed by this rubric:

These run via the existing alert delivery pipeline (email + webhook). The posture grade is what makes posture_regression meaningful — without an absolute rubric, "header drift" has no severity scale.

Changelog

Future rubric changes will be documented here with the same level of specificity. Customers who graded their site at A+ this week and find it has slipped to A in three months should be able to read this section and know exactly which header expectation tightened.