DEV Community

Brandon Sellam
Brandon Sellam

Posted on

Add a post-quantum readiness gate to your CI in 5 lines

Your codebase almost certainly relies on RSA and elliptic-curve cryptography — TLS, JWTs, SSH keys, signed tokens. All of it is breakable by a large enough quantum computer (Shor's algorithm), and "harvest now, decrypt later" means data you encrypt today can be captured today and decrypted later. Regulators noticed: CNSA 2.0 (US federal + suppliers), DORA (EU financial entities, applies from Jan 2025), and NIS2 now mandate strict cryptographic risk management — which in practice means knowing where your quantum-vulnerable crypto lives, a cryptographic bill of materials (CBOM).

Most teams can't answer "where is our RSA/ECC?" off the top of their head. Here's how to make CI answer it for you, on every push, for free.

What we're building

A GitHub Action that scans your repo, grades its post-quantum readiness A–F, writes a CycloneDX 1.6 CBOM, and — if you want — fails the build when classically-broken crypto (MD5, RC4, 3DES, deprecated TLS) shows up.

Step 1 — try it in your browser first (30 seconds, nothing uploaded)

Before touching CI, paste a package.json / requirements.txt / cipher list into the in-browser scanner and see your grade. It runs entirely client-side — no upload: https://throndar.ai/cbom

Step 2 — add it to CI (the 5 lines)

# .github/workflows/pqc-readiness.yml
name: PQC readiness
on: [push, pull_request]
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: brandonjsellam-Releone/pq-readiness-scorecard@v1
        with:
          path: .
Enter fullscreen mode Exit fullscreen mode

That's it. The Action is self-contained and dependency-free — no npm install, no setup step. On the next push it prints a scorecard to the job summary:

Post-Quantum Readiness Scorecard: D  (52/100) — Quantum-vulnerable — migrate
3 files · broken-classical 0 · quantum-broken 4 · weakened 1 · resistant 0
Enter fullscreen mode Exit fullscreen mode

Step 3 — see findings in the Security tab (SARIF)

The Action emits SARIF 2.1.0. Upload it and every finding shows up as a code-scanning alert:

      - id: pqc
        uses: brandonjsellam-Releone/pq-readiness-scorecard@v1
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: ${{ steps.pqc.outputs.sarif-file }}
Enter fullscreen mode Exit fullscreen mode

You also get cbom.cdx.json (the CycloneDX CBOM) as a build artifact — feed it to any SBOM/CBOM tooling.

Step 4 — fail the build on broken crypto

Grading is nice; a gate is better. Fail the build when anything classically-broken appears:

        with:
          fail-on: broken-classical        # or: broken-classical,quantum-broken
          # min-grade: B                    # optional: fail below grade B
Enter fullscreen mode Exit fullscreen mode

Now a PR that adds hashlib.md5() or TLSv1.0 goes red before it merges.

Which findings do you fix first? (harvest-now-decrypt-later)

Not every quantum-vulnerable finding is equally urgent. Key establishment — ECDH, Diffie-Hellman, RSA key transport (RSA-OAEP, static-RSA TLS) — is the most time-critical: an adversary can record your encrypted traffic today and decrypt it later once a quantum computer exists ("harvest now, decrypt later"). Signatures are less urgent — forging one needs a quantum computer at signing time, not retroactively. The scanner tags the harvest-now findings and puts them first in the migration plan, so you don't waste the early budget on the wrong things.

What it actually detects

  • Quantum-broken (Shor): RSA, ECDSA, ECDH, finite-field DH, EC curves, RSA/ECDSA JWTs, SSH RSA/ECDSA keys.
  • Hardcoded JWTs: it decodes the token header (base64url segment only — never the payload, so no secrets end up in a finding) and classifies the alg: RS256/ES256/PS256 → Shor-broken, HS256 → Grover-weakened, alg:none → critical unsigned.
  • Quantum-weakened (Grover): AES-128/192 (Grover's quadratic speedup reduces effective security — enough to prefer AES-256); SHA-256 (collision resistance drops to ~2^85). SHA-384/512 stay fine.
  • Classically broken (fix today): MD5, SHA-1, RC4, 3DES, Blowfish, deprecated TLS, NTLM, WEP.
  • Quantum-resistant: ML-KEM, ML-DSA, SLH-DSA (the NIST FIPS 203/204/205 standards), AES-256, SHA-384, SHA-512, ChaCha20 (256-bit).
  • Broken PQ candidates: it also flags SIKE/SIDH (broken by Castryck–Decru in 2022) and GeMSS — so a team that thinks it migrated to post-quantum isn't left trusting something already broken.

It reads inline code, declared crypto libraries, numeric OIDs in certs/ASN.1, and base64/PEM key blobs.

Honest caveats (read these)

It's a lexical scan: findings are leads to verify, not a complete inventory, and it is not a certification. Algorithm names denote the public standards they're based on — not a CMVP/FIPS-140 validation. It won't fake a clean bill of health: a scan that examines zero files refuses to grade rather than reporting "A". The scanner is open-source (MIT) — read it and re-run every finding yourself: github.com/brandonjsellam-Releone/verify-pqc. (Falcon, if you see it flagged, is FN-DSA for the forthcoming FIPS 206 — in development, not yet standardized.)

If your grade is bad

Start with Phase 1: rip out the classically-broken stuff (MD5/SHA-1/RC4/3DES, old TLS) — that's exploitable today, quantum or not. Then plan the quantum-broken key-establishment (the harvest-now items) and signatures toward the NIST PQC standards, running classical+PQC in hybrid during the transition.

If you need a signed, auditor-ready version of this — an Evidence Pack with an executive summary, the grade, the findings, the CBOM, and a prioritized migration plan, cryptographically signed so your auditors can verify it hasn't been altered — that's at throndar.ai/evidence. But the free Action above is enough to answer the question every regulator is about to ask: where is our quantum-vulnerable cryptography, and what's the plan?


Built by TRELYAN Inc. The scanner and CLI are MIT. Feedback — especially false positives/negatives on real repos — is genuinely wanted: open an issue on the repo.

Top comments (0)