npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@quantakrypto/qscan

v0.10.0

Published

qScan — find quantum-vulnerable cryptography in any codebase (CLI). Zero runtime dependencies.

Readme

@quantakrypto/qscan

Find quantum-vulnerable cryptography in any codebase.

qscan walks a project and reports where it relies on classical asymmetric cryptography (RSA, (EC)DH, ECDSA, EdDSA, DSA, …) — the algorithms broken by a sufficiently large quantum computer, and the ones exposed to harvest-now, decrypt-later (HNDL) attacks today. It scans source files, dependency manifests, and configuration, then prints a readiness score and a concrete next step.

  • Zero runtime dependencies. Node built-ins only; the engine is @quantakrypto/core.
  • CI-friendly. Severity thresholds drive the exit code; baselines suppress known findings so the build only fails on new problems.
  • Multiple formats. human (default), json, SARIF 2.1.0 for code-scanning dashboards, a CycloneDX 1.6 CBOM for compliance tooling, an ISO 27001 A.8.24 evidence report, and an OpenVEX 0.2.0 document for VEX pipelines.
  • Fast on big repos. Optional worker-thread parallelism (--parallel) and git-aware incremental scanning (--changed).

Language coverage

Inline crypto detection currently covers JavaScript/TypeScript, Python, Go, Java/Kotlin/Scala (JCA + BouncyCastle), C#/.NET, Rust, Ruby, PHP (openssl / phpseclib3 / libsodium), Elixir (:crypto / X509 / JOSE), C/C++ (OpenSSL, Mbed TLS, wolfSSL), Swift (CryptoKit / Security), Objective-C (Security SecKey*), and Dart/Flutter (pointycastle / cryptography), and smart contracts (Solidity/Move/Cairo on-chain signature verification) source — 14 languages. PEM key material, SSH keys (including SSH-CA certificates), TLS/certificate config, reverse-proxy/gRPC TLS, WebAuthn/FIDO2, code-signing, weak signature hashes (SHA-1/MD5), DKIM, SPIFFE/SPIRE, and dependency manifests for eight ecosystems — npm (plus yarn.lock / pnpm-lock.yaml), PyPI, Cargo, Go modules, Maven, RubyGems, NuGet, and Composer — are detected in any file regardless of language.

qScan is honest about coverage: if a scan walks files but finds none in a supported source language, it says so and will not present a bare 100/100 as a clean bill of health — the crypto may simply live in a language it can't read yet. Always check the analyzed count in the report before relying on the score.

Install

npm install -g @quantakrypto/qscan
# or run without installing
npx @quantakrypto/qscan .

Requires Node ≥ 20.

Usage

qscan [path] [options]

path defaults to the current directory (.).

Options

