cd /news/ai-safety/pqc-scan-scan-your-codebase-for-quan… Β· home β€Ί topics β€Ί ai-safety β€Ί article
[ARTICLE Β· art-49520] src=github.com β†— pub= topic=ai-safety verified=true sentiment=Β· neutral

Pqc-scan: scan your codebase for quantum-vulnerable cryptography

A new open-source static analysis tool called pqc-scan helps developers find quantum-vulnerable cryptography in their codebases before quantum computers become a threat. The tool scans source code, configurations, and dependencies for algorithms like RSA and ECDSA that are broken by Shor's algorithm, and recommends migration to NIST-standardized post-quantum algorithms such as ML-KEM and ML-DSA.

read13 min views2 publishedJul 7, 2026
Pqc-scan: scan your codebase for quantum-vulnerable cryptography
Image: source

Snyk for Post-Quantum Cryptography β€” a developer-first static analysis tool that finds quantum-vulnerable cryptography in your code, configs, and dependencies before quantum computers (or your auditors) do.

pqc-scan

is zero-friction and lives where your code lives: in your editor, on the command line, and right inside your pull requests. It parses real source with tree-sitter ASTs (not brittle regexes), tells you exactly which line is vulnerable, why it matters, and how to migrate to a NIST-standardized post-quantum algorithm.

pqc-scan scan .
pqc-scan  Β·  Post-Quantum Cryptography scan

  βœ–  CRITICAL  PQC001 Β· RSA Key Generation   [high confidence]
  β”Œβ”€ app/keys.py:10:19   (RSA-2048)
  β”‚  rsa.generate_private_key(
  β”‚          public_exponent=65537,
  β”‚          key_size=2048,
  β”‚      )
  └─ RSA key generation detected. RSA is broken by Shor's algorithm on a
     cryptographically relevant quantum computer, regardless of key size.
       Migrate to: ML-KEM-768 (CRYSTALS-Kyber) …  Β·  FIPS 203 (ML-KEM) / FIPS 204 (ML-DSA)
       see: https://csrc.nist.gov/pubs/fips/203/final

────────────────────────────────────────────────────────────────────────────────
  Critical: 2  High: 2  Medium: 0  Low: 0   |  Total findings: 4
  Files scanned: 1  |  Time: 0.00s

The public-key cryptography that secures almost everything online β€” TLS handshakes, SSH, code signing, JWTs, certificates, VPNs β€” relies on math problems that are hard for classical computers. Shor's algorithm, run on a cryptographically relevant quantum computer, solves all of them efficiently. That breaks, completely:

RSA(any key size, including RSA-4096)** Elliptic-curve crypto**: ECDSA, ECDH/ECDHE, X25519/X448, Ed25519/Ed448** Finite-field crypto**: Diffie-Hellman (DH/DHE), DSA

Symmetric crypto and hashing are weakened but not broken: Grover's algorithm only halves the effective security level, so AES-256 and SHA-256/SHA3-256 remain safe.

You don't need a quantum computer to exist today to be at risk. Adversaries can capture encrypted traffic now and decrypt it later once quantum hardware matures. Any data with a long confidentiality lifetime β€” health records, financial data, state secrets, long-lived credentials β€” is already exposed. Key-exchange material (ECDH, X25519, DH) is the prime target.

August 2024β€” NIST finalized the first post-quantum standards:** FIPS 203 (ML-KEM)for key encapsulation, FIPS 204 (ML-DSA)and FIPS 205 (SLH-DSA)for digital signatures. 2030 / 2035**β€” US federal guidance (CNSA 2.0, NSM-10) sets a migration deadline: begin now, complete the transition for most systems by2030, finish by 2035.

Migration is a multi-year inventory-and-replace effort. pqc-scan

is the inventory step you can run on every commit.

pqc-scan

requires Python β‰₯ 3.10.

Install editable from a clone of the source:

git clone https://github.com/pqc-scan/pqc-scan.git
cd pqc-scan
pip install -e .

This installs the pqc-scan

console script. Verify:

pqc-scan --version

For development (tests + coverage):

