pqc-spotter scans a directory and reports every cryptographic library, primitive and dependency it can find — split into what stays safe against a quantum computer and what does not. One command, no dependencies, designed to run in CI.
$ curl -fsSL https://pqc-spotter.qcomply.tech/install.sh | sh
Three steps from nothing installed to a report on your own code.
The script downloads one self-contained file, verifies its checksum
and drops a pqc-spotter launcher into
~/.local/bin (or /usr/local/bin when run as
root). It installs no packages and touches nothing else.
$ curl -fsSL https://pqc-spotter.qcomply.tech/install.sh | sh
Prefer not to pipe a script into a shell? Read it first at /install.sh, or skip it entirely and use the zipapp shown in step 1b.
pqc-spotter.pyz is a single-file Python zipapp. Download it
and hand it to any Python 3.8 or newer. Useful in containers and on
machines where you would rather not write to PATH.
$ curl -fsSLO https://pqc-spotter.qcomply.tech/pqc-spotter.pyz $ python3 pqc-spotter.pyz .
Point it at any path. With no argument it scans the current directory. Vendored code, build output and version-control metadata are skipped automatically.
$ pqc-spotter /path/to/your/project
You get a summary by posture, an inventory of every algorithm found, the individual findings with file and line, and a single overall tier for the codebase. What the verdicts mean →
Nothing is executed. pqc-spotter reads files as text and matches them against a signature database. It never imports, builds or runs the code under scan, and it makes no network calls — so it is safe to point at a repository you do not trust.
Real output from the demo codebase bundled with the tool — a small polyglot project that deliberately contains every posture at once.
pqc-spotter v0.1.0 scanned 19 files in /home/ubuntu/qcomply/pqc-spotter/DEMO 0.01s SUMMARY -------------------------------------------------------------------- ! Quantum-vulnerable 31 ############## x Broken (classical) 11 ##### ~ Reduced margin 4 ## ? Needs review 24 ########### + Quantum-safe 20 ######### -------------------------------------------------------------------- Total findings 90 across 18 files CRYPTOGRAPHIC INVENTORY -------------------------------------------------------------------- ALGORITHM FAMILY USES VERDICT RSA public-key-encryption 5 Quantum-vulnerable X25519 key-exchange 4 Quantum-vulnerable ECDH key-exchange 3 Quantum-vulnerable ECDSA signature 3 Quantum-vulnerable Ed25519 signature 3 Quantum-vulnerable JWT signature 3 Quantum-vulnerable RSA/ECC library public-key-encryption 3 Quantum-vulnerable EC key-exchange 2 Quantum-vulnerable SSH key-material 2 Quantum-vulnerable X.509 signature 2 Quantum-vulnerable SSH key-exchange 1 Quantum-vulnerable SHA-1 hash 3 Broken (classical) DES symmetric-cipher 2 Broken (classical) ECB symmetric-cipher 2 Broken (classical) MD5 hash 2 Broken (classical) PRNG random 2 Broken (classical) AES symmetric-cipher 2 Reduced margin AES-128 symmetric-cipher 2 Reduced margin unidentified library 11 Needs review crypto library library 5 Needs review JWT signature 4 Needs review key-material key-material 2 Needs review TLS protocol 1 Needs review X.509 signature 1 Needs review KDF kdf 7 Quantum-safe SHA-2 hash 5 Quantum-safe AES-256 symmetric-cipher 2 Quantum-safe Hybrid KEM key-exchange 2 Quantum-safe PQC library library 2 Quantum-safe ML-DSA signature 1 Quantum-safe ML-KEM key-exchange 1 Quantum-safe WHAT TO DO -------------------------------------------------------------------- Ed25519 Move signatures to ML-DSA (FIPS 204). Where signature size matters more than verification cost, consider FN-DSA; for firmware and other long-lived roots of trust, SLH-DSA (FIPS 205) or LMS/XMSS. RSA/ECC library Replace direct public-key encryption with ML-KEM (FIPS 203) key encapsulation plus an AEAD such as AES-256-GCM. SSH OpenSSH 9.x offers the hybrid sntrup761x25519-sha512 key exchange; enable it and prefer it in KexAlgorithms. X25519 Move key establishment to ML-KEM (FIPS 203), ideally as a hybrid with the existing group so interoperability is preserved. RSA Replace direct public-key encryption with ML-KEM (FIPS 203) key encapsulation plus an AEAD such as AES-256-GCM. ECDH Move key establishment to ML-KEM (FIPS 203), ideally as a hybrid with the existing group so interoperability is preserved. ==================================================================== VERDICT: QS-Preferred Post-quantum primitives are present alongside classical ones - a migration is under way but not finished. ====================================================================
Drop --quiet and each finding is listed with its file, line,
rule ID and the text that matched. Add --only vulnerable to
see just the part that needs migrating.
pqc-spotter v0.1.0 scanned 19 files in /home/ubuntu/qcomply/pqc-spotter/DEMO 0.01s SUMMARY -------------------------------------------------------------------- ! Quantum-vulnerable 31 ######################################## -------------------------------------------------------------------- Total findings 31 across 12 files CRYPTOGRAPHIC INVENTORY -------------------------------------------------------------------- ALGORITHM FAMILY USES VERDICT RSA public-key-encryption 5 Quantum-vulnerable X25519 key-exchange 4 Quantum-vulnerable ECDH key-exchange 3 Quantum-vulnerable ECDSA signature 3 Quantum-vulnerable Ed25519 signature 3 Quantum-vulnerable JWT signature 3 Quantum-vulnerable RSA/ECC library public-key-encryption 3 Quantum-vulnerable EC key-exchange 2 Quantum-vulnerable SSH key-material 2 Quantum-vulnerable X.509 signature 2 Quantum-vulnerable SSH key-exchange 1 Quantum-vulnerable QUANTUM-VULNERABLE (31) Broken by Shor's algorithm once a cryptographically relevant quantum computer exists. Data protected by these algorithms is also exposed retroactively to harvest-now-decrypt-later capture. ! Cargo.toml:8 [PQCS005] Edwards-curve signatures - matched 'ed25519' | ed25519-dalek = "2.1" ! Cargo.toml:8 [PQCS502] Classical asymmetric dependency - matched 'ed25519-dalek' | ed25519-dalek = "2.1" ! config/ssh_config:3 [PQCS012] Classical SSH host/user key - matched 'id_rsa' | IdentityFile ~/.ssh/id_rsa ! config/ssh_config:4 [PQCS006] Montgomery-curve key agreement - matched 'curve25519' | KexAlgorithms curve25519-sha256,ecdh-sha2-nistp256 ! config/ssh_config:5 [PQCS005] Edwards-curve signatures - matched 'ed25519' | HostKeyAlgorithms ssh-ed25519,ssh-rsa ... and 26 more (use --format json for the full list) WHAT TO DO -------------------------------------------------------------------- Ed25519 Move signatures to ML-DSA (FIPS 204). Where signature size matters more than verification cost, consider FN-DSA; for firmware and other long-lived roots of trust, SLH-DSA (FIPS 205) or LMS/XMSS. RSA/ECC library Replace direct public-key encryption with ML-KEM (FIPS 203) key encapsulation plus an AEAD such as AES-256-GCM. SSH OpenSSH 9.x offers the hybrid sntrup761x25519-sha512 key exchange; enable it and prefer it in KexAlgorithms. X25519 Move key establishment to ML-KEM (FIPS 203), ideally as a hybrid with the existing group so interoperability is preserved. RSA Replace direct public-key encryption with ML-KEM (FIPS 203) key encapsulation plus an AEAD such as AES-256-GCM. ECDH Move key establishment to ML-KEM (FIPS 203), ideally as a hybrid with the existing group so interoperability is preserved. ==================================================================== VERDICT: Classical-Only Only classical public-key cryptography was found. No post-quantum capability is present. ====================================================================
Every finding lands in one of five buckets. The split that matters for a post-quantum programme is the first two.
Broken by Shor's algorithm once a cryptographically relevant quantum computer exists: RSA, DSA, Diffie-Hellman and everything on elliptic curves — including Ed25519 and X25519. Traffic captured today is decryptable later, so this is the bucket to plan against.
ML-KEM, ML-DSA, SLH-DSA and FN-DSA (the NIST standards), hash-based signatures such as XMSS and LMS, and symmetric primitives that keep an adequate margin — AES-256, ChaCha20, SHA-2, SHA-3.
Survives, but Grover's algorithm halves the effective strength. AES-128 and short digests sit here. Not urgent — schedule them for the next parameter change rather than a redesign.
Already unsafe against ordinary attackers: MD5, SHA-1, DES, RC4, ECB mode. Quantum computers are irrelevant to these. Fix them regardless of any migration timeline.
Cryptography is clearly in use, but the evidence does not name a
primitive — a bare import crypto, an algorithm read from
config, a TLS client. These need a human, and the tool says so instead
of guessing.
Each scan also gets one verdict for the codebase as a whole, using the same vocabulary as the QComply network scanners so a repository and an endpoint can be described in the same words.
| Tier | Meaning |
|---|---|
QS-Only |
Every public-key primitive found is post-quantum. No classical asymmetric fallback remains in the source. |
QS-Preferred |
Post-quantum primitives are present alongside classical ones — a migration is under way but not finished. |
QS-Ready |
A post-quantum library is available to the project but nothing calls it yet, while classical public-key cryptography is still in use. |
Classical-Only |
Only classical public-key cryptography was found. No post-quantum capability is present. |
No-Crypto-Found |
No cryptographic evidence in the scanned files. |
pqc-spotter [PATH] [options] — PATH is the directory or file to scan, defaulting to the current directory.
| Option | Description |
|---|---|
-f, --format | text (default), json, sarif, cyclonedx, markdown |
-o, --output FILE | Write the report to a file instead of stdout. |
--fail-on LEVEL | Exit 1 when findings exist at vulnerable, broken, weak or any. Default never. |
--only POSTURES | Report only the listed postures, comma separated. Does not affect the exit code. |
-e, --exclude GLOB | Skip paths matching a glob. Repeatable. |
--no-default-excludes | Also scan node_modules, vendor, build output and similar. |
--include-hidden | Scan dotfiles and dot-directories. |
--follow-symlinks | Follow symlinked directories. |
--min-confidence | low, medium (default), high. Raise it to drop the noisier heuristics. |
--max-file-size BYTES | Skip files above this size. Default 2 MB. |
--max-per-group N | Findings shown per posture in text output. Default 10. |
-q, --quiet | Summary, inventory and verdict only. |
--color | auto, always, never. |
--list-rules | Print the rule database and exit. |
-V, --version | Print the version and exit. |
| Code | Meaning |
|---|---|
0 | The scan completed. This is the default whatever was found — pqc-spotter does not break your pipeline unless you ask it to. |
1 | Findings exist at or above --fail-on. |
2 | The scan itself failed: bad path, bad argument, unreadable target. |
textColoured terminal report. The default when stdout is a terminal; colour switches itself off when piped.
jsonFull result: summary, inventory and every finding with file, line, evidence and remediation. For dashboards and scripts.
sarifSARIF 2.1.0 for GitHub code scanning. Findings appear inline on the pull request that introduced them.
cyclonedxA CycloneDX 1.6 CBOM — a cryptographic bill of materials, one component per algorithm, for compliance evidence.
markdownTables suited to a CI job summary or a pull-request comment.
pqc-spotter .
pqc-spotter . -q
pqc-spotter src --only vulnerable
pqc-spotter . -f json -o pqc.json
pqc-spotter . -e 'tests/*' -e '*.min.js'
The scan exits 0 by default, so you can add it to an existing pipeline
today and see what it finds without breaking a build. Turn on
--fail-on when you are ready to hold the line.
name: post-quantum scan on: [push, pull_request] jobs: pqc-spotter: runs-on: ubuntu-latest permissions: security-events: write steps: - uses: actions/checkout@v4 - name: Install pqc-spotter run: curl -fsSL https://pqc-spotter.qcomply.tech/install.sh | sh - name: Scan run: ~/.local/bin/pqc-spotter . -f sarif -o pqc.sarif - uses: github/codeql-action/upload-sarif@v3 with: sarif_file: pqc.sarif
pqc-scan: image: python:3.12-slim before_script: - apt-get update && apt-get install -y curl script: # Report only, never fail the pipeline: - curl -fsSL https://pqc-spotter.qcomply.tech/install.sh | sh - ~/.local/bin/pqc-spotter . # When you are ready to enforce, add: # --fail-on vulnerable artifacts: paths: [pqc.json]
# Append a table to the GitHub job summary pqc-spotter . -f markdown >> $GITHUB_STEP_SUMMARY
# CycloneDX cryptographic bill of materials pqc-spotter . -f cyclonedx -o cbom.json # Pre-commit style gate on new legacy crypto pqc-spotter . --fail-on broken -q
Worth knowing before you read a report, so you spend your time on the findings that matter.
Whether a connection actually negotiates ML-KEM depends on the peer, the library build and the runtime configuration — none of which are visible in code. pqc-spotter flags TLS use and tells you to scan the endpoint.
If a cipher name arrives from a config file or an environment variable, the scanner reports "needs review" rather than guessing. Configurable defaults are a common place for legacy algorithms to survive.
MD5 used as a cache key is not a vulnerability. The report is an inventory to triage — the tool tells you where the cryptography is and what it would cost you, not that you have a bug.
Need the runtime half of the picture? QComply's network scanners probe live TLS and SSH endpoints for the post-quantum groups they actually negotiate, and report using the same tier vocabulary you see here. See qcomply.tech.