| Flag | Description | Default | | --- | --- | --- | | --format <human\|json\|sarif\|cbom\|evidence\|vex> | Output format. | human | | --cbom | Alias for --format cbom (CycloneDX 1.6 CBOM). | — | | -o, --output <file> | Write the report to a file instead of stdout. | stdout | | --severity-threshold <level> | Exit 1 if any finding is at/above this level. One of critical, high, medium, low, info. | high | | --no-source | Skip scanning source files for inline crypto. | scan on | | --no-deps | Skip scanning dependency manifests. | scan on | | --no-config | Skip scanning config files (TLS/certificates). Toggles config detectors — not the config file below. | scan on | | --config <path> | Use this quantakrypto.config.json instead of auto-discovering one at the scan root. | auto | | --no-config-file | Disable quantakrypto.config.json auto-discovery. | discovery on | | --ignore <pattern> | Exclude paths matching <pattern>. Repeatable. | — | | --include <pattern> | Restrict the scan to paths matching <pattern>. Repeatable. | all files | | --max-file-size <bytes> | Skip files larger than <bytes>. | 2 MiB | | --no-default-ignores | Don't skip node_modules/.git/dist by default. | ignores on | | --scan-minified | Scan minified/generated/bundled files too. | skipped | | --changed | Incremental: scan only files git reports as changed. | off | | --since <git-ref> | With --changed, diff against <git-ref> (implies --changed). | working tree | | --parallel | Scan using a worker-thread pool when the workload is large enough. | off | | --concurrency <n> | Worker count for --parallel (implies --parallel). 0 forces serial. | CPU count | | --audit | Opt-in supply-chain checks (see below): dependency advisories via each ecosystem's own audit tool, plus a declared-source-repository (provenance) check. Findings merge into the report and the exit code; a missing tool or network hiccup degrades to a stderr diagnostic. | off | | --mandate <id> | Gate findings against a compliance mandate's dated clauses (cnsa-2.0, nist-ir-8547; repeatable). Reports each prohibited finding with its clause + deadline; fails the build only once a disallow deadline has passed. Verdicts also ride in --format json (mandateMapping), sarif (run.properties.mandate), and evidence (hashed). | off | | --lead-months <n> | Fail early when a --mandate disallow deadline is within n months. | — | | --fail-now | Fail on any --mandate-prohibited finding, ignoring the deadline. | off | | --policy <file> | Org crypto-policy JSON: adds §4 verdicts to --format evidence; with --mandate, permitted/in-transition families are acknowledged and exempt from the early gate (--fail-now/--lead-months), but a passed disallow deadline still fails. | — | | --profile <id> | Standards regime for the migration-targets footer: nist, cnsa-2.0, bsi-tr-02102, anssi, uk-ncsc. | nist | | --tier <id> | CNSA security tier for migration targets: category-3, category-5 (alias for a profile). | — | | --hndl | Score findings by harvest-now-decrypt-later exposure (reads hndl.yml; qscan hndl init scaffolds one). Annotates only; never changes the exit code. | off | | --triage | BYOK LLM pass that re-ranks findings by real exposure and explains them. Never suppresses; never changes the exit code. Needs an API key. | off | | --triage-floor <level> | With --triage, only triage findings at/above this level. | medium | | --context <level> | How much source is shared with the LLM: metadata, snippet, function, file (key material redacted, best-effort — review with --dry-run). | snippet | | --dry-run | With --triage, print the exact payload that would be sent and exit without contacting the provider. | off | | --llm-provider <name> | BYOK provider: anthropic or openai-compatible. | anthropic | | --llm-model <id> | Model id for the BYOK provider. | provider default | | --baseline <file> | Suppress findings whose fingerprint is in the baseline file (severity gate only — the --mandate gate is evaluated on pre-baseline findings, so a baseline can't waive a regulatory deadline). | — | | --write-baseline <file> | Write current findings as a baseline, then exit 0. | — | | --quiet | Suppress the human summary banner. | off | | -v, --version | Print version and exit. | — | | -h, --help | Print help and exit. | — |

This table covers the common flags. Run qscan --help for the authoritative, complete list (including --sign/--timestamp, --crypto-agility, --merge, --cache, --top, --max-findings, --no-snippets, --color), plus the subcommands qscan hndl init and qscan crypto-agility emit|validate.

Exit codes

| Code | Meaning | | --- | --- | | 0 | No findings at/above the threshold — or a baseline was written. | | 1 | One or more findings at/above the severity threshold. | | 2 | Usage error or I/O failure. |

Config file (quantakrypto.config.json)

qScan auto-discovers a quantakrypto.config.json at the scan root and applies it under a strict precedence: CLI flags > config file > built-in defaults (per-key). It encodes include / exclude / maxFileSize / noDefaultIgnores / scanMinified, the detector-family toggles, severityThreshold, and a baseline path so CI and local runs share one policy. Point at a file elsewhere with --config <path>, or disable discovery with --no-config-file. See docs/CONFIG.md for the full schema.

Example output

qScan — quantum-vulnerable cryptography report
root: ./examples/vulnerable-app  •  files scanned: 2  •  qscan v0.9.0

3 findings  (2 high, 1 medium)
2 exposed to harvest-now-decrypt-later (HNDL).
Readiness score: 70/100

Top findings
  high     rsa-keygen      src/crypto.js:5
           RSA is not quantum-safe.
           → Use ML-KEM-768 (hybrid X25519MLKEM768).
  high     dep-vulnerable  package.json:7
           Dependency "node-forge" provides classical asymmetric crypto.
  medium   ecdh-usage      src/crypto.js:13
           ECDH is not quantum-safe.
           → Use a hybrid KEM (X25519MLKEM768).

Next step: migrate src/crypto.js — Use ML-KEM-768 (hybrid X25519MLKEM768).

Color is emitted only when writing the human format to an interactive terminal (and is suppressed by the NO_COLOR environment variable). Reports written to a file or piped are always plain text.

Baselines

A baseline records the fingerprints of findings you have already triaged. qScan uses the canonical baseline shared across the whole monorepo (@quantakrypto/core, the GitHub Action, and this CLI): a single on-disk format and a single fingerprint algorithm, so a baseline written by one tool is understood by the others.

