🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@quantakrypto/core

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@quantakrypto/core

Shared post-quantum readiness library: crypto detectors, vulnerable-dependency database, inventory + SARIF reporting. Zero runtime dependencies.

Source
npmnpm
Version
0.5.0
Version published
Weekly downloads
275
-35.14%
Maintainers
1
Weekly downloads
 
Created
Source

@quantakrypto/core

Shared post-quantum readiness library for the quantakrypto toolchain. It finds classical, non-quantum-safe asymmetric cryptography in a codebase — inline crypto calls, embedded keys/certificates, and quantum-vulnerable npm dependencies — and turns the results into an inventory, a readiness score, and machine- or human-readable reports.

  • Zero runtime dependencies. Node built-ins only.
  • ESM + NodeNext, TypeScript strict, Node ≥ 20.
  • Powers @quantakrypto/qscan (CLI), the MCP server, and the GitHub Action.

Why it exists

Shor's algorithm breaks RSA, (EC)DH, ECDSA, DSA and EdDSA. Two threats follow:

  • Harvest now, decrypt later (HNDL). Traffic protected by classical key exchange / public-key encryption (ECDH, DH, RSA-OAEP) can be recorded today and decrypted once a cryptographically relevant quantum computer exists. Findings carry an hndl: true flag.
  • Forgery. Classical signatures (RSA-PSS, ECDSA, EdDSA, DSA, JWT RS*/PS*/ES*/EdDSA) can be forged by a quantum attacker. These are hndl: false but still high severity.

@quantakrypto/core flags both, and points each finding at a NIST PQC replacement (ML-KEM / FIPS 203, ML-DSA / FIPS 204, SLH-DSA / FIPS 205, hybrid X25519MLKEM768).

Install

npm install @quantakrypto/core

Quick start

import { scan, formatSummary, toSarif, toJson } from "@quantakrypto/core";

const result = await scan({ root: "./", onFile: (f) => process.stderr.write(`scanning ${f}\n`) });

console.log(formatSummary(result, { color: true })); // human report
const sarif = toSarif(result);                        // SARIF 2.1.0 for CI
const json = toJson(result);                          // structured object

API

scan(options: ScanOptions): Promise<ScanResult>

Recursively scans a directory (or a single file) and returns findings, an inventory, file count, timing, and the tool version.

interface ScanOptions {
  root: string;                 // directory or single file
  include?: string[];           // restrict the walk to matching paths (substring/prefix)
  exclude?: string[];           // extra exclude patterns (substring/prefix)
  noDefaultIgnores?: boolean;   // disable node_modules/.git/dist/… ignores
  source?: boolean;             // scan source files (default true)
  dependencies?: boolean;       // scan manifests/lockfiles across 7 ecosystems (default true)
  config?: boolean;             // scan PEM/TLS/cert config (default true)
  maxFileSize?: number;         // bytes; default 2 MiB (manifests are exempt)
  scanMinified?: boolean;       // scan minified/generated files (default false: skip them)
  files?: string[];             // explicit relative file list (incremental scans)
  detectors?: Detector[];       // override/extend the built-in detector set
  onFile?: (file: string) => void; // progress callback (relative POSIX path)
}
  • include is now wired into the walker: when set, only paths matching one of the patterns are scanned.
  • files bypasses the directory walk entirely and scans the given relative paths (used for incremental / changed-files scans — pair it with changedFiles). Binary and missing files are skipped; manifests over the size cap are still read.
  • scanMinified is off by default; machine-minified / generated / bundled content (*.bundle.js, *.generated.ts, long single-line files, …) is skipped for speed unless you opt in.

scanParallel(options): Promise<ScanResult>

A worker-thread pool over the file list with a deterministic result merge (byte-identical to scan). Falls back automatically to the in-process scan for small workloads (below ~200 files / ~2 MiB) and whenever worker_threads is unavailable. Extra options:

interface ParallelScanOptions extends ScanOptions {
  concurrency?: number;            // worker count; default os.availableParallelism()
  parallelThresholdBytes?: number; // serial below this total size (default 2 MiB)
  parallelFileThreshold?: number;  // serial below this file count (default 200)
  chunkBytes?: number;             // target bytes per worker chunk (default 4 MiB)
}

changedFiles(root, since?): Promise<string[]>

