Post-quantum readiness · Static analysis

Find the cryptography
your codebase forgot about.

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.

Install (macOS, Linux, WSL)
$ curl -fsSL https://pqc-spotter.qcomply.tech/install.sh | sh
No runtime dependencies Python 3.8+ ~25 KB Nothing leaves your machine
Getting started

Up and running in under a minute

Three steps from nothing installed to a report on your own code.

Install the tool

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.

Or run it without installing anything

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 .

Scan a directory

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

Read the verdict

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.

Example

What a scan looks like

Real output from the demo codebase bundled with the tool — a small polyglot project that deliberately contains every posture at once.

pqc-spotter DEMO --quiet
  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.
  ====================================================================

Individual findings

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 DEMO --only vulnerable
  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.
  ====================================================================
Interpretation

What the verdicts mean

Every finding lands in one of five buckets. The split that matters for a post-quantum programme is the first two.

!

Quantum-vulnerable

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.

+

Quantum-safe

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.

~

Reduced margin

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.

x

Broken (classical)

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.

?

Needs review

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.

=

The overall tier

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.

TierMeaning
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.
Reference

Command options

pqc-spotter [PATH] [options]PATH is the directory or file to scan, defaulting to the current directory.

OptionDescription
-f, --formattext (default), json, sarif, cyclonedx, markdown
-o, --output FILEWrite the report to a file instead of stdout.
--fail-on LEVELExit 1 when findings exist at vulnerable, broken, weak or any. Default never.
--only POSTURESReport only the listed postures, comma separated. Does not affect the exit code.
-e, --exclude GLOBSkip paths matching a glob. Repeatable.
--no-default-excludesAlso scan node_modules, vendor, build output and similar.
--include-hiddenScan dotfiles and dot-directories.
--follow-symlinksFollow symlinked directories.
--min-confidencelow, medium (default), high. Raise it to drop the noisier heuristics.
--max-file-size BYTESSkip files above this size. Default 2 MB.
--max-per-group NFindings shown per posture in text output. Default 10.
-q, --quietSummary, inventory and verdict only.
--colorauto, always, never.
--list-rulesPrint the rule database and exit.
-V, --versionPrint the version and exit.

Exit codes

CodeMeaning
0The scan completed. This is the default whatever was found — pqc-spotter does not break your pipeline unless you ask it to.
1Findings exist at or above --fail-on.
2The scan itself failed: bad path, bad argument, unreadable target.

Output formats

text

Coloured terminal report. The default when stdout is a terminal; colour switches itself off when piped.

json

Full result: summary, inventory and every finding with file, line, evidence and remediation. For dashboards and scripts.

sarif

SARIF 2.1.0 for GitHub code scanning. Findings appear inline on the pull request that introduced them.

cyclonedx

A CycloneDX 1.6 CBOM — a cryptographic bill of materials, one component per algorithm, for compliance evidence.

markdown

Tables suited to a CI job summary or a pull-request comment.

Examples

pqc-spotter .
pqc-spotter . -q
pqc-spotter src --only vulnerable
pqc-spotter . -f json -o pqc.json
pqc-spotter . -e 'tests/*' -e '*.min.js'

Automation

Running it in CI

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.

.github/workflows/pqc.ymlGitHub Actions
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
.gitlab-ci.ymlGitLab CI
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]
Job summary commentMarkdown
# Append a table to the GitHub job summary
pqc-spotter . -f markdown >> $GITHUB_STEP_SUMMARY
Compliance evidenceCBOM
# 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
Honest limits

What a static scan cannot tell you

Worth knowing before you read a report, so you spend your time on the findings that matter.

TLS posture is not in the source

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.

Runtime choices stay unresolved

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.

A finding is evidence, not a defect

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.