pqcheck 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,12 +14,17 @@ That's it. No install. Works from any terminal with Node 18+.
14
14
 
15
15
  `pqcheck` scans any HTTPS domain and computes its **Decryption Blast Radius Score** — the first continuous metric for harvest-now-decrypt-later (HNDL) risk. Every other TLS scanner answers "is post-quantum cryptography enabled?" with a yes/no. `pqcheck` answers the question that actually matters: *if an adversary harvests this traffic today and decrypts it in 2035, how much past + future data unlocks?*
16
16
 
17
- The score combines:
17
+ The score combines (Quantum / cert findings — our differentiator):
18
+ - **Public-key reuse across rotations** — detects when the same private key has been live across multiple cert renewals (often 4+ years at large enterprises). **★ Unique to pqcheck — no other ASM/TLS scanner surfaces this.**
18
19
  - **Cipher-class probing** — does the server accept RSA fallback even if it prefers ECDHE?
19
20
  - **Certificate chain analysis** — including the intermediate cert (the chain's actual quantum failure point)
20
- - **Public-key reuse across rotations** — detects when the same private key has been live across multiple cert renewals (often 4+ years at large enterprises)
21
21
  - **Subject scale** — wildcard certs and subdomain count multiplying the blast radius
22
22
 
23
+ Plus a full ASM check suite for credibility (so the report doesn't feel narrow):
24
+ - **Email security** — SPF, DMARC, DKIM (15 selectors probed), BIMI
25
+ - **HTTP header security** — HSTS (with preload + max-age), CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, COOP, CORP
26
+ - **Subdomain takeover detection** — fingerprint-based scan against AWS S3, GitHub Pages, Heroku, Shopify, Fastly, and 5+ other commonly-orphaned services
27
+
23
28
  ## Example
24
29
 
25
30
  ```
@@ -83,6 +88,15 @@ The `--threshold` flag turns `pqcheck` into a quantum-risk gate for any pipeline
83
88
 
84
89
  If the score is 7.0 or higher, the step fails and the PR can't merge.
85
90
 
91
+ For GitHub Actions specifically, there's also a [first-class action](https://github.com/mzon7/quantapact/tree/main/action) with `score` / `grade` / `report-url` outputs:
92
+
93
+ ```yaml
94
+ - uses: mzon7/quantapact/action@main
95
+ with:
96
+ domain: mycompany.com
97
+ threshold: '7'
98
+ ```
99
+
86
100
  For finer control, combine `--quiet` with shell logic:
87
101
 
88
102
  ```bash
package/bin/pqcheck.js CHANGED
@@ -7,7 +7,7 @@
7
7
  // =============================================================================
8
8
 
9
9
  const API_BASE = process.env.PQCHECK_API_BASE || "https://quantapact.com";
10
- const VERSION = "0.2.0";
10
+ const VERSION = "0.3.0";
11
11
 
12
12
  const ANSI = {
13
13
  reset: "\x1b[0m",
@@ -131,16 +131,47 @@ function printReport(r) {
131
131
  console.log(` • HSTS: ${r.publicSurface.hsts ? color("green", "enabled") : color("dim", "not detected")}`);
132
132
  console.log(` • Subdomains: ${r.publicSurface.subdomainCount}${r.publicSurface.wildcardCert ? color("yellow", " (wildcard cert)") : ""}`);
133
133
  console.log("");
134
+ // Coverage line — communicates breadth of checks
135
+ const coverage = ["TLS", "Cert chain", "Cipher class", color("violet", "★ Key reuse (CT-log)"), "Subdomains"];
136
+ if (r.emailSecurity) coverage.push("SPF", "DMARC", "DKIM", "BIMI");
137
+ if (r.httpHeaders && r.httpHeaders.reachable) coverage.push("HSTS", "CSP", "X-Frame", "Referrer-Policy");
138
+ if (r.subdomainTakeover) coverage.push("Takeover");
139
+ console.log(color("dim", " Checked: ") + coverage.join(color("dim", " · ")));
140
+ console.log("");
141
+
134
142
  if (r.findings && r.findings.length) {
135
- console.log(color("dim", " Findings:"));
143
+ // Group findings by category. Quantum/cert findings come first since
144
+ // they're the differentiator; ASM-completeness findings come after.
145
+ const groups = { quantum: [], takeover: [], email: [], headers: [], other: [] };
136
146
  for (const f of r.findings) {
137
- const sev = f.severity.toUpperCase();
138
- const sevColor =
139
- f.severity === "critical" ? "red" :
140
- f.severity === "high" ? "yellow" :
141
- f.severity === "medium" ? "yellow" : "dim";
142
- console.log(` ${color(sevColor, `[${sev}]`)} ${f.title}`);
143
- console.log(color("dim", ` ${f.detail}`));
147
+ const t = (f.title || "").toLowerCase();
148
+ if (/spf|dmarc|dkim|bimi/.test(t)) groups.email.push(f);
149
+ else if (/hsts|csp|x-frame|content-?type|referrer|clickjacking|server version|permissions-policy/.test(t)) groups.headers.push(f);
150
+ else if (/takeover/.test(t)) groups.takeover.push(f);
151
+ else if (/key reused?|key persist|reused for|cert rotation|chain weakest|rsa fallback|ecdhe|quantum/.test(t)) groups.quantum.push(f);
152
+ else groups.other.push(f);
153
+ }
154
+ const sections = [
155
+ ["quantum", "Quantum & cert exposure (our differentiator):", groups.quantum],
156
+ ["takeover", "Subdomain takeover:", groups.takeover],
157
+ ["email", "Email security (SPF / DMARC / DKIM / BIMI):", groups.email],
158
+ ["headers", "HTTP header security:", groups.headers],
159
+ ["other", "Other:", groups.other],
160
+ ];
161
+ for (const [key, label, arr] of sections) {
162
+ if (!arr || arr.length === 0) continue;
163
+ console.log(color("violet", ` ${label}`));
164
+ for (const f of arr) {
165
+ const sev = f.severity.toUpperCase();
166
+ const sevColor =
167
+ f.severity === "critical" ? "red" :
168
+ f.severity === "high" ? "yellow" :
169
+ f.severity === "medium" ? "yellow" : "dim";
170
+ const isUnique = key === "quantum" && /key reused?|reused for|key persist/.test((f.title || "").toLowerCase());
171
+ const star = isUnique ? color("violet", " ★ UNIQUE TO PQCHECK") : "";
172
+ console.log(` ${color(sevColor, `[${sev}]`)} ${f.title}${star}`);
173
+ console.log(color("dim", ` ${f.detail}`));
174
+ }
144
175
  }
145
176
  console.log("");
146
177
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pqcheck",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Decryption Blast Radius scanner — find out how much of your data unlocks when quantum decryption arrives.",
5
5
  "keywords": [
6
6
  "post-quantum",