Returns relative POSIX paths that changed in a git work tree (uncommitted + untracked, plus a since ref/range when provided). Tolerant of non-git directories — returns []. Feed the result into ScanOptions.files for incremental scans.

const files = await changedFiles(".", "origin/main...HEAD");
const result = await scan({ root: ".", files });

walkFiles(root, options?): AsyncGenerator<string>

Recursive async generator yielding scannable text files as relative POSIX paths. Skips default-ignored directories (node_modules, .git, dist, build, .next, out, coverage, vendor, .turbo, .cache), honours exclude patterns (substring or path-prefix), skips obvious binaries by extension, and skips files larger than maxFileSize (default 2 MiB). root may be a single file.

for await (const file of walkFiles("./src", { exclude: ["legacy"] })) {
  console.log(file); // e.g. "components/Button.tsx"
}

detectors: Detector[] / defaultRegistry / DetectorRegistry

The built-in, pure detectors. Each declares a scope ("source" | "config"), a language, appliesTo(filePath), and detect({ file, content }). scan() drives the source/config scope toggles from the detector's declared scope (not from ruleId prefixes). Detector families:

DetectorScopeCatches
node-cryptosourcegenerateKeyPair(Sync)('rsa'|'ec'|'dsa'|'dh'|'x25519'|'x448'|'ed25519'|'ed448'), createSign/createVerify, one-shot crypto.sign/verify, createDiffieHellman, getDiffieHellman('modpN'), createECDH, publicEncrypt/privateDecrypt, diffieHellman
webcryptosourcesubtle.{generateKey,importKey,deriveKey,deriveBits,sign,verify,…} with RSA-OAEP, RSA-PSS, RSASSA-PKCS1-v1_5, ECDH, ECDSA
crypto-libssourcenode-forge (pki.rsa.generateKeyPair, ed25519), elliptic (new EC(...)), jsrsasign, node-rsa, direct secp256k1.* usage
jwt-josesourceJWT/JOSE alg strings (RS/PS/ES*, EdDSA) and ECDH-ES* key agreement (HNDL)
tls-configconfigminVersion/secureProtocol: 'TLSv1'/'TLSv1.1', rejectUnauthorized: false, weak ciphers (RC4/DES/3DES/MD5/NULL/EXPORT)
pem-materialconfigPEM keys/certs in any file: RSA/EC/DSA/PKCS#8/OPENSSH/PGP PRIVATE KEY, PGP MESSAGE, CERTIFICATE
ssh-certconfigSSH public keys (ssh-rsa, ssh-ed25519, ecdsa-sha2-*) and X.509 certificate signature algorithms (sha256WithRSAEncryption, ecdsa-with-SHA256, …)

The rows above cover JavaScript/TypeScript plus the language-agnostic PEM/SSH/TLS surfaces. Thirteen further language packs apply the same RSA/EC/DSA/DH/Ed25519 detection to other ecosystems — including a smart-contract pack (Solidity/Move/ Cairo on-chain signature verification) — each a single umbrella detector:

DetectorScopeLanguage
python-cryptosourcePython (cryptography, PyCryptodome, pyca)
go-cryptosourceGo (crypto/rsa, crypto/ecdsa, crypto/ecdh, crypto/ed25519, …)
java-cryptosourceJava/Kotlin (JCA KeyPairGenerator/Signature/KeyAgreement, BouncyCastle)
csharp-cryptosourceC#/.NET (RSA, ECDsa, ECDiffieHellman, DSA)
rust-cryptosourceRust (rsa, p256/k256 ECDSA, x25519-dalek, ed25519-dalek)
ruby-cryptosourceRuby (OpenSSL::PKey::{RSA,EC,DSA,DH})
php-cryptosourcePHP (openssl_pkey_new, phpseclib RSA/EC/DSA)
elixir-cryptosourceElixir/Erlang (:crypto, :public_key RSA/ECDSA/EdDSA)
c-cryptosourceC/C++ (OpenSSL EVP_PKEY_* / RSA_* / EC_* / DSA_* / DH_*)
swift-cryptosourceSwift (CryptoKit + Apple Security SecKey*)
objc-cryptosourceObjective-C (.m/.mm, Apple Security SecKey*)
dart-cryptosourceDart/Flutter (pointycastle, cryptography — RSA/EC/Ed25519/X25519)