A fingerprint is a full SHA-256 of ruleId|file|normalizedSnippet. It is deliberately line-insensitive — unrelated edits that shift line numbers no longer invalidate it — and the snippet's whitespace is normalized so reformatting doesn't either. It ignores volatile fields like severity wording or timestamps.

# 1. Accept the current state of the world.
qscan . --write-baseline qscan-baseline.json

# 2. From now on, fail only on findings that are NOT in the baseline.
qscan . --baseline qscan-baseline.json

The baseline file is plain JSON:

{
  "version": 1,
  "fingerprints": [
    "0f1e2d3c4b5a...full-sha256...",
    "a1b2c3d4e5f6...full-sha256..."
  ]
}

Incremental scans

In CI you usually only care about what a change introduced. --changed restricts the scan to the files git reports as modified, which is a large win on big repos:

# Files modified in the working tree (staged, unstaged, and untracked).
qscan . --changed

# Everything that changed since a base ref (e.g. a PR base).
qscan . --changed --since origin/main

Outside a git work tree the changed-file list is empty (nothing is scanned), rather than an error.

Parallel scans

For large trees, route the scan through a worker-thread pool. qScan automatically stays serial for small inputs, so --parallel is safe to leave on:

qscan . --parallel               # auto worker count (CPU cores)
qscan . --concurrency 4          # pin the worker count (implies --parallel)

Supply-chain audit (--audit, opt-in)

--audit layers three supply-chain checks on top of the normal scan. It is opt-in because two of them shell out (dependency advisories) or make a network request (provenance); a default qscan . stays offline. Every check degrades gracefully — a missing tool, an unparseable output, or a network hiccup becomes a qscan: audit: … diagnostic on stderr, never a hard failure. Any findings it does produce merge into the report and the exit code, so a known-vulnerable dependency can gate CI.

qscan . --audit                       # add advisory + provenance checks
qscan . --audit --format sarif -o qscan.sarif
  1. Dependency advisories. For each ecosystem present at the scan root, qScan runs that ecosystem's own audit tool and turns its advisories into dependency findings (ruleId: dep-advisory, severity from the advisory, <pkg>@<ver>: <summary> (<ID>), remediation = the patched version):

    • Rust — Cargo.toml / Cargo.lockcargo audit --json
    • Python — requirements*.txt / pyproject.tomlpip-audit --format json
    • npm — package-lock.jsonnpm audit --json

    The tool must be on PATH; if it is not, that ecosystem is skipped with a diagnostic (cargo audit not available, skipped). This complements the built-in quantum-vulnerable-dependency database (which flags packages whose purpose is classical public-key crypto) with known-CVE coverage.

  2. PQC parameter / size verification (a default detector, always on — not gated behind --audit). Flags code that has already reached for a post-quantum KEM but got it subtly wrong: a pre-standard round-3 Kyber (pqc_kyber, pqcrypto-kyber, Kyber768, …) used where FIPS 203 ML-KEM is intended (pqc-prestandard-kem, confidence raised when a FIPS-203/ML-KEM/NIST claim is in the same file), and an ML-KEM/Kyber byte size that names a different parameter set than the code advertises (pqc-parameter-mismatch, conservative — fires only on an exact size against a conflicting advertised level).

  3. Provenance / declared source repository. Reads the root manifest's repository URL (package.json repository, Cargo.toml repository, pyproject.toml [project.urls]). A manifest that declares no repository yields an info finding (provenance-repo-missing); with --audit, a declared URL that 404s or does not resolve yields provenance-repo-unresolved (medium). The HEAD request is the only network call qScan itself makes; transient network errors are skipped silently.

CBOM (CycloneDX)

Emit a CycloneDX 1.6 cryptographic bill of materials — one cryptographic-asset component per distinct (assetType, algorithm, discriminator), with file:line occurrence evidence — for compliance and supply-chain tooling. Findings are classified into their proper CycloneDX assetType: algorithm (crypto usage), certificate (X.509), related-crypto-material (private/public key material), and protocol (TLS):

qscan . --cbom -o qscan-cbom.json
# equivalently:
qscan . --format cbom -o qscan-cbom.json

The output is deterministic (sorted components and occurrences, stable serial number), so re-running on an unchanged tree produces byte-identical CBOMs.

VEX (OpenVEX)

Emit an OpenVEX 0.2.0 document so the quantum-readiness posture flows into the same supply-chain pipeline that already ingests CVE-based VEX:

qscan . --format vex -o qscan.openvex.json

