pqcheck 0.7.2 → 0.7.3
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 +165 -106
- package/bin/pqcheck.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,78 +1,139 @@
|
|
|
1
1
|
# pqcheck
|
|
2
2
|
|
|
3
|
-
> **
|
|
3
|
+
> **Decryption Blast Radius scanner** — find out how much of your data unlocks when quantum decryption arrives.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npx pqcheck
|
|
6
|
+
npx pqcheck stripe.com
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Zero install. Works in any terminal with Node 18+. Free, no signup, no API key.
|
|
10
|
+
|
|
11
|
+
The same scanner that powers [quantapact.com](https://quantapact.com), the browser extension, and the GitHub Action.
|
|
10
12
|
|
|
11
13
|
---
|
|
12
14
|
|
|
13
15
|
## What it does
|
|
14
16
|
|
|
15
|
-
`pqcheck` scans any HTTPS domain and computes its **Decryption Blast Radius
|
|
17
|
+
`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 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
18
|
|
|
17
19
|
The score combines (Quantum / cert findings — our differentiator):
|
|
18
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). **★ Unique to pqcheck — no other ASM/TLS scanner surfaces this.**
|
|
19
21
|
- **Cipher-class probing** — does the server accept RSA fallback even if it prefers ECDHE?
|
|
20
22
|
- **Certificate chain analysis** — including the intermediate cert (the chain's actual quantum failure point)
|
|
21
23
|
- **Subject scale** — wildcard certs and subdomain count multiplying the blast radius
|
|
24
|
+
- **Hybrid PQC TLS detection** — credits servers using `X25519MLKEM768` with a methodology-aware discount
|
|
22
25
|
|
|
23
|
-
Plus a full ASM check suite for credibility
|
|
24
|
-
- **Email security** — SPF, DMARC, DKIM (
|
|
25
|
-
- **HTTP header security** — HSTS (with preload + max-age), CSP, X-Frame-Options,
|
|
26
|
-
- **Subdomain takeover detection** — fingerprint-based scan against AWS S3, GitHub Pages, Heroku, Shopify, Fastly,
|
|
26
|
+
Plus a full ASM check suite for credibility:
|
|
27
|
+
- **Email security** — SPF, DMARC, DKIM (~30 selectors probed including Resend/Mailgun/SES/etc.), BIMI
|
|
28
|
+
- **HTTP header security** — HSTS (with preload + max-age), CSP, X-Frame-Options, Referrer-Policy, Permissions-Policy, COOP, CORP
|
|
29
|
+
- **Subdomain takeover detection** — fingerprint-based scan against AWS S3, GitHub Pages, Heroku, Shopify, Fastly, etc.
|
|
27
30
|
|
|
28
|
-
##
|
|
31
|
+
## Commands
|
|
29
32
|
|
|
30
33
|
```
|
|
31
|
-
|
|
34
|
+
npx pqcheck <domain> Scan + print human-readable report
|
|
35
|
+
npx pqcheck lock <domain> Generate quantapact.lock (QXM) committable manifest
|
|
36
|
+
npx pqcheck deps <domain> Scan all third-party origins on the page (supply-chain HNDL)
|
|
37
|
+
npx pqcheck diff <old.lock> <new.lock> Compare two QXM lockfiles; exit 2 on regression
|
|
38
|
+
npx pqcheck history <domain> Show 90-day score history (sparkline + samples)
|
|
39
|
+
npx pqcheck cert <file.pem> Analyze a local PEM/CRT cert file (offline, no network)
|
|
40
|
+
```
|
|
32
41
|
|
|
33
|
-
|
|
34
|
-
─────────────────────────────────────
|
|
35
|
-
PUBLIC SURFACE BLAST RADIUS: 5.6 / 10 (MEDIUM)
|
|
42
|
+
### Multi-domain
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
• HSTS: not detected
|
|
42
|
-
• Subdomains: 47 (wildcard cert)
|
|
44
|
+
```
|
|
45
|
+
npx pqcheck a.com b.com c.com Multi-domain scan (positional)
|
|
46
|
+
npx pqcheck --file domains.txt Bulk scan from a newline-separated file (# comments allowed)
|
|
47
|
+
```
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
[HIGH] Same RSA-2048 key reused for 4.2 years across 3 cert rotations
|
|
46
|
-
[HIGH] ECDHE-only — quantum-vulnerable key exchange
|
|
47
|
-
[MED] Wildcard cert spans 47 subdomains
|
|
49
|
+
### Output formats
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
| Format | Use case |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `--format text` *(default)* | Human-readable terminal output |
|
|
54
|
+
| `--format json` (or `--json`) | Raw JSON for piping; NDJSON for multi-domain |
|
|
55
|
+
| `--format markdown` | GitHub-issue / Slack-ready Markdown |
|
|
56
|
+
| `--format csv` | Spreadsheet-friendly CSV row |
|
|
57
|
+
| `--format sarif` | SARIF 2.1.0 for upload to GitHub Code Scanning |
|
|
58
|
+
| `--gh-action` | GitHub Actions `::notice/::warning/::error` annotations |
|
|
51
59
|
|
|
52
|
-
|
|
53
|
-
If quantum decryption arrives in 2030–2040, harvested traffic from
|
|
54
|
-
chase.com (US banks) would unlock 4.2 years of session data, across
|
|
55
|
-
47 subdomains under one wildcard cert.
|
|
60
|
+
### Common flags
|
|
56
61
|
|
|
57
|
-
|
|
58
|
-
|
|
62
|
+
| Flag | Purpose |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `-h`, `--help` | Show help |
|
|
65
|
+
| `-v`, `--version` | Show version |
|
|
66
|
+
| `--threshold <0-10>` | Exit 2 if score meets or exceeds this (CI gate) |
|
|
67
|
+
| `-q`, `--quiet` | Print only the numeric score |
|
|
68
|
+
| `--watch [seconds]` | Poll every N seconds (default 300) and report changes |
|
|
69
|
+
| `--webhook <url>` | POST scan results to a URL (one-shot or each watch tick) |
|
|
59
70
|
|
|
60
|
-
|
|
71
|
+
### Subcommand-specific flags
|
|
61
72
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
**`pqcheck deps`:**
|
|
74
|
+
- `--lock` — Also write `quantapact-deps.lock` + `.md`
|
|
75
|
+
- `-o <dir>` — Output directory for `--lock` files
|
|
76
|
+
- `--max=<N>` — Max third parties to scan (default 20)
|
|
77
|
+
- `--allowlist <file>` — Exit **3** if any third-party not in allowlist (CI vendor-risk gate)
|
|
78
|
+
|
|
79
|
+
**`pqcheck lock`:**
|
|
80
|
+
- `-o <dir>` — Output directory
|
|
81
|
+
- `--stdout` — Print JSON to stdout instead of writing files
|
|
82
|
+
|
|
83
|
+
**`pqcheck history`:**
|
|
84
|
+
- `--days <N>` — History window (default 90)
|
|
85
|
+
- `--json` — Raw JSON output
|
|
86
|
+
|
|
87
|
+
### Exit codes
|
|
88
|
+
|
|
89
|
+
| Code | Meaning |
|
|
90
|
+
|---|---|
|
|
91
|
+
| `0` | Success |
|
|
92
|
+
| `1` | Usage / network / scan error |
|
|
93
|
+
| `2` | Score met or exceeded `--threshold`, or `diff` detected regression |
|
|
94
|
+
| `3` | Allowlist violation (`pqcheck deps --allowlist`) |
|
|
95
|
+
|
|
96
|
+
## Examples
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Quick scan
|
|
100
|
+
npx pqcheck stripe.com
|
|
101
|
+
|
|
102
|
+
# CI gate — fail if score >= 7
|
|
103
|
+
npx pqcheck mybank.com --threshold 7
|
|
104
|
+
|
|
105
|
+
# Generate committable QXM lockfile (like SBOM, but for quantum exposure)
|
|
106
|
+
npx pqcheck lock mycompany.com
|
|
107
|
+
|
|
108
|
+
# Track posture changes in PRs by diffing lockfiles
|
|
109
|
+
npx pqcheck diff main.lock pr.lock
|
|
110
|
+
|
|
111
|
+
# Supply-chain HNDL — scan all third-party scripts/iframes on a page
|
|
112
|
+
npx pqcheck deps mycompany.com --lock
|
|
113
|
+
|
|
114
|
+
# Vendor-risk CI gate — fail PR if any third-party not in allowlist
|
|
115
|
+
npx pqcheck deps mycompany.com --allowlist allowed-vendors.txt
|
|
116
|
+
|
|
117
|
+
# Score history sparkline
|
|
118
|
+
npx pqcheck history mycompany.com
|
|
119
|
+
|
|
120
|
+
# Offline cert analysis (no network)
|
|
121
|
+
npx pqcheck cert ./mycert.pem
|
|
122
|
+
|
|
123
|
+
# Bulk scan from list, NDJSON output
|
|
124
|
+
npx pqcheck --file domains.txt --format json > scans.ndjson
|
|
125
|
+
|
|
126
|
+
# Upload findings to GitHub Code Scanning
|
|
127
|
+
npx pqcheck mybank.com --format sarif > pqcheck.sarif
|
|
128
|
+
|
|
129
|
+
# GitHub Actions inline PR annotations
|
|
130
|
+
npx pqcheck mybank.com --gh-action
|
|
131
|
+
|
|
132
|
+
# Watch mode — poll, alert via webhook on change
|
|
133
|
+
npx pqcheck mybank.com --watch 600 --webhook https://hooks.slack.com/...
|
|
73
134
|
```
|
|
74
135
|
|
|
75
|
-
### QXM — Quantum Exposure Manifest
|
|
136
|
+
### QXM — Quantum Exposure Manifest
|
|
76
137
|
|
|
77
138
|
Like SBOM, `package-lock.json`, or `cargo audit` outputs — track quantum exposure as a versioned artifact in your repo. Diffs surface real changes in pull requests.
|
|
78
139
|
|
|
@@ -83,97 +144,95 @@ npx pqcheck lock yourcompany.com
|
|
|
83
144
|
# quantapact-report.md — human-readable summary (renders on GitHub)
|
|
84
145
|
```
|
|
85
146
|
|
|
86
|
-
Commit both files.
|
|
147
|
+
Commit both files. Use `npx pqcheck diff old.lock new.lock` in CI to surface regressions in PR comments.
|
|
87
148
|
|
|
88
|
-
|
|
149
|
+
Schema documented at [quantapact.com/schemas/qxm/v1](https://quantapact.com/methodology/qxm).
|
|
89
150
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
151
|
+
### Supply-chain dependency scanning
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npx pqcheck deps stripe.com
|
|
155
|
+
# Output: every third-party origin on stripe.com (analytics, CDN, fonts, etc.) graded for quantum risk
|
|
95
156
|
```
|
|
96
157
|
|
|
97
|
-
|
|
158
|
+
Add `--lock` to write `quantapact-deps.lock` + `.md` for committing or PR comparison. Add `--allowlist file.txt` to gate CI on vendor approval.
|
|
98
159
|
|
|
99
|
-
|
|
160
|
+
## Companion surfaces
|
|
100
161
|
|
|
101
|
-
|
|
102
|
-
|------|---------|
|
|
103
|
-
| 0 | Success — score below threshold (or no threshold set) |
|
|
104
|
-
| 1 | Usage / network / scan error |
|
|
105
|
-
| 2 | Score met or exceeded `--threshold` |
|
|
162
|
+
This CLI is one of four ways to consume the [Decryption Blast Radius API](https://quantapact.com/api):
|
|
106
163
|
|
|
107
|
-
|
|
164
|
+
| Surface | Where |
|
|
165
|
+
|---|---|
|
|
166
|
+
| **CLI** (this package) | `npx pqcheck` |
|
|
167
|
+
| **Browser extension** | Chrome Web Store / Firefox AMO / Edge — toolbar badge per tab + dependency analysis |
|
|
168
|
+
| **GitHub Action** | [`quantapact/pqcheck/action@main`](https://github.com/quantapact/pqcheck/tree/main/action) — PR comments, SARIF upload, lockfile generation |
|
|
169
|
+
| **Slack `/pqcheck`** | [Install on workspace](https://quantapact.com/install-slack) |
|
|
170
|
+
| **Web** | [quantapact.com](https://quantapact.com) — share-friendly URLs at `/r/<domain>` |
|
|
108
171
|
|
|
109
|
-
|
|
172
|
+
## Public API
|
|
110
173
|
|
|
111
|
-
|
|
112
|
-
# .github/workflows/quantum-risk-gate.yml
|
|
113
|
-
- name: Check public-surface quantum-decryption risk
|
|
114
|
-
run: npx pqcheck mycompany.com --threshold 7
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
If the score is 7.0 or higher, the step fails and the PR can't merge.
|
|
174
|
+
`pqcheck` is a wrapper around the public Quantapact API. You can also call the API directly:
|
|
118
175
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
```yaml
|
|
122
|
-
- uses: mzon7/quantapact/action@main
|
|
123
|
-
with:
|
|
124
|
-
domain: mycompany.com
|
|
125
|
-
threshold: '7'
|
|
176
|
+
```bash
|
|
177
|
+
curl -s "https://www.quantapact.com/api/scan?domain=stripe.com" | jq '.grade, .score'
|
|
126
178
|
```
|
|
127
179
|
|
|
128
|
-
|
|
180
|
+
Full API reference at [quantapact.com/api](https://quantapact.com/api).
|
|
129
181
|
|
|
130
|
-
|
|
131
|
-
SCORE=$(npx pqcheck mybank.com --quiet)
|
|
132
|
-
echo "Public surface blast radius: $SCORE / 10"
|
|
133
|
-
```
|
|
182
|
+
**Rate limit:** ~60 requests/minute per IP. No API key required. Returns HTTP 429 if exceeded — back off and retry.
|
|
134
183
|
|
|
135
|
-
|
|
184
|
+
## Methodology
|
|
136
185
|
|
|
137
|
-
|
|
138
|
-
npx pqcheck mybank.com --format json | jq '.findings[] | select(.severity=="high")'
|
|
139
|
-
```
|
|
186
|
+
Decryption Blast Radius scoring methodology is fully open. Component weights, PQC discount math, the "what we DON'T claim" sections, edge cases — all documented:
|
|
140
187
|
|
|
141
|
-
|
|
188
|
+
- [Decryption Blast Radius](https://quantapact.com/methodology/decryption-blast-radius) — core methodology
|
|
189
|
+
- [Score components](https://quantapact.com/methodology/score-components) — the 4-bar weighted breakdown + PQC discount
|
|
190
|
+
- [QXM lockfile schema](https://quantapact.com/methodology/qxm) — committable manifest format
|
|
191
|
+
- [Browser extension methodology](https://quantapact.com/methodology/browser-extension) — supply-chain HNDL detection logic
|
|
192
|
+
- [Methodology library](https://quantapact.com/methodology) — full index
|
|
142
193
|
|
|
143
|
-
|
|
194
|
+
## Versioning + stability
|
|
144
195
|
|
|
145
|
-
|
|
196
|
+
We don't break the API contract. New fields are added; old fields are preserved. If we ever need a breaking change, it ships at `/api/v2/scan` with a deprecation timeline.
|
|
146
197
|
|
|
147
|
-
|
|
198
|
+
The CLI follows the same policy — output formats are stable across minor versions.
|
|
148
199
|
|
|
149
|
-
|
|
200
|
+
## Privacy
|
|
150
201
|
|
|
151
|
-
-
|
|
152
|
-
- US Healthcare Systems (20 peers)
|
|
153
|
-
- Major SaaS / Cloud Platforms (30 peers)
|
|
154
|
-
- US Federal Government (25 peers)
|
|
155
|
-
- Major EU & UK Banks (25 peers)
|
|
156
|
-
- US Defense Contractors (15 peers)
|
|
157
|
-
- Global Automakers (15 peers)
|
|
158
|
-
- Global News & Media (15 peers)
|
|
159
|
-
- US Telecom & ISPs (15 peers)
|
|
160
|
-
- US Airlines (10 peers)
|
|
161
|
-
- UK Government & Public Services (15 peers)
|
|
202
|
+
`pqcheck` sends the domain you scan to `quantapact.com/api/scan` (so the TLS handshake can be performed from the public internet). No other data is sent — no email, no client-side identifier. The server logs anonymized analytics: domain, hashed IP (for rate limiting), user-agent. We don't track individual users across scans. See [quantapact.com/privacy](https://quantapact.com/privacy).
|
|
162
203
|
|
|
163
|
-
|
|
204
|
+
## CI integration
|
|
164
205
|
|
|
165
|
-
|
|
206
|
+
```yaml
|
|
207
|
+
# .github/workflows/quantum-risk-gate.yml
|
|
208
|
+
- name: Quantapact public-surface gate
|
|
209
|
+
run: npx pqcheck@latest mycompany.com --threshold 7
|
|
210
|
+
```
|
|
166
211
|
|
|
167
|
-
|
|
212
|
+
For richer integration (sticky PR comments, SARIF upload to Code Scanning, lockfile diff on regression), use the [GitHub Action](https://github.com/quantapact/pqcheck/tree/main/action):
|
|
168
213
|
|
|
169
|
-
|
|
214
|
+
```yaml
|
|
215
|
+
- uses: quantapact/pqcheck/action@main
|
|
216
|
+
with:
|
|
217
|
+
domain: mycompany.com
|
|
218
|
+
threshold: '7'
|
|
219
|
+
comment-on-pr: 'true'
|
|
220
|
+
generate-sarif: 'true'
|
|
221
|
+
- uses: github/codeql-action/upload-sarif@v3
|
|
222
|
+
with:
|
|
223
|
+
sarif_file: pqcheck-results.sarif
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Disclaimer
|
|
170
227
|
|
|
171
|
-
`pqcheck`
|
|
228
|
+
`pqcheck` measures only the **public** surface of a domain — what's observable from the open internet. Internal Blast Radius (east-west traffic, internal databases, VPN tunnels, backup pipelines) is typically 12–40× the public score depending on sector. A passing public-surface grade does **not** mean low internal exposure.
|
|
172
229
|
|
|
173
230
|
## License
|
|
174
231
|
|
|
175
232
|
MIT. © 2026 Quantapact.
|
|
176
233
|
|
|
177
|
-
|
|
234
|
+
---
|
|
178
235
|
|
|
179
|
-
|
|
236
|
+
**Source:** [github.com/quantapact/pqcheck](https://github.com/quantapact/pqcheck) *(public, pending org transfer to `quantapact/pqcheck`)*
|
|
237
|
+
|
|
238
|
+
**Issues / feedback:** [quantapact.com/feedback](https://quantapact.com/feedback) or open an issue on the repo.
|
package/bin/pqcheck.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pqcheck",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
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",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"bugs": "https://quantapact.com",
|
|
22
22
|
"repository": {
|
|
23
23
|
"type": "git",
|
|
24
|
-
"url": "https://github.com/
|
|
24
|
+
"url": "https://github.com/quantapact/pqcheck.git",
|
|
25
25
|
"directory": "cli"
|
|
26
26
|
},
|
|
27
27
|
"license": "MIT",
|