pip install -e ".[dev]"
pytest

All scanning dependencies (tree-sitter grammars for Python, JavaScript, Java, Go, plus Typer, Rich and PyYAML) are installed automatically β€” there is no native toolchain to build.

pqc-scan scan .                       # scan the current tree, pretty console report
pqc-scan scan src/ -s high            # only report HIGH and CRITICAL findings
pqc-scan scan . -o sarif -f out.sarif # write SARIF for GitHub code scanning
pqc-scan scan . --changed-only        # only files changed in the current git diff
pqc-scan rules                         # list every detection rule
pqc-scan init                          # write a starter .pqcscan.yml

pqc-scan

exposes four commands: scan

, report

, init

, and rules

.

pqc-scan scan [PATH] [OPTIONS]

PATH

defaults to .

(the current directory) and may be a file or a directory.

Flag Alias Description
--output
-o
Output format: console (default), sarif , cbom , json .
--output-file
-f
Write output to this file instead of stdout.
--severity
-s
Minimum severity to report: critical , high , medium , low .
--exclude
Glob pattern to exclude. Repeatable.
--changed-only
Only scan files changed in the current git diff (fast PR scans).
--config
Path to a .pqcscan.yml config file.
--no-color
Disable colored output (auto-disabled when writing to a file).
--fail-on-findings
Exit with code 1 if any findings are reported β€” for CI gating.
--limit N
Show at most N findings in console output (0 = all).
--summary
Console output: totals and a per-file breakdown only, no per-finding detail.
--group-by
Console grouping: severity (default) or file .

Examples:

pqc-scan scan . --fail-on-findings

pqc-scan scan . --exclude "**/tests/**" --exclude "**/third_party/**"

pqc-scan scan src/ -o json

pqc-scan scan . --changed-only -s high --fail-on-findings

pqc-scan scan . --summary
pqc-scan scan . --group-by file --limit 50

Example console output (scanning a single file):

  pqc-scan  Β·  Post-Quantum Cryptography scan

  βœ–  CRITICAL  PQC001 Β· RSA Key Generation   [high confidence]
  β”Œβ”€ app/keys.py:10:19   (RSA-2048)
  β”‚  rsa.generate_private_key(
  β”‚          public_exponent=65537,
  β”‚          key_size=2048,
  β”‚      )
  └─ RSA key generation detected. RSA is broken by Shor's algorithm on a
     cryptographically relevant quantum computer, regardless of key size.
       Migrate to: ML-KEM-768 (CRYSTALS-Kyber) for encryption / key
       establishment, or ML-DSA-65 …  Β·  FIPS 203 (ML-KEM) / FIPS 204 (ML-DSA)
       see: https://csrc.nist.gov/pubs/fips/203/final

  ⚠  HIGH  PQC002 · RSA Encryption / Padding   [high confidence]
  β”Œβ”€ app/keys.py:26:9   (RSA-OAEP)
  β”‚  padding.OAEP(
  β”‚              mgf=padding.MGF1(algorithm=hashes.SHA256()),
  β”‚              algorithm=hashes.SHA256(),
  β”‚              label=None,
  β”‚          )
  └─ RSA-based encryption or padding (OAEP / PKCS1v15) detected. RSA encryption
     is broken by Shor's algorithm.
       Migrate to: ML-KEM-768 (CRYSTALS-Kyber)  Β·  FIPS 203
       see: https://csrc.nist.gov/pubs/fips/203/final

────────────────────────────────────────────────────────────────────────────────
  Critical: 2  High: 2  Medium: 0  Low: 0   |  Total findings: 4
  Files scanned: 1  |  Time: 0.00s

report

runs a scan and writes a machine-readable artifact to disk. Unlike scan

, the format defaults to cbom

and --output-file

is required.

pqc-scan report [PATH] --output-file FILE [--format cbom|sarif|json] [--config FILE]
pqc-scan report . --output-file cbom.json

pqc-scan report . --format sarif --output-file results.sarif
pqc-scan init [PATH] [--force]

Writes a starter .pqcscan.yml