One statement per rule (a synthetic QK-<ruleId> vulnerability), listing every affected file:line product with status: "affected" and the rule's remediation as the action_statement. PQC findings have no CVE, so qScan mints a stable per-rule identifier rather than claiming one. qScan never reports not_affected — only an operator can attest a mitigation — so downgrading a statement is left to you to post-process. When --triage is also set, each verdict (exposure score / priority / rationale) is carried in the statement's status_notes. Output is deterministic (statements sorted by vulnerability, products deduped and sorted; the @id derives from the finding set).

Triage (opt-in, BYOK)

--triage adds an optional LLM pass that re-ranks and explains findings by their real-world exposure. It is purely additive: it never suppresses a finding and never changes the exit code (that is still computed from severity alone), so it cannot mask a problem or gate CI. It is bring-your-own-key — provide an API key via QK_LLM_API_KEY (or ANTHROPIC_API_KEY / OPENAI_API_KEY); without a key, triage is skipped and the deterministic scan is unaffected.

# Re-rank + annotate findings at/above the floor (default floor: medium).
qscan . --triage

# Only triage the most serious findings, with a specific provider/model.
qscan . --triage --triage-floor high --llm-provider anthropic --llm-model claude-sonnet-5

# See exactly what would be sent — contacts nothing, needs no key.
qscan . --triage --dry-run

--context controls how much source leaves the machine (metadata | snippet | function | file, default snippet); key material is redacted on every payload (best-effort — pattern-based, so review with --dry-run). --dry-run prints the exact, redacted payload and exits without contacting the provider, so you can review what triage would send before enabling it.

Remediation (qremediate)

This package also ships a qremediate bin that applies fixes, not just reports them. It scans, then for each finding a deterministic codemod proposes a patch; every patch must clear a verify gate (the crypto finding is gone and no new crypto finding is introduced) and a patch policy (only files that have findings, plus dependency manifests) before it is offered.

qremediate .                 # print a unified diff of every verified fix (default; writes nothing)
qremediate . --mode apply    # write the verified fixes into the working tree
qremediate . --mode pr       # commit them to a new branch and open a DRAFT PR (never merges)

Deterministic codemod fixes are safe to apply directly. With --llm (BYOK, same keys as --triage), an LLM can also propose fixes codemods can't:

qremediate . --llm --mode diff   # review LLM-proposed fixes as a diff first
qremediate . --llm --mode pr     # or stage them as a draft PR

Review LLM-proposed fixes before trusting them. The verify gate only confirms the classical crypto finding was removed (a crypto-count check) — it is not a full semantic safety review, so read every LLM-proposed change as a diff. Prefer --mode diff or --mode pr for --llm fixes; --mode apply writes straight to the working tree. Draft PRs are built in an isolated git worktree (your checkout is never touched) and are never auto-merged.

CI

Fail the build on any high-or-worse finding, while tolerating an accepted baseline:

# .github/workflows/qscan.yml
name: qscan
on: [push, pull_request]

jobs:
  quantum-readiness:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - name: Scan for quantum-vulnerable crypto
        run: npx @quantakrypto/qscan . --severity-threshold high --baseline qscan-baseline.json

      # Optional: upload SARIF to GitHub code scanning.
      - name: Generate SARIF
        if: always()
        run: npx @quantakrypto/qscan . --format sarif -o qscan.sarif
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: qscan.sarif

Programmatic API

The CLI is a thin shell over runQscan, which @quantakrypto/action reuses:

import { runQscan, EXIT } from "@quantakrypto/qscan";

const { result, exitCode, suppressed } = await runQscan({
  path: "src",
  format: "json",
  severityThreshold: "high",
  baseline: "qscan-baseline.json",
});

console.log(`${result.findings.length} findings, exit ${exitCode}`);
if (exitCode === EXIT.FINDINGS) process.exitCode = 1;

runQscan never touches process or stdout — it returns the rendered report string and a suggested exitCode, leaving I/O to the caller. The package also re-exports the argument parser (parseArgs, defaultOptions), severity helpers (severityRank, meetsThreshold), and the canonical baseline utilities from @quantakrypto/core (fingerprintFinding, baselineFromFindings, applyBaseline, loadBaseline, saveBaseline) plus their legacy aliases (fingerprint, buildBaseline, readBaseline, writeBaseline) for source compatibility.

Examples

See examples/ for a sample vulnerable project and the commands to scan it.

License

Apache-2.0

Support & training

Questions, commercial support, or post-quantum readiness training for your team — visit quantakrypto.com or email [email protected].