HRPQ lets one origin require post-quantum TLS. Cookies don't stop at the origin,
they're scoped to the whole registrable domain. hrpq-gap-scan finds
the sibling subdomains, missing headers, and enterprise TLS proxies that turn
that mismatch into a real downgrade path, before an incident finds it for you.
A domain-scoped cookie set by a PQ-protected origin is still readable by, and overwritable by, any PQ-insecure sibling on the same registrable domain. Protecting one origin doesn't protect that origin's session state.
includeSubDomains is all-or-nothingSet it, and any subdomain that isn't PQ hybrid-capable hard-fails once HRPQ is enforced, no silent classical fallback. Leave it off, and the cookie-injection gap above stays open.
A proxy that terminates and re-originates TLS is its own migration target. Clients roaming between a proxied and unproxied network see connections fail and recover with no obvious explanation.
| Finding | Severity | Meaning |
|---|---|---|
hrpq-missing-includesubdomains |
HIGH | HRPQ set without includeSubDomains; siblings can still inject cookies into this origin's session state. |
includesubdomains-breaks-subdomain |
HIGH | includeSubDomains set, but a subdomain isn't PQ-capable and will hard-fail once HRPQ is enforced. |
cookie-injection-exposure |
HIGH | A domain-scoped cookie from a PQ-capable host is exposed to a non-PQ-capable sibling. |
proxy-downgrade-vector |
HIGH | A host negotiates PQ hybrid directly but not through an enterprise proxy path (via diff). |
no-pq-hybrid |
MEDIUM | Host negotiated a classical group; a downgrade pivot point until upgraded. |
unreachable |
LOW | Host couldn't be probed; verify manually. |
$ hrpq-gap-scan scan example.com --subdomains app.example.com legacy.example.com
hrpq-gap-scan report for example.com
============================================================
example.com: X25519MLKEM768 [PQ hybrid] max-age=31536000; includeSubDomains
app.example.com: X25519MLKEM768 [PQ hybrid] no HRPQ header
legacy.example.com: X25519 [classical] no HRPQ header
Findings (3):
[HIGH] legacy.example.com: example.com sets includeSubDomains, but
legacy.example.com does not negotiate a PQ hybrid group. Browsers
enforcing HRPQ have no silent classical fallback here.
[HIGH] example.com: Cookie 'session' is domain-scoped (Domain=.example.com)
and set by a PQ hybrid-capable host, but legacy.example.com on the
same registrable domain is not PQ hybrid-capable.
[MEDIUM] legacy.example.com: Negotiated group was 'X25519', a classical
group. This host is a viable downgrade pivot until upgraded.
$ hrpq-gap-scan scan example.com --subdomains-file subdomains.txt --json
{
"apex": "example.com",
"hosts": { "...": "..." },
"findings": [
{
"severity": "high",
"kind": "cookie-injection-exposure",
"host": "example.com",
"detail": "Cookie 'session' is domain-scoped (Domain=.example.com) ..."
}
]
}
$ hrpq-gap-scan scan example.com --json > direct.json # outside the proxy
$ hrpq-gap-scan scan example.com --json > via_proxy.json # inside the proxied network
$ hrpq-gap-scan diff direct.json via_proxy.json
Proxy vantage-point differences (1):
[HIGH] app.example.com: app.example.com negotiates a PQ hybrid group
directly but the proxied path resolves to 'X25519'. The
TLS-inspecting proxy on this network path is the actual downgrade
vector, not the origin server.
pip install -e . from a clone of the repo. Requires OpenSSL 3.2+
on PATH. Full walkthrough and sample output in
examples/.