to PATH

(default .

). Refuses to overwrite an existing file unless --force

is given.

pqc-scan init
pqc-scan rules

Prints a table of every rule (ID, name, severity, category, description).

pqc-scan

ships 14 rules, covering quantum-vulnerable key generation, signatures, encryption, key exchange, hashing, weak JWT/TLS configuration, legacy ciphers, and quantum-vulnerable dependencies.

ID Name Severity Category
PQC001
RSA Key Generation critical
key-generation
PQC002
RSA Encryption / Padding high
encryption
PQC003
RSA Signature critical
signing
PQC004
ECDSA Key Generation or Signing critical
signing
PQC005
ECDH / X25519 Key Exchange high
key-exchange
PQC006
Ed25519 / Ed448 Key Generation high
signing
PQC007
Diffie-Hellman Key Exchange high
key-exchange
PQC008
DSA Key Generation or Signing critical
signing
PQC009
SHA-1 Usage medium
hashing
PQC010
MD5 Usage high
hashing
PQC011
Weak JWT Algorithm (RS/ES/PS) high
signing
PQC012
Weak TLS Configuration medium
configuration
PQC013
DES / 3DES Usage high
encryption
PQC014
Quantum-Vulnerable Dependency medium
dependency

Run pqc-scan rules

for the full descriptions and to confirm the set installed on your machine.

Supported languages (code): Python, JavaScript/TypeScript, Java, Go. Supported manifests/configs: requirements.txt

, package.json

, plus YAML / JSON / TOML / .conf

configuration files (TLS, JWT, cipher lists).

Library coverage highlights (beyond the language standard libraries):

Pythonβ€”cryptography

(hazmat), pycryptodome/pycrypto (RSA.generate

,pkcs1_15

,pss

,DSS

,PKCS1_OAEP

), pyOpenSSL (TYPE_RSA

), paramiko, PyJWT / python-jose,ssl

,hashlib

(includinghashlib.new("sha1")

and theusedforsecurity=False

demotion tolow

).JavaScriptβ€” Nodecrypto

(generateKeyPair

,createDiffieHellman

,publicEncrypt

,createSign

), WebCryptoSubtleCrypto

,jsonwebtoken

,jose

(setProtectedHeader

), node-forge, AWS KMS asymmetricKeySpec

s.Javaβ€” JCA factories (KeyPairGenerator

,Signature

,Cipher

,MessageDigest

,KeyAgreement

), Bouncy Castle lightweight API (RSAKeyGenerationParameters

,ECDSASigner

,Ed25519Signer

, …), andSSLContext.getInstance

with legacy protocols.Goβ€”crypto/rsa

,crypto/ecdsa

,crypto/ecdh

,crypto/ed25519

,crypto/dsa

,crypto/tls

configuration (MinVersion

pins and weakCipherSuites

),x/crypto/curve25519

, and golang-jwt signing methods.

Context hints. Findings inside code that looks like crypto-library plumbing (paths containing hazmat

, _internal

, backends

, vendor

, …) or inside a generate_*_key()

-style wrapper carry a context_hint

explaining whether the call site is actionable for you or belongs to a library you merely consume. Hints appear in console output, SARIF properties.contextHint

, and the JSON context_hint

field.

Choose with -o

/--output

on scan

, or --format

on report

.

A colorized, human-readable report with severity badges, the exact code snippet, the migration target, and the relevant NIST standard. Color is auto-disabled when writing to a file or with --no-color

.

Static Analysis Results Interchange Format 2.1.0. Upload it with the CodeQL action and findings appear as inline annotations on the exact line in pull requests and in the repository's Security β†’ Code scanning tab.

pqc-scan scan . -o sarif -f pqc-scan.sarif
{
  "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/.../sarif-schema-2.1.0.json",
  "version": "2.1.0",
  "runs": [
    {
      "tool": { "driver": { "name": "pqc-scan", "version": "0.1.0", "rules": [ ... ] } },
      "results": [ ... ]
    }
  ]
}

A CycloneDX 1.6 CBOM: a structured inventory of every cryptographic asset found, emitted as cryptographic-asset

components. Ideal for compliance, supply-chain attestation, and tracking migration progress over time.

pqc-scan report . --format cbom --output-file cbom.json
{
  "bomFormat": "CycloneDX",
  "specVersion": "1.6",
  "components": [
    { "type": "cryptographic-asset", "name": "RSA-2048", "...": "..." }
  ]
}

Scan metadata plus every finding with full migration metadata β€” easy to pipe into jq

, dashboards, or custom tooling.

pqc-scan scan . -o json | jq '.findings[] | {rule_id, severity, file_path, line_number, algorithm}'
{
  "tool": "pqc-scan",
  "version": "0.1.0",
  "generated_at": "2026-07-06T12:00:00Z",
  "paths": ["/repo"],
  "summary": {
    "total": 4,
    "by_severity": { "critical": 2, "high": 2, "medium": 0, "low": 0 },
    "files_scanned": 128,
    "duration_seconds": 0.4211,
    "errors": []
  },
  "findings": [
    {
      "file_path": "app/keys.py",
      "line_number": 10,
      "column_number": 19,
      "algorithm": "RSA-2048",
      "category": "key-generation",
      "severity": "critical",
      "confidence": "high",
      "rule_id": "PQC001",
      "context_hint": null,
      "migration_suggestion": {
        "recommended_algorithm": "ML-KEM-768 (CRYSTALS-Kyber) …",
        "nist_standard": "FIPS 203 (ML-KEM) / FIPS 204 (ML-DSA)",
        "docs_url": "https://csrc.nist.gov/pubs/fips/203/final"
      }
    }
  ]
}

Run pqc-scan

on every pull request and surface findings as inline code-scanning annotations. Save this as .github/workflows/pqc-scan.yml

:

name: pqc-scan

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read
  security-events: write   # required to upload SARIF to code scanning

jobs:
  pqc-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run pqc-scan
        uses: ./                          # this repo's action; or pin: pqc-scan/pqc-scan@v1
        with:
          path: .
          severity: high                  # critical | high | medium | low
          output-sarif: pqc-scan.sarif
          fail-on-findings: 'false'        # set 'true' to block the PR on any finding

      - name: Upload SARIF to GitHub code scanning
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: pqc-scan.sarif

Action inputs

Input Default Description
path
.
File or directory to scan.
severity
medium
Minimum severity to report.
output-sarif
pqc-scan.sarif
Path to write the SARIF report.
fail-on-findings
false
Fail the job (exit 1) if any findings are reported.

The action exits 0

when the scan is clean; with fail-on-findings: 'true'

the SARIF is still uploaded before the job is failed, so annotations always appear.

If you prefer to run the CLI directly without the composite action, the equivalent step is just:

      - run: pip install -e . && pqc-scan scan . -o sarif -f pqc-scan.sarif -s high

Pair it with --changed-only

in PR jobs to scan only the diff and keep runs fast.

pqc-scan

reads a .pqcscan.yml

file. It is discovered automatically by walking up from the scanned path, or pointed at explicitly with --config

. Generate a starter with pqc-scan init

. Full schema:


exclude:
  - "**/tests/**"
  - "**/*.test.py"
  - "**/vendor/**"
  - "**/node_modules/**"

severity_threshold: medium

languages:
  - python
  - javascript
  - java
  - go

scan_configs: true        # Scan YAML/JSON/TOML/.conf config files
scan_dependencies: true   # Scan dependency manifests (requirements.txt, package.json, ...)

rules:
  disable: []             # e.g. [PQC010] to silence a specific rule

output:
  default_format: console # console | sarif | cbom | json
  cbom_path: cbom.json

Notes:

  • CLI flags override config values (e.g. -s high

beatsseverity_threshold

). rules.disable