defaultRegistry is a DetectorRegistry preloaded with these built-ins. The registry is the plugin point:

import { DetectorRegistry, defaultRegistry, scan } from "@quantakrypto/core";

const registry = defaultRegistry.clone().register(myDetector);
const result = await scan({ root: ".", detectors: registry.all() });

DetectorRegistry exposes register(d), get(id), has(id), all() and clone(). Ids must be unique (duplicate registration throws).

Public plugin surface vs. internal helpers. The stable, frozen way to add a detector from outside this package is the Detector interface plus the scan({ detectors }) / DetectorRegistry hook shown above — build your rule metadata with the public RuleMeta type and return Finding[]. The lexical conveniences the in-repo detectors use (findingFromRule, eachMatch, the comment maskers, hasExtension, …) are internal and intentionally not part of the frozen API: they churn with the scanner internals. The step-by-step guide below is for in-repo contributors (it edits registry.ts, detect-utils.ts, comments.ts), who can import those helpers directly.

Adding a detector / language (in-repo contributors)

  • Create src/detectors/<lang>.ts exporting one or more Detectors. Set language (a member of DetectorLanguage in types.ts — add a new one for a new language pack), scope ("source" | "config"), an appliesTo(path) extension check, and a pure detect({ file, content }) returning Finding[]. Build findings with findingFromRule(ruleMeta, at, overrides?) (not makeFinding) so every rule's metadata lives once in its RuleMeta catalog entry.
  • Define <LANG>_EXTENSIONS in detect-utils.ts next to the other packs (do not inline the list in the detector) and gate appliesTo on it.
  • Wire the new SOURCE language into coverage + comment handling (skipping this is how a pack half-lands): add the extensions to ANALYZABLE_SOURCE_EXTENSIONS and the name to ANALYZABLE_LANGUAGES_LABEL (detect-utils.ts) so analyzedFiles/coverage count it; and add them to the comment table in comments.ts (C_LIKE for //+/* */, HASH_LIKE for #) so commented-out code is suppressed. A config detector instead masks its own comment lines with maskCommentLines / maskBlockComments.
  • Register it in builtinDetectors (registry.ts) — the single source of truth the default registry and public detectors export are built from. (Ad-hoc: pass { detectors: [...] } to scan.) No edit to scan() is needed; scope is honoured from the detector's declared scope.
  • Add tests: at least one positive per rule, one negative/FP-bait, and a gating test; consider a labelled benchmark corpus fixture (test/benchmark/). For a new dependency ecosystem, also extend VulnerableDependency.ecosystem + a matcher in dependencies.ts.

vulnerableDependencies: VulnerableDependency[]

Curated database (77 entries) of packages whose purpose is classical asymmetric crypto, spanning seven ecosystems — npm, PyPI, Cargo, Go modules, Maven, RubyGems, and NuGet (VulnerableDependency.ecosystem). The npm subset includes node-forge, elliptic, jsrsasign, node-rsa, ursa, sshpk, jsonwebtoken, jose, jws, eccrypto, secp256k1, tweetnacl, ed25519, @noble/curves, @noble/secp256k1, @noble/ed25519, paseto, bcrypto, ecpair, keypair. scan() matches these against each ecosystem's manifests and lockfiles — package.json / package-lock.json / yarn.lock / pnpm-lock.yaml, requirements.txt / pyproject.toml / Pipfile, Cargo.toml, go.mod, pom.xml / build.gradle, Gemfile / *.gemspec, *.csproj / packages.config / directory.packages.props — and emits category: "dependency" findings located at the manifest.

buildInventory(findings: Finding[]): CryptoInventory

Aggregates findings into per-algorithm / per-category / per-severity counts, the HNDL count, and a readinessScore (0–100, 100 = no classical asymmetric crypto found). The score starts at 100 and subtracts severity-weighted penalties with diminishing returns per severity bucket, clamped to [0, 100].

Reporters

  • toSarif(result): SarifLog — valid SARIF 2.1.0 ($schema, version, runs[0].tool.driver { name: "qScan", informationUri, version, rules[] }, results[] with ruleId, level (error/warning/note), message.text, locations[].physicalLocation with artifactLocation.uri and region.startLine/startColumn).
  • toJson(result): Record<string, unknown> — clean, JSON-serialisable object.
  • formatSummary(result, { color? }): string — human report with the readiness score, severity/algorithm breakdown, top findings, and an HNDL note. Colour is off by default and uses raw ANSI codes when enabled.

remediationFor(algorithm): Remediation | undefined / remediationForTier(algorithm, tier?)

remediationFor returns the recommended PQC replacement for a classical family. remediationForTier adds a security tier: "category-3" (default, commercial — ML-KEM-768 / ML-DSA-65) or "category-5" (CNSA 2.0 / long-lived — ML-KEM-1024 / ML-DSA-87).

remediationFor("ECDH");
// { algorithm: "ECDH", recommendation: "hybrid X25519MLKEM768 (ML-KEM-768)", detail: … }

remediationForTier("ECDH", "category-5");
// recommendation mentions ML-KEM-1024; detail cites CNSA 2.0 (2030/2033 milestones)

STATEFUL_HBS_NOTE / statefulHbsApplies(algorithm) surface the SP 800-208 stateful hash-based signatures (LMS / XMSS / HSS) guidance for firmware / boot signing (stateful — use only with rigorous state management).

Baseline (fingerprintFinding, baselineFromFindings, applyBaseline, loadBaseline, saveBaseline)

The single canonical baseline scheme shared by qScan and the Action. A baseline is { version, fingerprints: string[] }. A fingerprint is the SHA-256 hex of ruleId|file|normalizedSnippetline-insensitive (survives line shifts) and snippet-whitespace-normalized (survives reformatting).

import { saveBaseline, loadBaseline, applyBaseline } from "@quantakrypto/core";

await saveBaseline(".quantakrypto-baseline.json", result.findings);          // write
const baseline = await loadBaseline(".quantakrypto-baseline.json");          // read (tolerant)
const { newFindings, suppressed } = applyBaseline(result.findings, baseline);

toCbom(result): CycloneDxBom

A CycloneDX 1.6 cryptographic bill of materials (CBOM): one cryptographic-asset component per distinct (assetType, algorithm, discriminator), with occurrence evidence and quantumVulnerable / harvestNowDecryptLater flags. Each finding is classified into its proper CycloneDX assetTypealgorithm (crypto usage), certificate (X.509), related-crypto-material (private/public key material), or protocol (TLS). Deterministic output.

toOpenVex(result, opts?): OpenVexDocument

An OpenVEX 0.2.0 document: one statement per rule (a synthetic QK-<ruleId> vulnerability, since PQC findings have no CVE), every affected file:line product, status: "affected", the rule's remediation as action_statement, and any --triage verdict in status_notes. Deterministic output; feeds VEX pipelines.

Evidence chain — buildReadinessReport / signReadinessReport / verifyReadinessReport

The ISO/IEC 27001 A.8.24 readiness report (see docs/compliance/iso27001-a8.24-evidence.md):

  • buildReadinessReport(result, opts?) — bundles the scan result, inventory, CBOM, and a deterministic attestation.contentHash (excludes the volatile scan time).
  • signReadinessReport(report, { signer?, timestamper? }) — orchestrates an EXTERNAL signer/timestamper over the contentHash (ADR-0004; the tool implements no crypto).
  • verifyReadinessReport(report) — recomputes the content hash to detect tampering with any attested field, returning { valid, computedHash, claimedHash, reason? }.

CWE tagging

Every detector sets a Finding.cwe (CWE-327 broken crypto, CWE-326 weak strength, CWE-295 cert validation, CWE-798 hardcoded key). toSarif maps it into rules[].properties, result taxa, and a run-level CWE taxonomies component; toJson includes it. Constants are exported (CWE_BROKEN_CRYPTO, …).

VERSION: string

Tool version surfaced in reports (kept in sync with package.json).

API reference

ExportKindSummary
scanfnScan a dir / file / explicit file list → ScanResult
scanParallelfnWorker-pool scan with deterministic merge + serial fallback
changedFilesfnGit-aware changed-files list for incremental scans
detectFilefnPure per-file detect (used by workers / tests)
compareFindingsfnStable finding comparator (file → line → ruleId)
walkFiles, isBinaryPath, looksMinifiedfnWalker + file-classification helpers
detectorsconstBuilt-in detector array (mirrors defaultRegistry.all())
DetectorRegistry, defaultRegistryclass/constDetector plugin point
buildInventoryfnAggregate findings → CryptoInventory
vulnerableDependenciesconstCurated quantum-vulnerable dependency DB (7 ecosystems)
toSarif, toJson, formatSummaryfnReporters (SARIF 2.1.0 / JSON / human)
toCbomfnCycloneDX 1.6 CBOM export (assetType-classified)
toOpenVexfnOpenVEX 0.2.0 export
buildReadinessReport, signReadinessReport, verifyReadinessReportfnISO A.8.24 evidence chain (build / sign / verify)
remediationFor, remediationForTier, TIER_PARAMSfn/constPQC remediation (family + CNSA tier)
STATEFUL_HBS_NOTE, statefulHbsAppliesconst/fnSP 800-208 LMS/XMSS guidance
fingerprintFinding, baselineFromFindings, applyBaseline, loadBaseline, saveBaseline, BASELINE_VERSIONfn/constCanonical baseline
verifyFix, languageToExtensionfnSnippet-level fix verification (crypto finding removed?) + language→extension map
buildContext, renderPreflightfnRedacted source-context builder + preflight preview (secrets stripped)
TRIAGE_RUBRIC, TRIAGE_VERDICT_SCHEMA, buildTriageRequestconst/fnDeterministic, offline triage-request bundle (rubric + verdict schema)
REMEDIATE_RUBRIC, FIX_REQUEST_SCHEMA, buildRemediateRequestconst/fnDeterministic, offline remediation-request bundle (rubric + fix schema)
checkPatchPolicyfnPatch-policy gate — only files with findings + dependency manifests
withWorktreefnRun a callback inside an ephemeral git worktree (isolates writes; no auto-merge)
codemodRegistry, codemodFor, configToggleCodemodconst/fnDeterministic codemod registry + per-finding lookup
remediateFindingsfnRemediation pipeline: propose → policy + verify gate → verified patches
loadConfig, ConfigError, CONFIG_FILENAMEfn/constquantakrypto.config.json loader
AbortError, BudgetExceededErrorclassScan cancellation / work-budget overflow errors
CWE_BROKEN_CRYPTO, CWE_WEAK_STRENGTH, CWE_CERT_VALIDATION, CWE_HARDCODED_KEY, CWE_RISKY_PRIMITIVEconstCWE identifiers
VERSIONconstTool version

Types: Finding (now with optional cwe), ScanOptions/ParallelScanOptions, ScanResult, Detector (now with scope/language), DetectorScope, DetectorLanguage, Baseline, CycloneDxBom, CbomComponent, SecurityTier, AlgorithmFamily (now includes X448), and the rest of the locked contract in src/types.ts.

Core types

See src/types.ts for the locked contract. Highlights:

type Severity = "critical" | "high" | "medium" | "low" | "info";

type AlgorithmFamily =
  | "RSA" | "ECDH" | "ECDSA" | "EdDSA"
  | "DH"  | "DSA"  | "X25519" | "X448" | "ECIES" | "unknown";

type FindingCategory =
  | "kem" | "key-exchange" | "signature"
  | "tls" | "certificate"  | "dependency" | "hash" | "rng";

interface Finding {
  ruleId: string;
  title: string;
  category: FindingCategory;
  severity: Severity;
  confidence: "high" | "medium" | "low";
  algorithm?: AlgorithmFamily;
  hndl: boolean;          // harvest-now-decrypt-later exposure
  message: string;
  remediation?: string;
  cwe?: string;           // e.g. "CWE-327"
  location: { file: string; line: number; column?: number; endLine?: number; snippet?: string };
}

interface CryptoInventory {
  byAlgorithm: Partial<Record<AlgorithmFamily, number>>;
  byCategory: Partial<Record<FindingCategory, number>>;
  bySeverity: Record<Severity, number>;
  hndlCount: number;
  readinessScore: number; // 0–100
}

Example

A runnable example lives in examples/scan-example.mjs:

node examples/scan-example.mjs ./path/to/project

Development

npm run build   # tsc -b
npm test        # node --import tsx --test test/*.test.ts

Tests use only node:test + node:assert. The package has zero runtime dependencies.

License

Apache-2.0

Support & training

Questions, commercial support, or post-quantum readiness training for your team — visit quantakrypto.com or email hello@quantakrypto.com.

FAQs

Package last updated on 20 Jul 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts