Skip to main content

pqcheck

CI PyPI Python License Sigstore

Generate a Cryptography Bill of Materials (CBOM) for your codebase in seconds, and gate CI on a crypto policy you can read.

pqcheck scans source code and dependency lockfiles for cryptographic algorithm usage — RSA, ECDSA, AES modes, legacy hashes, post-quantum primitives — and emits a CycloneDX 1.6 CBOM plus SARIF 2.1.0, evaluated against a versionable YAML policy. It runs on a laptop and in CI with no server, no account, and no network access during the scan.

Why now: NIST IR 8547 deprecates RSA and ECC by 2030 and disallows them by 2035. Every migration framework (OMB M-23-02, the EU coordinated roadmap, FS-ISAC guidance) makes inventory the first step. The existing open tooling for that step needs a SonarQube server; the commercial options start at enterprise pricing. This is the pip install version.

Status: pre-release. v0.1.0 lands on PyPI with Sigstore-signed wheels. Until then: uv sync --all-extras && uv run pqcheck --help. Leia em português.

Quickstart

$ pqcheck scan ./your-repo --policy cryptoct-default
✗ src/auth.py:42 — RSA [banned/critical, confidence high] — Shor — migrate to ML-KEM-768
⚠ src/hash.py:7  — BLAKE2B [default/medium, confidence high]
✓ src/aead.py:12 — AES [approved/info, confidence high]
dependencies: 47 parsed
policy cryptoct-default-1.0.0: 1 fail, 1 warn, 1 allow

Machine-readable outputs:

$ pqcheck scan . --policy cryptoct-default --format cbom -o cbom.cdx.json
$ pqcheck scan . --format sarif -o pqcheck.sarif   # imports into GitHub Code Scanning

Gate CI (exit 1 when the policy trips):

$ pqcheck scan . --policy br-bcb-conservative --fail-on policy
$ pqcheck self-audit          # fixed policy, CBOM always written

--fail-on high gates on base severity instead; --strict treats WARN decisions as failures. A finding's displayed severity is demoted by detection confidence, but gating always reads the base severity — low confidence never lets RSA through.

Verify a release yourself (needs the sigstore extra; the .sigstore.json bundle ships next to each wheel on the GitHub release):

$ pqcheck verify-release pqcheck-0.1.0-py3-none-any.whl
OK: pqcheck-0.1.0-py3-none-any.whl verified against pqcheck-0.1.0-py3-none-any.whl.sigstore.json

What it detects