takes rule IDs (PQC001

…PQC014

), case-insensitive.- Without a config file, the defaults exclude **/tests/**

,**/node_modules/**

,**/.venv/**

,**/venv/**

,**/vendor/**

,**/dist/**

, and**/build/**

(thetests

glob matches test directories atany depth), and the walker never descends into.git

,site-packages

, caches, or IDE directories. - A malformed --config

file exits with code2

; a malformeddiscoveredconfig prints a warning and falls back to defaults.

Every finding ships with concrete, NIST-aligned migration guidance and a before/after code example. The high-level mapping:

Vulnerable today Migrate to NIST standard
RSA key generation / encryption (PQC001/002) ML-KEM-768 (CRYSTALS-Kyber)
FIPS 203
RSA signatures (PQC003) ML-DSA-65 (CRYSTALS-Dilithium)
FIPS 204
ECDSA / EC keys (PQC004) ML-DSA-65
FIPS 204
ECDH / ECDHE / X25519 (PQC005) ML-KEM-768
FIPS 203
Ed25519 / Ed448 (PQC006) ML-DSA-65 (or SLH-DSA)
FIPS 204 / 205
Diffie-Hellman (PQC007) ML-KEM-768
FIPS 203
DSA (PQC008) ML-DSA-65
FIPS 204
SHA-1 (PQC009) SHA-256 / SHA3-256
FIPS 180-4 / 202
MD5 (PQC010) SHA-256 / SHA3-256
FIPS 180-4 / 202
Weak JWT RS/ES/PS256 (PQC011) HS256 internally; track IETF JOSE for PQC β€”
Weak TLS config (PQC012) TLS 1.3 + hybrid X25519MLKEM768
FIPS 203
DES / 3DES (PQC013) AES-256-GCM
FIPS 197

Heads-up about liboqs.The Python post-quantum libraryoqs

(liboqs-python) isnota purepip install

. It wraps the compiledliboqsC library, which must be available first:pip install liboqs

builds it from source via CMake, or you install the distro package / build from[https://github.com/open-quantum-safe/liboqs]. Hash and symmetric replacements (SHA-256, AES-256-GCM) need no special install β€” they live inhashlib

and thecryptography

package.

pqc-scan

uses two complementary detection strategies:

Code (Python, JavaScript/TypeScript, Java, Go): tree-sitter AST analysis. Source is parsed into a concrete syntax tree and the analyzers traverse real nodes β€” call expressions, imports, dotted attribute access, string and keyword arguments. This isnot regex matching: it resolves what is actually beingcalled(e.g.rsa.generate_private_key(...)

,ec.generate_private_key(...)

), so it sees through aliasing and whitespace, reports precise 1-based line/column positions, and avoids matching the same construct inside comments or strings. - Configs and dependencies: pattern-based scanning. TLS/JWT/cipher settings in YAML/JSON/TOML/.conf

, and manifests likerequirements.txt

andpackage.json

, are matched against curated patterns of quantum-vulnerable algorithms and libraries.

Each language analyzer exposes a common contract (LANGUAGE

, EXTENSIONS

, GRAMMAR

, analyze(...)

) and emits Finding

objects through a single shared factory, so console, SARIF, CBOM, and JSON outputs all stay perfectly consistent.

pqc-scan

is a static analyzer. It is tuned for high-confidence, low-noise detection, but a few caveats apply:

It flags presence, not necessarily exploitable risk. APQC014

dependency match means a quantum-vulnerable library is declared, not that a vulnerable code path is exercised. Treat findings as an inventory to triage.Dynamic / reflective crypto can be missed. Algorithms chosen at runtime, built from string concatenation, or invoked through heavy indirection may not be resolved by static analysis.Detection is best-effort across libraries. Coverage targets the most common crypto APIs per language; exotic or in-house wrappers may not be recognized.Configuration heuristics are pattern-based and can occasionally over- or under-match unusual config layouts. Tune withrules.disable

andexclude

.

Use --changed-only

for fast PR feedback, the full scan for an inventory/CBOM, and the migration guidance attached to each finding as your remediation checklist.

Apache-2.0. See the project metadata in pyproject.toml

.

── more in #ai-safety 4 stories Β· sorted by recency
── more on @pqc-scan 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/pqc-scan-scan-your-c…] indexed:0 read:13min 2026-07-07 Β· β€”