Surface Coverage
Python source stdlib hashlib, cryptography (current + legacy + decrepit paths), pycryptodome — via AST, no execution
Go source stdlib crypto/* and golang.org/x/crypto — union of a bundled go/types analyzer (semantic: key sizes, curves, modes) and a tree-sitter pass that also covers GOOS/cgo-gated files, which type resolution cannot see by construction
Lockfiles pyproject.toml, uv.lock, requirements.txt, pom.xml, go.mod+go.sum, package-lock.json

Java is next on the roadmap; it is not in v0.1.

Policies

Six bundled policies, all plain YAML you can fork:

  • cryptoct-default / cryptoct-strict / cryptoct-advisory — the general tiers (fail / fail-hard / report-only).
  • br-bcb-conservative — for Brazilian financial institutions aligning their inventory with the cybersecurity controls of Res. CMN 4.893/2021.
  • br-drex-piloto — the strictest profile, for teams that want new code quantum-safe by construction.
  • br-vendor-dd — advisory profile for vendor due-diligence annexes.

To be clear about the regulatory framing: no Brazilian regulation currently mandates a cryptographic inventory or PQC migration. The BR profiles anticipate that direction; they do not claim an obligation that does not exist.

pqcheck policy show <name> prints any of them resolved; pqcheck policy validate <file> checks your own against the schema.

Measured precision and recall

Every HIGH/CRITICAL finding across a 10-repo public corpus (pyjwt, paramiko, sigstore-python, age, go-jose, smallstep/crypto, …) was human-adjudicated by reading the flagged line: 255 findings, 0 false positives. Recall on the same repos, against a ground truth of 527 adjudicated call sites, is 1.00. The honest caveat: that corpus's miss list drove the catalog expansion, so it is a tuning set and says nothing about generalization. A held-out set of 6 unseen repos (authlib, borgbackup, certbot, cosign, wireguard-go, certmagic) measured recall 0.989 (273/276; the 3 misses are borgbackup's Cython/OpenSSL binding, outside the import-resolution model) and precision 0.99 (76/77). One round of fixes came from that miss list, so the held-out set is no longer strictly untouched either — future generalization claims need fresh repos. Protocols, pinned SHAs, and verdicts are in tests/corpus/.

Known limitations

pqcheck is a static, single-repo scanner, and these gaps follow from that design:

  • No dataflow analysis: an algorithm reached through a variable, parameter, or lookup table is either missed or reported as a generic low-confidence finding — e.g. .digest() called on a hash object passed in as a parameter, or a cipher picked from a dict at runtime. authlib is the clearest example in the held-out corpus.
  • No C-extension or FFI visibility: crypto implemented behind an in-repo Cython or C binding, like borgbackup's OpenSSL binding, is invisible to source-level detection — only the Python or Go call surface is scanned.
  • Catalog-scoped detection: pqcheck flags what's in its curated Python and Go catalogs. A library or symbol outside the catalog produces no findings, and no findings isn't evidence of no crypto.
  • Static analysis only: there's no runtime or dynamic-dispatch resolution. hashlib.new(name_var) with a name computed at runtime, or getattr-based dispatch, resolve to nothing.
  • Usage-context blindness: a symbol match carries no intent. "RSA verifying a third-party webhook" reads the same as "RSA encrypting data at rest," and an ECDH() call used only for key-format conversion gets flagged the same as a real key agreement (one known false positive in the held-out set). Context-scoped policy rules are parsed but not shipped in the bundled policies until detectors emit context.
  • Hybrid-scheme detection covers filippo.io/hpke (X25519MLKEM768) only; other hybrid constructions read as their classical component.
  • Only the repo root's .gitignore/.pqcheckignore are honored.
  • Dependency findings are inventory (introduces metadata in the CBOM); they do not trip the policy gate in v0.1 — call sites do.

See tests/corpus/ for the adjudication protocol behind these numbers.

Development

Requires Python 3.12+ and uv: uv sync --all-extras, then uv run pytest, uv run ruff check ., uv run mypy. See CONTRIBUTING.md.

License

Apache-2.0. See SECURITY.md for the vulnerability disclosure process and the honest list of classical crypto this project itself transitively depends on.

Metadata

Release files for pqcheck 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for pqcheck 0.1.0
File
pqcheck-0.1.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
pqcheck-0.1.0-py3-none-musllinux_1_2_x86_64.whl Python 3 none Linux musl 1.2+ x86-64 Details
pqcheck-0.1.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl Python 3 none Linux glibc 2.5+ x86-64, Linux glibc 2.28+ x86-64 Details
pqcheck-0.1.0-py3-none-macosx_11_0_x86_64.whl Python 3 none macOS 11.0+ x86-64 Details
pqcheck-0.1.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details

Total release size: 20.7 MB

Release files / pqcheck-0.1.0-py3-none-win_amd64.whl

Download URL pqcheck-0.1.0-py3-none-win_amd64.whl
Size 4.2 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
83dc7bd5e1d65710bda486863a98b56fe9163fa754dd14ee4d8c0a0e7422a572
BLAKE2b-256 checksum
How to use checksums
c13ce267e18271a3e00ed0b67a159e7b9756d68eb386f16f5c2481427a2b17a9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 13, 2026.

Transparency log

Release files / pqcheck-0.1.0-py3-none-musllinux_1_2_x86_64.whl

Download URL pqcheck-0.1.0-py3-none-musllinux_1_2_x86_64.whl
Size 4.2 MB
Tags Linux musl 1.2+ x86-64 Python 3
SHA-256 checksum
How to use checksums
2772d358371c38533bc3aeabaa2feea09c751861a5c13de47906276be2295454
BLAKE2b-256 checksum
How to use checksums
932de2b995267756845acf9145c2f00b2a7e4e063df30b6fae88646475b6967c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 13, 2026.

Transparency log

Release files / pqcheck-0.1.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl

Download URL pqcheck-0.1.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
Size 4.2 MB
Tags Linux glibc 2.28+ x86-64 Linux glibc 2.5+ x86-64 Python 3
SHA-256 checksum
How to use checksums
7aabbcc40161b6a09c70dc14020d45a6fd16046d9d331c001aed209a9dd7c8b5
BLAKE2b-256 checksum
How to use checksums
0e7442021eca1145824289ce0430854f6c8ad2259d67cec2075ac943bbd54d5e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 13, 2026.

Transparency log

Release files / pqcheck-0.1.0-py3-none-macosx_11_0_x86_64.whl

Download URL pqcheck-0.1.0-py3-none-macosx_11_0_x86_64.whl
Size 4.2 MB
Tags Python 3 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
94ad45fb3bef814419fdd58882690f68db9ea85181fef028364bc865ce7feb23
BLAKE2b-256 checksum
How to use checksums
eae4ca11edfca46483e833756ffd572fd2e7ef84479bd65e920db2b42a776110
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 13, 2026.

Transparency log

Release files / pqcheck-0.1.0-py3-none-macosx_11_0_arm64.whl

Download URL pqcheck-0.1.0-py3-none-macosx_11_0_arm64.whl
Size 4.0 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
404d05911c15f60df69491801ed06f5c4cbbe9a4691d344a2b7eb1ef3a4b0c19
BLAKE2b-256 checksum
How to use checksums
bda71d0009c4cec8abf2bbf319996cfe29a1b0dbb0167273ae5e1e9566993b03
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

5 release files

0.0.1

4 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page