@quantakrypto/core 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -27
- package/dist/cbom-merge.d.ts +9 -0
- package/dist/cbom-merge.d.ts.map +1 -0
- package/dist/cbom-merge.js +121 -0
- package/dist/cbom-merge.js.map +1 -0
- package/dist/cbom.d.ts +5 -0
- package/dist/cbom.d.ts.map +1 -1
- package/dist/cbom.js +132 -37
- package/dist/cbom.js.map +1 -1
- package/dist/comments.d.ts +6 -26
- package/dist/comments.d.ts.map +1 -1
- package/dist/comments.js +77 -38
- package/dist/comments.js.map +1 -1
- package/dist/dependencies.d.ts.map +1 -1
- package/dist/dependencies.js +1 -1
- package/dist/dependencies.js.map +1 -1
- package/dist/detect-utils.d.ts +59 -21
- package/dist/detect-utils.d.ts.map +1 -1
- package/dist/detect-utils.js +143 -8
- package/dist/detect-utils.js.map +1 -1
- package/dist/detectors/age.d.ts +16 -0
- package/dist/detectors/age.d.ts.map +1 -0
- package/dist/detectors/age.js +40 -0
- package/dist/detectors/age.js.map +1 -0
- package/dist/detectors/ansible.d.ts +13 -0
- package/dist/detectors/ansible.d.ts.map +1 -0
- package/dist/detectors/ansible.js +108 -0
- package/dist/detectors/ansible.js.map +1 -0
- package/dist/detectors/bicep.d.ts +20 -0
- package/dist/detectors/bicep.d.ts.map +1 -0
- package/dist/detectors/bicep.js +74 -0
- package/dist/detectors/bicep.js.map +1 -0
- package/dist/detectors/c.d.ts +4 -2
- package/dist/detectors/c.d.ts.map +1 -1
- package/dist/detectors/c.js +222 -4
- package/dist/detectors/c.js.map +1 -1
- package/dist/detectors/cicd.d.ts +27 -0
- package/dist/detectors/cicd.d.ts.map +1 -0
- package/dist/detectors/cicd.js +129 -0
- package/dist/detectors/cicd.js.map +1 -0
- package/dist/detectors/cloud-kms.d.ts +24 -0
- package/dist/detectors/cloud-kms.d.ts.map +1 -0
- package/dist/detectors/cloud-kms.js +99 -0
- package/dist/detectors/cloud-kms.js.map +1 -0
- package/dist/detectors/cloudformation.d.ts +38 -0
- package/dist/detectors/cloudformation.d.ts.map +1 -0
- package/dist/detectors/cloudformation.js +201 -0
- package/dist/detectors/cloudformation.js.map +1 -0
- package/dist/detectors/codesign.d.ts +50 -0
- package/dist/detectors/codesign.d.ts.map +1 -0
- package/dist/detectors/codesign.js +143 -0
- package/dist/detectors/codesign.js.map +1 -0
- package/dist/detectors/csharp.d.ts.map +1 -1
- package/dist/detectors/csharp.js +13 -3
- package/dist/detectors/csharp.js.map +1 -1
- package/dist/detectors/dart.d.ts +35 -0
- package/dist/detectors/dart.d.ts.map +1 -0
- package/dist/detectors/dart.js +177 -0
- package/dist/detectors/dart.js.map +1 -0
- package/dist/detectors/database.d.ts +19 -0
- package/dist/detectors/database.d.ts.map +1 -0
- package/dist/detectors/database.js +97 -0
- package/dist/detectors/database.js.map +1 -0
- package/dist/detectors/dkim.d.ts +54 -0
- package/dist/detectors/dkim.d.ts.map +1 -0
- package/dist/detectors/dkim.js +92 -0
- package/dist/detectors/dkim.js.map +1 -0
- package/dist/detectors/dnssec.d.ts +55 -0
- package/dist/detectors/dnssec.d.ts.map +1 -0
- package/dist/detectors/dnssec.js +116 -0
- package/dist/detectors/dnssec.js.map +1 -0
- package/dist/detectors/elixir.d.ts +20 -0
- package/dist/detectors/elixir.d.ts.map +1 -0
- package/dist/detectors/elixir.js +227 -0
- package/dist/detectors/elixir.js.map +1 -0
- package/dist/detectors/java.d.ts.map +1 -1
- package/dist/detectors/java.js +34 -4
- package/dist/detectors/java.js.map +1 -1
- package/dist/detectors/jose.d.ts +20 -0
- package/dist/detectors/jose.d.ts.map +1 -0
- package/dist/detectors/jose.js +72 -0
- package/dist/detectors/jose.js.map +1 -0
- package/dist/detectors/jwk.d.ts +25 -0
- package/dist/detectors/jwk.d.ts.map +1 -0
- package/dist/detectors/jwk.js +131 -0
- package/dist/detectors/jwk.js.map +1 -0
- package/dist/detectors/k8s.d.ts +17 -0
- package/dist/detectors/k8s.d.ts.map +1 -0
- package/dist/detectors/k8s.js +88 -0
- package/dist/detectors/k8s.js.map +1 -0
- package/dist/detectors/keystore.d.ts +19 -0
- package/dist/detectors/keystore.d.ts.map +1 -0
- package/dist/detectors/keystore.js +76 -0
- package/dist/detectors/keystore.js.map +1 -0
- package/dist/detectors/mesh.d.ts +34 -0
- package/dist/detectors/mesh.d.ts.map +1 -0
- package/dist/detectors/mesh.js +91 -0
- package/dist/detectors/mesh.js.map +1 -0
- package/dist/detectors/messaging.d.ts +16 -0
- package/dist/detectors/messaging.d.ts.map +1 -0
- package/dist/detectors/messaging.js +79 -0
- package/dist/detectors/messaging.js.map +1 -0
- package/dist/detectors/objc.d.ts +41 -0
- package/dist/detectors/objc.d.ts.map +1 -0
- package/dist/detectors/objc.js +146 -0
- package/dist/detectors/objc.js.map +1 -0
- package/dist/detectors/openpgp.d.ts +20 -0
- package/dist/detectors/openpgp.d.ts.map +1 -0
- package/dist/detectors/openpgp.js +151 -0
- package/dist/detectors/openpgp.js.map +1 -0
- package/dist/detectors/pem.d.ts.map +1 -1
- package/dist/detectors/pem.js +33 -1
- package/dist/detectors/pem.js.map +1 -1
- package/dist/detectors/php.d.ts +25 -0
- package/dist/detectors/php.d.ts.map +1 -0
- package/dist/detectors/php.js +171 -0
- package/dist/detectors/php.js.map +1 -0
- package/dist/detectors/pkcs11.d.ts +17 -0
- package/dist/detectors/pkcs11.d.ts.map +1 -0
- package/dist/detectors/pkcs11.js +87 -0
- package/dist/detectors/pkcs11.js.map +1 -0
- package/dist/detectors/proxy.d.ts +52 -0
- package/dist/detectors/proxy.d.ts.map +1 -0
- package/dist/detectors/proxy.js +157 -0
- package/dist/detectors/proxy.js.map +1 -0
- package/dist/detectors/pulumi.d.ts +19 -0
- package/dist/detectors/pulumi.d.ts.map +1 -0
- package/dist/detectors/pulumi.js +80 -0
- package/dist/detectors/pulumi.js.map +1 -0
- package/dist/detectors/python.d.ts.map +1 -1
- package/dist/detectors/python.js +70 -0
- package/dist/detectors/python.js.map +1 -1
- package/dist/detectors/rust.d.ts.map +1 -1
- package/dist/detectors/rust.js +73 -0
- package/dist/detectors/rust.js.map +1 -1
- package/dist/detectors/secrets.d.ts +24 -0
- package/dist/detectors/secrets.d.ts.map +1 -0
- package/dist/detectors/secrets.js +63 -0
- package/dist/detectors/secrets.js.map +1 -0
- package/dist/detectors/solidity.d.ts +50 -0
- package/dist/detectors/solidity.d.ts.map +1 -0
- package/dist/detectors/solidity.js +108 -0
- package/dist/detectors/solidity.js.map +1 -0
- package/dist/detectors/source.d.ts.map +1 -1
- package/dist/detectors/source.js +243 -53
- package/dist/detectors/source.js.map +1 -1
- package/dist/detectors/spire.d.ts +49 -0
- package/dist/detectors/spire.d.ts.map +1 -0
- package/dist/detectors/spire.js +77 -0
- package/dist/detectors/spire.js.map +1 -0
- package/dist/detectors/ssh-ca.d.ts +72 -0
- package/dist/detectors/ssh-ca.d.ts.map +1 -0
- package/dist/detectors/ssh-ca.js +119 -0
- package/dist/detectors/ssh-ca.js.map +1 -0
- package/dist/detectors/stateful-hbs.d.ts.map +1 -1
- package/dist/detectors/stateful-hbs.js +9 -6
- package/dist/detectors/stateful-hbs.js.map +1 -1
- package/dist/detectors/supply-chain.d.ts +17 -0
- package/dist/detectors/supply-chain.d.ts.map +1 -0
- package/dist/detectors/supply-chain.js +89 -0
- package/dist/detectors/supply-chain.js.map +1 -0
- package/dist/detectors/swift.d.ts +22 -0
- package/dist/detectors/swift.d.ts.map +1 -0
- package/dist/detectors/swift.js +120 -0
- package/dist/detectors/swift.js.map +1 -0
- package/dist/detectors/terraform.d.ts +21 -0
- package/dist/detectors/terraform.d.ts.map +1 -0
- package/dist/detectors/terraform.js +150 -0
- package/dist/detectors/terraform.js.map +1 -0
- package/dist/detectors/vault.d.ts +15 -0
- package/dist/detectors/vault.d.ts.map +1 -0
- package/dist/detectors/vault.js +97 -0
- package/dist/detectors/vault.js.map +1 -0
- package/dist/detectors/vpn.d.ts +22 -0
- package/dist/detectors/vpn.d.ts.map +1 -0
- package/dist/detectors/vpn.js +73 -0
- package/dist/detectors/vpn.js.map +1 -0
- package/dist/detectors/weak-hash.d.ts +71 -0
- package/dist/detectors/weak-hash.d.ts.map +1 -0
- package/dist/detectors/weak-hash.js +116 -0
- package/dist/detectors/weak-hash.js.map +1 -0
- package/dist/detectors/webauthn.d.ts +61 -0
- package/dist/detectors/webauthn.d.ts.map +1 -0
- package/dist/detectors/webauthn.js +109 -0
- package/dist/detectors/webauthn.js.map +1 -0
- package/dist/detectors/xmldsig.d.ts +23 -0
- package/dist/detectors/xmldsig.d.ts.map +1 -0
- package/dist/detectors/xmldsig.js +84 -0
- package/dist/detectors/xmldsig.js.map +1 -0
- package/dist/evidence.d.ts +79 -4
- package/dist/evidence.d.ts.map +1 -1
- package/dist/evidence.js +76 -0
- package/dist/evidence.js.map +1 -1
- package/dist/index.d.ts +17 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -9
- package/dist/index.js.map +1 -1
- package/dist/inventory.d.ts +0 -2
- package/dist/inventory.d.ts.map +1 -1
- package/dist/inventory.js +15 -6
- package/dist/inventory.js.map +1 -1
- package/dist/policy.d.ts +67 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +115 -0
- package/dist/policy.js.map +1 -0
- package/dist/registry.d.ts +9 -4
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +81 -4
- package/dist/registry.js.map +1 -1
- package/dist/remediate-pipeline.d.ts +0 -3
- package/dist/remediate-pipeline.d.ts.map +1 -1
- package/dist/remediate-pipeline.js +23 -2
- package/dist/remediate-pipeline.js.map +1 -1
- package/dist/remediation.d.ts +10 -0
- package/dist/remediation.d.ts.map +1 -1
- package/dist/remediation.js +32 -0
- package/dist/remediation.js.map +1 -1
- package/dist/report.d.ts +9 -0
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +38 -1
- package/dist/report.js.map +1 -1
- package/dist/scan-worker.js +5 -3
- package/dist/scan-worker.js.map +1 -1
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +35 -6
- package/dist/scan.js.map +1 -1
- package/dist/standards-profiles.d.ts +58 -0
- package/dist/standards-profiles.d.ts.map +1 -0
- package/dist/standards-profiles.js +100 -0
- package/dist/standards-profiles.js.map +1 -0
- package/dist/standards.d.ts +96 -0
- package/dist/standards.d.ts.map +1 -0
- package/dist/standards.js +107 -0
- package/dist/standards.js.map +1 -0
- package/dist/types.d.ts +6 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/vex.d.ts +39 -0
- package/dist/vex.d.ts.map +1 -0
- package/dist/vex.js +87 -0
- package/dist/vex.js.map +1 -0
- package/dist/walk.d.ts +8 -3
- package/dist/walk.d.ts.map +1 -1
- package/dist/walk.js +32 -1
- package/dist/walk.js.map +1 -1
- package/package.json +1 -1
- package/src/cbom-merge.ts +146 -0
- package/src/cbom.ts +153 -39
- package/src/comments.ts +84 -39
- package/src/dependencies.ts +2 -1
- package/src/detect-utils.ts +146 -12
- package/src/detectors/age.ts +60 -0
- package/src/detectors/ansible.ts +140 -0
- package/src/detectors/bicep.ts +107 -0
- package/src/detectors/c.ts +240 -6
- package/src/detectors/cicd.ts +171 -0
- package/src/detectors/cloud-kms.ts +141 -0
- package/src/detectors/cloudformation.ts +250 -0
- package/src/detectors/codesign.ts +214 -0
- package/src/detectors/csharp.ts +13 -3
- package/src/detectors/dart.ts +237 -0
- package/src/detectors/database.ts +141 -0
- package/src/detectors/dkim.ts +172 -0
- package/src/detectors/dnssec.ts +195 -0
- package/src/detectors/elixir.ts +268 -0
- package/src/detectors/java.ts +39 -4
- package/src/detectors/jose.ts +110 -0
- package/src/detectors/jwk.ts +170 -0
- package/src/detectors/k8s.ts +115 -0
- package/src/detectors/keystore.ts +109 -0
- package/src/detectors/mesh.ts +130 -0
- package/src/detectors/messaging.ts +106 -0
- package/src/detectors/objc.ts +209 -0
- package/src/detectors/openpgp.ts +194 -0
- package/src/detectors/pem.ts +31 -1
- package/src/detectors/php.ts +230 -0
- package/src/detectors/pkcs11.ts +113 -0
- package/src/detectors/proxy.ts +236 -0
- package/src/detectors/pulumi.ts +106 -0
- package/src/detectors/python.ts +71 -0
- package/src/detectors/rust.ts +76 -0
- package/src/detectors/secrets.ts +103 -0
- package/src/detectors/solidity.ts +176 -0
- package/src/detectors/source.ts +283 -73
- package/src/detectors/spire.ts +143 -0
- package/src/detectors/ssh-ca.ts +215 -0
- package/src/detectors/stateful-hbs.ts +9 -6
- package/src/detectors/supply-chain.ts +117 -0
- package/src/detectors/swift.ts +149 -0
- package/src/detectors/terraform.ts +188 -0
- package/src/detectors/vault.ts +120 -0
- package/src/detectors/vpn.ts +103 -0
- package/src/detectors/weak-hash.ts +217 -0
- package/src/detectors/webauthn.ts +205 -0
- package/src/detectors/xmldsig.ts +115 -0
- package/src/evidence.ts +138 -4
- package/src/index.ts +50 -12
- package/src/inventory.ts +15 -7
- package/src/policy.ts +180 -0
- package/src/registry.ts +81 -4
- package/src/remediate-pipeline.ts +26 -3
- package/src/remediation.ts +39 -0
- package/src/report.ts +43 -1
- package/src/scan-worker.ts +5 -3
- package/src/scan.ts +41 -6
- package/src/standards-profiles.ts +136 -0
- package/src/standards.ts +186 -0
- package/src/types.ts +11 -4
- package/src/version.ts +1 -1
- package/src/vex.ts +122 -0
- package/src/walk.ts +33 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/detectors/source.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Source-code detectors for classical, non-quantum-safe asymmetric cryptography\n * in JavaScript / TypeScript. Each detector is pure and stateless: it declares\n * which files it applies to, the catalog of rules it can emit (`rules`), and\n * returns zero or more Findings for a file's contents.\n *\n * Rule metadata (title / severity / category / remediation / …) lives ONCE in\n * the per-detector `RuleMeta` declarations below, not inline in `detect()`.\n * `detect()` builds findings from those declarations via `findingFromRule`,\n * overriding only the fields that genuinely vary per match (e.g. the concrete\n * algorithm family of a `generateKeyPair('ec')` call). The declarations are the\n * catalog surfaced by the registry, SARIF `rules[]`, and the MCP resolver.\n *\n * The detection strategy is deliberately lexical (regex over source text). This\n * is robust to bundling and partial files and keeps the package dependency-free.\n * Confidence is set per-pattern to reflect how specific the match is.\n *\n * All per-file regexes are precompiled at module scope (not re-created per\n * file) — `eachMatch` clones a fresh stateful copy only when a regex lacks the\n * global flag, and these are all global, so they are reused safely.\n *\n * HNDL (harvest-now-decrypt-later) policy:\n * - confidentiality primitives (key exchange / KEM: ECDH, DH, RSA-OAEP) → hndl:true\n * - signatures (RSA-PSS, ECDSA, EdDSA, DSA, JWT alg) → hndl:false, but still high\n * severity because a quantum attacker can forge them.\n * - EC keygen is ambiguous (an 'ec' key feeds BOTH ECDSA and ECDH); it is\n * classified conservatively as key-exchange-capable (hndl:true).\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport {\n JS_TS_EXTENSIONS,\n DOC_EXTENSIONS,\n JWT_HOST_EXTENSIONS,\n eachMatch,\n findingFromRule,\n hasExtension,\n nearSortedCall,\n} from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO, CWE_CERT_VALIDATION, CWE_WEAK_STRENGTH } from \"../cwe.js\";\n\n/* -------------------------------------------------------------------------- */\n/* Precompiled regexes (module scope — never recreated per file) */\n/* -------------------------------------------------------------------------- */\n\n// `rsa-pss` is listed before `rsa` so the alternation consumes the full token\n// (ordered alternation would otherwise match `rsa` and reject the `-pss` tail).\nconst RE_GENERATE_KEYPAIR =\n /generateKeyPair(?:Sync)?\\s*\\(\\s*['\"`](rsa-pss|rsa|ec|dsa|dh|x25519|x448|ed25519|ed448)['\"`]/g;\nconst RE_CREATE_SIGN_VERIFY = /create(?:Sign|Verify)\\s*\\(/g;\n// One-shot crypto.sign/verify(algorithm, data, key). A LOOKBEHIND (not a\n// consumed char) anchors it so it doesn't fire inside identifiers like `assign(`\n// or `createSign(` (handled by the dedicated createSign/createVerify rule) —\n// consuming the preceding char used to push the match onto the previous line,\n// corrupting the reported line/snippet and SARIF/baseline fingerprints. The\n// first argument is either a quoted digest-algorithm string (RSA/ECDSA) or\n// `null` — Node's EdDSA one-shot form is `crypto.sign(null, data, edKey)`.\nconst RE_ONESHOT_SIGN_VERIFY =\n /(?<![.\\w])(?:crypto\\.)?(sign|verify)\\s*\\(\\s*(?:['\"`][\\w.-]+['\"`]|null)\\s*,/g;\nconst RE_CREATE_DH = /createDiffieHellman(?:Group)?\\s*\\(/g;\nconst RE_GET_DH = /getDiffieHellman\\s*\\(\\s*['\"`](modp\\d+)['\"`]\\s*\\)/g;\nconst RE_CREATE_ECDH = /createECDH\\s*\\(/g;\nconst RE_RSA_ENCRYPT = /(?:crypto\\.)?(?:publicEncrypt|privateDecrypt)\\s*\\(/g;\nconst RE_DH_KEYOBJECT = /(?:crypto\\.)?diffieHellman\\s*\\(\\s*\\{/g;\n\n// WebCrypto. Includes the newer curve algorithms (Ed25519/Ed448 signatures,\n// X25519/X448 key agreement) shipping in modern SubtleCrypto implementations.\nconst RE_WEBCRYPTO_ALGO =\n /\\b(RSA-OAEP|RSA-PSS|RSASSA-PKCS1-v1_5|ECDH|ECDSA|Ed25519|Ed448|X25519|X448)\\b/gi;\nconst RE_SUBTLE_CALL =\n /subtle\\s*\\.\\s*(generateKey|importKey|exportKey|deriveKey|deriveBits|sign|verify|encrypt|decrypt|wrapKey|unwrapKey)\\s*\\(/g;\n\n// Libraries.\nconst RE_FORGE_RSA = /pki\\.rsa\\.generateKeyPair\\s*\\(/g;\nconst RE_FORGE_ED25519 = /forge\\.ed25519\\b/g;\n// Require a curve-like first argument so `new EC(\"request-scope\")` (a non-crypto\n// `EC` class) is not flagged; the elliptic library is always constructed with a\n// named curve (`new EC('secp256k1')`, `new EC('p256')`, …).\nconst RE_ELLIPTIC_EC =\n /new\\s+(?:elliptic\\.)?ec\\s*\\(\\s*['\"`](?:sec[pt]|prime|nistp|curve|ed25519|ed448|brainpool|p-?(?:192|224|256|384|521)|x25519|x448)/gi;\nconst RE_JSRSASIGN_KEYGEN = /KEYUTIL\\.generateKeypair\\s*\\(/g;\nconst RE_JSRSASIGN_SIGN = /KJUR\\.crypto\\.(?:Signature|ECDSA)\\b/g;\nconst RE_NODE_RSA = /new\\s+NodeRSA\\s*\\(/g;\n// secp256k1 — direct @noble/secp256k1 / secp256k1-style API usage in source.\nconst RE_SECP256K1 =\n /\\b(?:secp(?:256k1)?|secp)\\s*\\.\\s*(?:sign|verify|getPublicKey|getSharedSecret|ecdh|recoverPublicKey)\\s*\\(/g;\n\n// JWT/JOSE.\nconst RE_JWT_ALG = /['\"`](RS(?:256|384|512)|PS(?:256|384|512)|ES(?:256|384|512|256K)|EdDSA)['\"`]/g;\n// JOSE ECDH-ES key agreement (HNDL) and COSE algorithm identifiers.\nconst RE_JOSE_ECDH = /['\"`](ECDH-ES(?:\\+A(?:128|192|256)KW)?)['\"`]/g;\n\n// TLS config.\nconst RE_TLS_LEGACY_VERSION =\n /(?:minVersion|maxVersion)\\s*:\\s*['\"`]TLSv1(?:\\.1)?['\"`]|secureProtocol\\s*:\\s*['\"`]TLSv1(?:_1)?_method['\"`]/g;\nconst RE_TLS_REJECT = /rejectUnauthorized\\s*:\\s*false/g;\n// Hardened cipher regex: bounded spans (no unbounded `[^'\"`]*` straddling the\n// alternation), single-quote-style anchoring removed in favour of {0,256} bounds\n// so worst-case backtracking is linear in the bound, not the file (P0-6).\n// The `(?<![!-])` lookbehind skips OpenSSL EXCLUSION syntax — `!MD5` / `-RC4`\n// DISABLE those ciphers, so a hardened list like `...:!aNULL:!MD5:!RC4` must not\n// be flagged as weak (audit: crypto #7). A genuinely-enabled `RC4` still matches.\nconst RE_TLS_WEAK_CIPHER =\n /ciphers\\s*:\\s*['\"`][^'\"`\\n]{0,256}?\\b(?<![!-])(RC4|DES|3DES|MD5|NULL|EXPORT|aNULL|eNULL)\\b[^'\"`\\n]{0,256}?['\"`]/gi;\n\n/* -------------------------------------------------------------------------- */\n/* Node.js `crypto` module */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Rule catalog for the Node `crypto` detector. `node-crypto-keygen` and\n * `node-crypto-dh-modp` refine some fields per match; the rest emit findings\n * straight from these declarations.\n */\nconst RULE_NODE_KEYGEN: RuleMeta = {\n id: \"node-crypto-keygen\",\n title: \"Classical key generation\",\n description: \"crypto.generateKeyPair(Sync)('rsa'|'ec'|'dsa'|'dh'|…)\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Generates a classical asymmetric key pair, which is not quantum-safe.\",\n};\nconst RULE_NODE_SIGN: RuleMeta = {\n id: \"node-crypto-sign\",\n title: \"Classical signature (createSign/createVerify)\",\n description: \"crypto.createSign / crypto.createVerify\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Uses createSign/createVerify, typically RSA, ECDSA or DSA — all forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n};\nconst RULE_NODE_SIGN_ONESHOT: RuleMeta = {\n id: \"node-crypto-sign-oneshot\",\n title: \"Classical one-shot signature (crypto.sign/verify)\",\n description: \"one-shot crypto.sign / crypto.verify (Node ≥ 12)\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Uses the one-shot crypto.sign/crypto.verify API, typically RSA/ECDSA/EdDSA — forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n};\nconst RULE_NODE_DH: RuleMeta = {\n id: \"node-crypto-dh\",\n title: \"Diffie-Hellman key exchange\",\n description: \"crypto.createDiffieHellman(Group)\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"DH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Finite-field Diffie-Hellman is broken by Shor's algorithm (harvest-now-decrypt-later).\",\n};\nconst RULE_NODE_DH_MODP: RuleMeta = {\n id: \"node-crypto-dh-modp\",\n title: \"Diffie-Hellman MODP group\",\n description: \"crypto.getDiffieHellman('modpN')\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"DH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Named finite-field DH MODP group is broken by Shor's algorithm (harvest-now-decrypt-later).\",\n};\nconst RULE_NODE_ECDH: RuleMeta = {\n id: \"node-crypto-ecdh\",\n title: \"ECDH key exchange\",\n description: \"crypto.createECDH\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Elliptic-curve Diffie-Hellman is broken by Shor's algorithm (harvest-now-decrypt-later).\",\n};\nconst RULE_NODE_RSA_ENCRYPT: RuleMeta = {\n id: \"node-crypto-rsa-encrypt\",\n title: \"RSA public-key encryption\",\n description: \"crypto.publicEncrypt / crypto.privateDecrypt\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"RSA public-key encryption is broken by Shor's algorithm and exposed to harvest-now-decrypt-later.\",\n};\nconst RULE_NODE_DH_KEYOBJECT: RuleMeta = {\n id: \"node-crypto-dh-keyobject\",\n title: \"Diffie-Hellman (KeyObject) key exchange\",\n description: \"crypto.diffieHellman({ privateKey, publicKey })\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"crypto.diffieHellman() performs a classical (EC)DH agreement (harvest-now-decrypt-later).\",\n};\n\n/** Detects classical asymmetric usage from Node's built-in `crypto` module. */\nconst nodeCryptoDetector: Detector = {\n id: \"node-crypto\",\n description: \"Classical asymmetric crypto via the Node.js `crypto` module\",\n scope: \"source\",\n language: \"js\",\n rules: [\n RULE_NODE_KEYGEN,\n RULE_NODE_SIGN,\n RULE_NODE_SIGN_ONESHOT,\n RULE_NODE_DH,\n RULE_NODE_DH_MODP,\n RULE_NODE_ECDH,\n RULE_NODE_RSA_ENCRYPT,\n RULE_NODE_DH_KEYOBJECT,\n ],\n appliesTo: (f) => hasExtension(f, JS_TS_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n\n // generateKeyPair(Sync)('rsa' | 'ec' | 'dsa' | 'dh' | 'x25519' | 'ed25519', ...)\n eachMatch(RE_GENERATE_KEYPAIR, content, (m) => {\n const type = m[1].toLowerCase();\n const map: Record<\n string,\n {\n algo: Finding[\"algorithm\"];\n cat: Finding[\"category\"];\n sev: Finding[\"severity\"];\n hndl: boolean;\n label: string;\n message?: string;\n remediation?: string;\n }\n > = {\n rsa: { algo: \"RSA\", cat: \"kem\", sev: \"high\", hndl: true, label: \"RSA\" },\n // RSA-PSS is signature-only, so classify it as a (forgeable) signature\n // rather than a KEM — no HNDL confidentiality exposure.\n \"rsa-pss\": {\n algo: \"RSA\",\n cat: \"signature\",\n sev: \"high\",\n hndl: false,\n label: \"RSA-PSS\",\n message:\n \"Generates a classical RSA-PSS signing key, which is forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n },\n // EC keys feed BOTH ECDSA (sign) and ECDH (key agreement). ECDH is\n // HNDL-exposed, so classify conservatively as key-exchange-capable and\n // surface both concerns rather than asserting signature-only (P0-4).\n ec: {\n algo: \"ECDH\",\n cat: \"key-exchange\",\n sev: \"high\",\n hndl: true,\n label: \"EC (ECDSA/ECDH)\",\n message:\n \"Generates a classical EC key pair. EC keys feed BOTH ECDSA signatures \" +\n \"and ECDH key agreement; the ECDH path is harvest-now-decrypt-later exposed.\",\n remediation:\n \"For key agreement: hybrid X25519MLKEM768 (ML-KEM-768). For signatures: ML-DSA-65 (FIPS 204).\",\n },\n dsa: { algo: \"DSA\", cat: \"signature\", sev: \"high\", hndl: false, label: \"DSA\" },\n dh: { algo: \"DH\", cat: \"key-exchange\", sev: \"high\", hndl: true, label: \"Diffie-Hellman\" },\n x25519: { algo: \"X25519\", cat: \"key-exchange\", sev: \"medium\", hndl: true, label: \"X25519\" },\n x448: { algo: \"X448\", cat: \"key-exchange\", sev: \"medium\", hndl: true, label: \"X448\" },\n ed25519: { algo: \"EdDSA\", cat: \"signature\", sev: \"low\", hndl: false, label: \"Ed25519\" },\n ed448: { algo: \"EdDSA\", cat: \"signature\", sev: \"low\", hndl: false, label: \"Ed448\" },\n };\n const info = map[type];\n findings.push(\n findingFromRule(\n RULE_NODE_KEYGEN,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `${info.label} key generation`,\n category: info.cat,\n severity: info.sev,\n algorithm: info.algo,\n hndl: info.hndl,\n message:\n info.message ??\n `Generates a classical ${info.label} key pair, which is not quantum-safe.`,\n ...(info.remediation ? { remediation: info.remediation } : {}),\n },\n ),\n );\n });\n\n // createSign / createVerify — RSA / ECDSA / DSA signatures.\n eachMatch(RE_CREATE_SIGN_VERIFY, content, (m) => {\n findings.push(\n findingFromRule(RULE_NODE_SIGN, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // One-shot crypto.sign(algorithm, data, key) / crypto.verify(...) (Node ≥ 12).\n eachMatch(RE_ONESHOT_SIGN_VERIFY, content, (m) => {\n findings.push(\n findingFromRule(RULE_NODE_SIGN_ONESHOT, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // createDiffieHellman / createDiffieHellmanGroup — finite-field DH key exchange.\n eachMatch(RE_CREATE_DH, content, (m) => {\n findings.push(\n findingFromRule(RULE_NODE_DH, { file, content, index: m.index, matchLength: m[0].length }),\n );\n });\n\n // getDiffieHellman('modpN') — named built-in finite-field MODP groups.\n eachMatch(RE_GET_DH, content, (m) => {\n findings.push(\n findingFromRule(\n RULE_NODE_DH_MODP,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `Diffie-Hellman MODP group (${m[1]})`,\n message: `Named finite-field DH MODP group \"${m[1]}\" is broken by Shor's algorithm (harvest-now-decrypt-later).`,\n },\n ),\n );\n });\n\n // createECDH — elliptic-curve Diffie-Hellman key exchange.\n eachMatch(RE_CREATE_ECDH, content, (m) => {\n findings.push(\n findingFromRule(RULE_NODE_ECDH, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // publicEncrypt / privateDecrypt — RSA encryption (KEM-like confidentiality).\n eachMatch(RE_RSA_ENCRYPT, content, (m) => {\n findings.push(\n findingFromRule(RULE_NODE_RSA_ENCRYPT, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // diffieHellman({ privateKey, publicKey }) — KeyObject-based DH/ECDH.\n eachMatch(RE_DH_KEYOBJECT, content, (m) => {\n findings.push(\n findingFromRule(RULE_NODE_DH_KEYOBJECT, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n return findings;\n },\n};\n\n/* -------------------------------------------------------------------------- */\n/* WebCrypto (SubtleCrypto) */\n/* -------------------------------------------------------------------------- */\n\nconst RULE_WEBCRYPTO: RuleMeta = {\n id: \"webcrypto-classical\",\n title: \"WebCrypto classical algorithm\",\n description: \"classical asymmetric algorithm passed to SubtleCrypto\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"A classical asymmetric WebCrypto algorithm is used, which is not quantum-safe.\",\n};\n\n/**\n * Detects classical algorithms passed to WebCrypto's SubtleCrypto methods. The\n * algorithm name can appear as a bare string (\"RSA-OAEP\") or as\n * `{ name: \"ECDH\" }`; we scan both forms within a window after a subtle call.\n */\nconst webCryptoDetector: Detector = {\n id: \"webcrypto\",\n description: \"Classical asymmetric algorithms via WebCrypto SubtleCrypto\",\n scope: \"source\",\n language: \"js\",\n rules: [RULE_WEBCRYPTO],\n appliesTo: (f) => hasExtension(f, JS_TS_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n\n // Only consider names that appear near a subtle.* call to reduce noise.\n // callIndexes is collected in ascending order (regex scans left→right), so\n // proximity is resolved with a binary search instead of an O(M·C) scan.\n const callIndexes: number[] = [];\n eachMatch(RE_SUBTLE_CALL, content, (m) => callIndexes.push(m.index));\n if (callIndexes.length === 0) return findings;\n\n eachMatch(RE_WEBCRYPTO_ALGO, content, (m) => {\n if (!nearSortedCall(callIndexes, m.index, 400)) return;\n const name = m[1].toUpperCase();\n // Classify by algorithm: RSA-OAEP is KEM (HNDL); ECDH/X25519/X448 are key\n // agreement (HNDL); RSA-PSS/RSASSA/ECDSA/Ed25519/Ed448 are signatures.\n let algorithm: Finding[\"algorithm\"];\n let category: Finding[\"category\"];\n let hndl: boolean;\n let severity: Finding[\"severity\"] | undefined;\n if (name.startsWith(\"RSA\")) {\n algorithm = \"RSA\";\n const isKem = name === \"RSA-OAEP\";\n category = isKem ? \"kem\" : \"signature\";\n hndl = isKem;\n } else if (name === \"ECDH\") {\n algorithm = \"ECDH\";\n category = \"key-exchange\";\n hndl = true;\n } else if (name === \"X25519\" || name === \"X448\") {\n algorithm = name === \"X448\" ? \"X448\" : \"X25519\";\n category = \"key-exchange\";\n hndl = true;\n severity = \"low\"; // modern but classical\n } else if (name === \"ED25519\" || name === \"ED448\") {\n algorithm = \"EdDSA\";\n category = \"signature\";\n hndl = false;\n severity = \"low\";\n } else {\n algorithm = \"ECDSA\";\n category = \"signature\";\n hndl = false;\n }\n findings.push(\n findingFromRule(\n RULE_WEBCRYPTO,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `WebCrypto ${m[1]}`,\n category,\n algorithm,\n hndl,\n ...(severity ? { severity } : {}),\n message: `WebCrypto algorithm \"${m[1]}\" is classical asymmetric crypto and not quantum-safe.`,\n },\n ),\n );\n });\n\n return findings;\n },\n};\n\n/* -------------------------------------------------------------------------- */\n/* Popular crypto libraries */\n/* -------------------------------------------------------------------------- */\n\nconst RULE_FORGE_RSA: RuleMeta = {\n id: \"forge-rsa-keygen\",\n title: \"node-forge RSA key generation\",\n description: \"node-forge pki.rsa.generateKeyPair\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"node-forge generates a classical RSA key pair, which is not quantum-safe.\",\n};\nconst RULE_FORGE_ED25519: RuleMeta = {\n id: \"forge-ed25519\",\n title: \"node-forge Ed25519 usage\",\n description: \"node-forge forge.ed25519.*\",\n category: \"signature\",\n severity: \"low\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"node-forge Ed25519 is a modern but still classical signature scheme.\",\n};\nconst RULE_ELLIPTIC_EC: RuleMeta = {\n id: \"elliptic-ec\",\n title: \"elliptic curve instantiation\",\n description: \"the `elliptic` library — new EC(...)\",\n // `new EC(...)` is a dual-use curve context (ECDSA sign AND ECDH `key.derive()`).\n // Per this scanner's own EC-ambiguity policy, ambiguous EC is treated as\n // key-agreement-capable and HNDL-exposed (audit: crypto #8).\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"The `elliptic` library implements classical ECDSA/ECDH, both broken by Shor's algorithm.\",\n};\nconst RULE_SECP256K1: RuleMeta = {\n id: \"secp256k1-usage\",\n title: \"secp256k1 ECDSA/ECDH usage\",\n description: \"direct @noble/secp256k1-style API usage\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"medium\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Direct secp256k1 usage (ECDSA signatures / ECDH agreement) is classical and broken by Shor's algorithm.\",\n remediation: \"ML-DSA-65 (FIPS 204) for signatures; hybrid X25519MLKEM768 for key agreement.\",\n};\nconst RULE_JSRSASIGN_KEYGEN: RuleMeta = {\n id: \"jsrsasign-keygen\",\n title: \"jsrsasign key generation\",\n description: \"jsrsasign KEYUTIL.generateKeypair\",\n // KEYUTIL.generateKeypair(\"RSA\"|\"EC\") makes keys usable for RSA-OAEP encryption\n // and ECDH — HNDL-exposed, like Node's generateKeyPair (audit: crypto #13).\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"jsrsasign generates classical RSA/EC key pairs, which are not quantum-safe.\",\n remediation: \"ML-KEM-768 (FIPS 203) / ML-DSA-65 (FIPS 204)\",\n};\nconst RULE_JSRSASIGN_SIGN: RuleMeta = {\n id: \"jsrsasign-sign\",\n title: \"jsrsasign signature\",\n description: \"jsrsasign KJUR.crypto.Signature / ECDSA\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"jsrsasign signing uses classical RSA/ECDSA signatures, forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204)\",\n};\nconst RULE_NODE_RSA_LIB: RuleMeta = {\n id: \"node-rsa\",\n title: \"node-rsa key/usage\",\n description: \"the `node-rsa` library — new NodeRSA(...)\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"node-rsa wraps classical RSA encryption/signing, which is not quantum-safe.\",\n};\n\n/** Detects classical crypto from popular npm libraries used in source. */\nconst libraryDetector: Detector = {\n id: \"crypto-libs\",\n description: \"Classical asymmetric crypto via node-forge, elliptic, jsrsasign, node-rsa\",\n scope: \"source\",\n language: \"js\",\n rules: [\n RULE_FORGE_RSA,\n RULE_FORGE_ED25519,\n RULE_ELLIPTIC_EC,\n RULE_SECP256K1,\n RULE_JSRSASIGN_KEYGEN,\n RULE_JSRSASIGN_SIGN,\n RULE_NODE_RSA_LIB,\n ],\n appliesTo: (f) => hasExtension(f, JS_TS_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n const add = (re: RegExp, rule: RuleMeta) =>\n eachMatch(re, content, (m) =>\n findings.push(\n findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }),\n ),\n );\n\n add(RE_FORGE_RSA, RULE_FORGE_RSA); // node-forge: pki.rsa.generateKeyPair(...)\n add(RE_FORGE_ED25519, RULE_FORGE_ED25519); // node-forge: forge.ed25519.*\n add(RE_ELLIPTIC_EC, RULE_ELLIPTIC_EC); // elliptic: new EC('secp256k1')\n add(RE_SECP256K1, RULE_SECP256K1); // secp.sign / getPublicKey / getSharedSecret\n add(RE_JSRSASIGN_KEYGEN, RULE_JSRSASIGN_KEYGEN); // jsrsasign: KEYUTIL.generateKeypair(...)\n add(RE_JSRSASIGN_SIGN, RULE_JSRSASIGN_SIGN); // jsrsasign: KJUR.crypto.*\n add(RE_NODE_RSA, RULE_NODE_RSA_LIB); // node-rsa: new NodeRSA(...)\n\n return findings;\n },\n};\n\n/* -------------------------------------------------------------------------- */\n/* JWT / JOSE / COSE algorithm strings */\n/* -------------------------------------------------------------------------- */\n\n// JOSE RSA key-transport algorithms (JWE `alg`): quoted RSA-OAEP / RSA-OAEP-256\n// /384/512 / RSA1_5. Classical RSA *encryption* (key transport) — distinct from\n// the RS*/PS* *signature* tokens above, and a harvest-now-decrypt-later surface.\nconst RE_JOSE_KEM = /['\"`](RSA-OAEP(?:-(?:256|384|512))?|RSA1_5)['\"`]/g;\n\nconst RULE_JWT_ALG: RuleMeta = {\n id: \"jwt-classical-alg\",\n title: \"Classical JWT/JOSE algorithm\",\n description: \"JWS alg tokens (RS/PS/ES/EdDSA)\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"A classical JWT/JOSE signature algorithm is used, forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204); track IETF PQC JOSE/COSE algorithms\",\n};\nconst RULE_JOSE_ECDH: RuleMeta = {\n id: \"jose-ecdh-es\",\n title: \"JOSE ECDH-ES key agreement\",\n description: \"JOSE ECDH-ES / ECDH-ES+A*KW key agreement\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"medium\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"JOSE ECDH-ES performs classical ECDH key agreement — harvest-now-decrypt-later exposed.\",\n remediation: \"Track IETF PQC JOSE/COSE; adopt hybrid X25519MLKEM768 KEM-based encryption.\",\n};\nconst RULE_JOSE_RSA_OAEP: RuleMeta = {\n id: \"jose-rsa-oaep\",\n title: \"JOSE RSA key-transport algorithm\",\n description: \"JWE RSA-OAEP / RSA-OAEP-256/384/512 / RSA1_5 key encryption\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"medium\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"JOSE RSA key transport (RSA-OAEP / RSA1_5) is classical RSA encryption — harvest-now-decrypt-later exposed.\",\n remediation: \"Track IETF PQC JOSE/COSE; adopt hybrid X25519MLKEM768 KEM-based encryption.\",\n};\n\n/**\n * Detects classical signature algorithm identifiers used by JWT/JOSE, plus\n * ECDH-ES key-agreement identifiers (HNDL-exposed). These appear as string\n * literals: `alg: \"RS256\"`, `algorithms: [\"ES256\"]`, `enc: \"ECDH-ES+A256KW\"`.\n */\nconst jwtDetector: Detector = {\n id: \"jwt-jose\",\n description: \"Classical JWT/JOSE algorithms (RS/PS/ES/EdDSA) and ECDH-ES key agreement\",\n scope: \"source\",\n // Language-agnostic evidence: a quoted \"RS256\"/\"ES256\" alg token is the same\n // signal in JS/TS or Python (e.g. PyJWT `algorithm=\"RS256\"`), so this detector\n // is un-gated from JS-only to the JWT host surfaces.\n language: \"any\",\n rules: [RULE_JWT_ALG, RULE_JOSE_ECDH, RULE_JOSE_RSA_OAEP],\n appliesTo: (f) => hasExtension(f, JWT_HOST_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n\n // Classical JWS signature alg tokens. Anchored to quotes to avoid words.\n eachMatch(RE_JWT_ALG, content, (m) => {\n const alg = m[1];\n let algorithm: Finding[\"algorithm\"];\n if (alg.startsWith(\"RS\") || alg.startsWith(\"PS\")) algorithm = \"RSA\";\n else if (alg === \"EdDSA\") algorithm = \"EdDSA\";\n else algorithm = \"ECDSA\"; // ES*\n findings.push(\n findingFromRule(\n RULE_JWT_ALG,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `JWT/JOSE algorithm ${alg}`,\n algorithm,\n message: `JWT/JOSE algorithm \"${alg}\" is a classical signature, forgeable by a quantum attacker.`,\n },\n ),\n );\n });\n\n // JOSE ECDH-ES key agreement (and ECDH-ES+A*KW) — confidentiality, HNDL.\n eachMatch(RE_JOSE_ECDH, content, (m) => {\n findings.push(\n findingFromRule(\n RULE_JOSE_ECDH,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `JOSE key agreement ${m[1]}`,\n message: `JOSE \"${m[1]}\" performs classical ECDH key agreement — harvest-now-decrypt-later exposed.`,\n },\n ),\n );\n });\n\n // JOSE RSA key transport (RSA-OAEP / RSA1_5) — classical RSA encryption, HNDL.\n eachMatch(RE_JOSE_KEM, content, (m) => {\n findings.push(\n findingFromRule(\n RULE_JOSE_RSA_OAEP,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `JOSE RSA key transport ${m[1]}`,\n message: `JOSE \"${m[1]}\" is classical RSA key transport — harvest-now-decrypt-later exposed.`,\n },\n ),\n );\n });\n\n return findings;\n },\n};\n\n/* -------------------------------------------------------------------------- */\n/* TLS legacy configuration */\n/* -------------------------------------------------------------------------- */\n\nconst RULE_TLS_LEGACY: RuleMeta = {\n id: \"tls-legacy-version\",\n title: \"Legacy TLS version pinned\",\n description: \"minVersion/maxVersion/secureProtocol pinned to TLS 1.0/1.1\",\n category: \"tls\",\n severity: \"medium\",\n confidence: \"high\",\n hndl: false,\n cwe: CWE_WEAK_STRENGTH,\n message: \"TLS 1.0/1.1 are deprecated and insecure; require TLS 1.3.\",\n remediation: \"Set minVersion: 'TLSv1.3' and prefer PQC-hybrid key exchange.\",\n};\nconst RULE_TLS_REJECT: RuleMeta = {\n id: \"tls-reject-unauthorized\",\n title: \"TLS certificate verification disabled\",\n description: \"rejectUnauthorized: false\",\n category: \"tls\",\n severity: \"high\",\n confidence: \"high\",\n hndl: false,\n cwe: CWE_CERT_VALIDATION,\n message: \"rejectUnauthorized:false disables TLS certificate verification (MITM risk).\",\n remediation: \"Remove rejectUnauthorized:false; verify certificates properly.\",\n};\nconst RULE_TLS_WEAK_CIPHER: RuleMeta = {\n id: \"tls-weak-cipher\",\n title: \"Weak TLS cipher configured\",\n description: \"weak/export cipher in a `ciphers` string\",\n category: \"tls\",\n severity: \"medium\",\n confidence: \"medium\",\n hndl: false,\n cwe: CWE_WEAK_STRENGTH,\n message: \"A weak cipher is configured in the TLS ciphers list.\",\n remediation: \"Use a modern AEAD cipher suite (TLS 1.3 defaults).\",\n};\n\n/**\n * Detects legacy / insecure TLS configuration expressed as JS object literals:\n * forced TLS 1.0/1.1, disabled certificate verification, and weak ciphers.\n * These aren't quantum-specific but materially weaken transport security and\n * are squarely in qScan's \"config\" scope.\n */\nconst tlsDetector: Detector = {\n id: \"tls-config\",\n description: \"Legacy / insecure TLS configuration in JS objects\",\n scope: \"config\",\n language: \"js\",\n rules: [RULE_TLS_LEGACY, RULE_TLS_REJECT, RULE_TLS_WEAK_CIPHER],\n appliesTo: (f) => hasExtension(f, JS_TS_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n\n // minVersion / maxVersion / secureProtocol pinned to TLS 1.0 or 1.1.\n eachMatch(RE_TLS_LEGACY_VERSION, content, (m) => {\n findings.push(\n findingFromRule(RULE_TLS_LEGACY, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // rejectUnauthorized: false — disables certificate verification.\n eachMatch(RE_TLS_REJECT, content, (m) => {\n findings.push(\n findingFromRule(RULE_TLS_REJECT, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // Weak / export ciphers referenced in a ciphers string (bounded regex).\n eachMatch(RE_TLS_WEAK_CIPHER, content, (m) => {\n findings.push(\n findingFromRule(\n RULE_TLS_WEAK_CIPHER,\n { file, content, index: m.index, matchLength: m[0].length },\n { message: `Weak cipher (${m[1]}) configured in the TLS ciphers list.` },\n ),\n );\n });\n\n return findings;\n },\n};\n\n/* -------------------------------------------------------------------------- */\n/* SSH public keys + TLS certificate signature algorithms (config scope) */\n/* -------------------------------------------------------------------------- */\n\nconst RE_SSH_PUBKEY = /\\b(ssh-rsa|ssh-ed25519|ssh-dss|ecdsa-sha2-nistp(?:256|384|521))\\b/g;\nconst RE_CERT_SIG_ALG =\n /\\b(sha(?:1|256|384|512)WithRSAEncryption|ecdsa-with-SHA(?:1|256|384|512)|rsassaPss|dsaWithSHA(?:1|256))\\b/g;\n// Classical SSH key-exchange algorithm identifiers: finite-field DH groups\n// (diffie-hellman-group{1,14,15,16,17,18} + group-exchange), ECDH over NIST\n// curves (ecdh-sha2-nistp*), and Curve25519 (curve25519-sha256). All are\n// Shor-broken key agreement — the harvest-now-decrypt-later surface a lexical\n// scan misses when only the `crypto/*` API is matched, not the negotiated kex.\nconst RE_SSH_KEX =\n /\\b(diffie-hellman-group(?:1|14|15|16|17|18)(?:-sha1|-sha256|-sha512)?|diffie-hellman-group-exchange-sha(?:1|256)|ecdh-sha2-nistp(?:256|384|521)|curve25519-sha256)\\b/g;\n\nconst RULE_SSH_PUBKEY: RuleMeta = {\n id: \"ssh-public-key\",\n title: \"Classical SSH public key\",\n description: \"ssh-rsa / ssh-ed25519 / ssh-dss / ecdsa-sha2-* public keys\",\n category: \"certificate\",\n severity: \"low\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n sensitive: true,\n message: \"A classical SSH public key is forgeable by a quantum attacker.\",\n remediation:\n \"Plan migration to PQC-capable SSH: prefer the mlkem768x25519-sha256 KEX (ML-KEM-768 hybrid, OpenSSH 10's default since Apr 2025); sntrup761x25519 is an acceptable interim. Rotate to PQC host keys as they land.\",\n};\nconst RULE_CERT_SIG_ALG: RuleMeta = {\n id: \"cert-signature-algorithm\",\n title: \"Classical certificate signature algorithm\",\n description: \"X.509/TLS certificate signature-algorithm identifiers\",\n category: \"certificate\",\n severity: \"low\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"A classical certificate signature algorithm (RSA/ECDSA/DSA) is a quantum forgery surface.\",\n remediation: \"Plan re-issuance with PQC-capable CAs as ML-DSA certificate profiles mature.\",\n};\nconst RULE_SSH_KEX: RuleMeta = {\n id: \"ssh-kex-classical\",\n title: \"Classical SSH key exchange\",\n description: \"diffie-hellman-group* / group-exchange / ecdh-sha2-* / curve25519-sha256 kex\",\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"A classical SSH key-exchange algorithm (finite-field DH / ECDH / X25519) is harvest-now-decrypt-later exposed.\",\n remediation:\n \"Prefer the mlkem768x25519-sha256 KEX (ML-KEM-768 hybrid, OpenSSH 10 default); sntrup761x25519 is an acceptable interim.\",\n};\n\n/**\n * Detects classical SSH public keys (`authorized_keys` / `known_hosts` lines)\n * and X.509 certificate signature-algorithm identifiers in any text file. These\n * are language-agnostic config surfaces — the SSH-key forgery surface and the\n * PKI signature surface that lexical PEM detection misses.\n */\nconst sshCertDetector: Detector = {\n id: \"ssh-cert\",\n description: \"SSH public keys and TLS/X.509 certificate signature algorithms in config\",\n scope: \"config\",\n language: \"any\",\n rules: [RULE_SSH_PUBKEY, RULE_CERT_SIG_ALG, RULE_SSH_KEX],\n // Skip prose/docs: a changelog or README that merely mentions `ssh-rsa` in a\n // sentence is not crypto config. PEM material is caught by its own detector.\n appliesTo: (f) => !hasExtension(f, DOC_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n\n // SSH public keys: ssh-rsa AAAA…, ecdsa-sha2-nistp256 …, ssh-ed25519 …\n eachMatch(RE_SSH_PUBKEY, content, (m) => {\n const tok = m[1];\n const algorithm: Finding[\"algorithm\"] = tok.startsWith(\"ssh-rsa\")\n ? \"RSA\"\n : tok === \"ssh-ed25519\"\n ? \"EdDSA\"\n : tok === \"ssh-dss\"\n ? \"DSA\"\n : \"ECDSA\";\n findings.push(\n findingFromRule(\n RULE_SSH_PUBKEY,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `Classical SSH public key (${tok})`,\n algorithm,\n message: `SSH public key type \"${tok}\" is a classical key forgeable by a quantum attacker.`,\n },\n ),\n );\n });\n\n // X.509 / TLS certificate signature algorithm identifiers (forgery surface).\n eachMatch(RE_CERT_SIG_ALG, content, (m) => {\n const tok = m[1];\n const algorithm: Finding[\"algorithm\"] = /RSA|rsassa/i.test(tok)\n ? \"RSA\"\n : tok.startsWith(\"ecdsa\")\n ? \"ECDSA\"\n : \"DSA\";\n findings.push(\n findingFromRule(\n RULE_CERT_SIG_ALG,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `Classical certificate signature algorithm (${tok})`,\n algorithm,\n message: `Certificate signature algorithm \"${tok}\" is classical (RSA/ECDSA/DSA) — a quantum forgery surface.`,\n },\n ),\n );\n });\n\n // SSH key-exchange algorithm identifiers (finite-field DH / ECDH / X25519).\n eachMatch(RE_SSH_KEX, content, (m) => {\n const tok = m[1];\n const algorithm: Finding[\"algorithm\"] = tok.startsWith(\"diffie-hellman\")\n ? \"DH\"\n : tok.startsWith(\"ecdh\")\n ? \"ECDH\"\n : \"X25519\";\n findings.push(\n findingFromRule(\n RULE_SSH_KEX,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `Classical SSH key exchange (${tok})`,\n algorithm,\n message: `SSH key-exchange \"${tok}\" is classical (${algorithm}) — harvest-now-decrypt-later exposed.`,\n },\n ),\n );\n });\n\n return findings;\n },\n};\n\n/* -------------------------------------------------------------------------- */\n/* Classical TLS key-exchange cipher suites (language-agnostic config) */\n/* -------------------------------------------------------------------------- */\n\n// Classical KEX cipher-suite identifiers, in both the OpenSSL (`ECDHE-RSA-…`) and\n// IANA (`TLS_ECDHE_RSA_WITH_…`) spellings, with `-` or `_` separators. These name\n// a Shor-broken key exchange (ECDHE/DHE), so they are the harvest-now surface a\n// PQC scanner should flag — distinct from the legacy-*version* / weak-cipher rules\n// above. Case-sensitive on purpose: cipher-suite tokens are upper-case constants,\n// so prose like \"ecdhe rsa\" does not misfire. No trailing \\b so the IANA\n// `TLS_ECDHE_RSA_WITH_…` form (a `_` follows `RSA`) still matches.\nconst RE_TLS_CLASSICAL_KEX = /\\b(?:TLS_)?(?:ECDHE|ECDH|DHE)[-_](?:RSA|ECDSA|DSS)/g;\n\nconst RULE_TLS_CLASSICAL_KEX: RuleMeta = {\n id: \"tls-classical-kex\",\n title: \"Classical TLS key-exchange cipher suite\",\n description: \"ECDHE / DHE cipher suites negotiate Shor-broken key exchange\",\n category: \"tls\",\n severity: \"medium\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Classical TLS key exchange (ECDHE/DHE) is harvest-now-decrypt-later exposed — the session key can be recorded now and recovered by a quantum attacker.\",\n remediation:\n \"Adopt a PQC-hybrid TLS 1.3 key exchange (e.g. X25519MLKEM768) as your stack and peers support it; keep classical suites only as a transitional fallback.\",\n};\n\n/**\n * Detects classical TLS key-exchange cipher suites in any text/config file\n * (OpenSSL cipher lists, IANA suite constants in Go/Java/C#/Rust, `.properties`,\n * etc.). Language-agnostic because the suite identifiers are the same tokens\n * everywhere — this is the cross-language TLS gap the legacy-version rule misses.\n */\nconst tlsClassicalKexDetector: Detector = {\n id: \"tls-cipher-suite\",\n description: \"Classical TLS key-exchange cipher suites (ECDHE/DHE) in any config\",\n scope: \"config\",\n language: \"any\",\n rules: [RULE_TLS_CLASSICAL_KEX],\n appliesTo: (f) => !hasExtension(f, DOC_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n eachMatch(RE_TLS_CLASSICAL_KEX, content, (m) => {\n const tok = m[0];\n const algorithm: Finding[\"algorithm\"] = tok.includes(\"ECDH\") ? \"ECDH\" : \"DH\";\n findings.push(\n findingFromRule(\n RULE_TLS_CLASSICAL_KEX,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n algorithm,\n message: `Classical TLS key-exchange suite \"${tok}…\" (${algorithm}) is harvest-now-decrypt-later exposed.`,\n },\n ),\n );\n });\n return findings;\n },\n};\n\n/** All built-in source/config detectors, in run order. */\nexport const sourceDetectors: Detector[] = [\n nodeCryptoDetector,\n webCryptoDetector,\n libraryDetector,\n jwtDetector,\n tlsDetector,\n sshCertDetector,\n tlsClassicalKexDetector,\n];\n"]}
|
|
1
|
+
{"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/detectors/source.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Source-code detectors for classical, non-quantum-safe asymmetric cryptography\n * in JavaScript / TypeScript. Each detector is pure and stateless: it declares\n * which files it applies to, the catalog of rules it can emit (`rules`), and\n * returns zero or more Findings for a file's contents.\n *\n * Rule metadata (title / severity / category / remediation / …) lives ONCE in\n * the per-detector `RuleMeta` declarations below, not inline in `detect()`.\n * `detect()` builds findings from those declarations via `findingFromRule`,\n * overriding only the fields that genuinely vary per match (e.g. the concrete\n * algorithm family of a `generateKeyPair('ec')` call). The declarations are the\n * catalog surfaced by the registry, SARIF `rules[]`, and the MCP resolver.\n *\n * The detection strategy is deliberately lexical (regex over source text). This\n * is robust to bundling and partial files and keeps the package dependency-free.\n * Confidence is set per-pattern to reflect how specific the match is.\n *\n * All per-file regexes are precompiled at module scope (not re-created per\n * file) — `eachMatch` clones a fresh stateful copy only when a regex lacks the\n * global flag, and these are all global, so they are reused safely.\n *\n * HNDL (harvest-now-decrypt-later) policy:\n * - confidentiality primitives (key exchange / KEM: ECDH, DH, RSA-OAEP) → hndl:true\n * - signatures (RSA-PSS, ECDSA, EdDSA, DSA, JWT alg) → hndl:false, but still high\n * severity because a quantum attacker can forge them.\n * - EC keygen is ambiguous (an 'ec' key feeds BOTH ECDSA and ECDH); it is\n * classified conservatively as key-exchange-capable (hndl:true).\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport {\n JS_TS_EXTENSIONS,\n DOC_EXTENSIONS,\n JWT_HOST_EXTENSIONS,\n eachMatch,\n enclosingObject,\n findingFromRule,\n hasExtension,\n nearSortedCall,\n} from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO, CWE_CERT_VALIDATION, CWE_WEAK_STRENGTH } from \"../cwe.js\";\n\n/* -------------------------------------------------------------------------- */\n/* Precompiled regexes (module scope — never recreated per file) */\n/* -------------------------------------------------------------------------- */\n\n// `rsa-pss` is listed before `rsa` so the alternation consumes the full token\n// (ordered alternation would otherwise match `rsa` and reject the `-pss` tail).\nconst RE_GENERATE_KEYPAIR =\n /generateKeyPair(?:Sync)?\\s*\\(\\s*['\"`](rsa-pss|rsa|ec|dsa|dh|x25519|x448|ed25519|ed448)['\"`]/g;\n\n/** Per-key-type classification for `generateKeyPair(Sync)('<type>', …)`. Hoisted\n * to module scope so the direct matcher AND the import-alias pass (below) share\n * one source of truth for how each key type is classified. */\ninterface KeygenInfo {\n algo: Finding[\"algorithm\"];\n cat: Finding[\"category\"];\n sev: Finding[\"severity\"];\n hndl: boolean;\n label: string;\n message?: string;\n remediation?: string;\n}\nconst KEYGEN_INFO: Record<string, KeygenInfo> = {\n rsa: { algo: \"RSA\", cat: \"kem\", sev: \"high\", hndl: true, label: \"RSA\" },\n // RSA-PSS is signature-only, so classify it as a (forgeable) signature\n // rather than a KEM — no HNDL confidentiality exposure.\n \"rsa-pss\": {\n algo: \"RSA\",\n cat: \"signature\",\n sev: \"high\",\n hndl: false,\n label: \"RSA-PSS\",\n message: \"Generates a classical RSA-PSS signing key, which is forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n },\n // EC keys feed BOTH ECDSA (sign) and ECDH (key agreement). ECDH is\n // HNDL-exposed, so classify conservatively as key-exchange-capable and\n // surface both concerns rather than asserting signature-only (P0-4).\n ec: {\n algo: \"ECDH\",\n cat: \"key-exchange\",\n sev: \"high\",\n hndl: true,\n label: \"EC (ECDSA/ECDH)\",\n message:\n \"Generates a classical EC key pair. EC keys feed BOTH ECDSA signatures \" +\n \"and ECDH key agreement; the ECDH path is harvest-now-decrypt-later exposed.\",\n remediation:\n \"For key agreement: hybrid X25519MLKEM768 (ML-KEM-768). For signatures: ML-DSA-65 (FIPS 204).\",\n },\n dsa: { algo: \"DSA\", cat: \"signature\", sev: \"high\", hndl: false, label: \"DSA\" },\n dh: { algo: \"DH\", cat: \"key-exchange\", sev: \"high\", hndl: true, label: \"Diffie-Hellman\" },\n x25519: { algo: \"X25519\", cat: \"key-exchange\", sev: \"medium\", hndl: true, label: \"X25519\" },\n x448: { algo: \"X448\", cat: \"key-exchange\", sev: \"medium\", hndl: true, label: \"X448\" },\n ed25519: { algo: \"EdDSA\", cat: \"signature\", sev: \"low\", hndl: false, label: \"Ed25519\" },\n ed448: { algo: \"EdDSA\", cat: \"signature\", sev: \"low\", hndl: false, label: \"Ed448\" },\n};\n\n/** Emit a keygen finding for `generateKeyPair(Sync)('<type>')` at [index]. Shared\n * by the direct matcher and the import-alias pass so both classify identically. */\nfunction pushKeygenFinding(\n findings: Finding[],\n rawType: string,\n file: string,\n content: string,\n index: number,\n matchLength: number,\n): void {\n const info = KEYGEN_INFO[rawType.toLowerCase()];\n if (!info) return;\n findings.push(\n findingFromRule(\n RULE_NODE_KEYGEN,\n { file, content, index, matchLength },\n {\n title: `${info.label} key generation`,\n category: info.cat,\n severity: info.sev,\n algorithm: info.algo,\n hndl: info.hndl,\n message:\n info.message ??\n `Generates a classical ${info.label} key pair, which is not quantum-safe.`,\n ...(info.remediation ? { remediation: info.remediation } : {}),\n },\n ),\n );\n}\n\n/** Canonical Node-crypto call names whose import-aliases we resolve. */\nconst ALIASABLE: readonly string[] = [\n \"generateKeyPairSync\",\n \"generateKeyPair\",\n \"createECDH\",\n \"createDiffieHellman\",\n \"createDiffieHellmanGroup\",\n];\n\n/**\n * Collect import-aliases for the canonical crypto calls we resolve, so\n * `import { generateKeyPairSync as gk } from 'node:crypto'` (or the CommonJS\n * `const { generateKeyPairSync: gk } = require('crypto')`) is followed when `gk`\n * is called later. Returns Map<canonical, alias[]>. An alias equal to its own\n * canonical name is skipped (already matched directly). Precision-safe: the\n * alias is only ever bound to a known crypto symbol, so a later `gk(` call is\n * unambiguously that symbol.\n */\nfunction collectCryptoAliases(content: string): Map<string, string[]> {\n const out = new Map<string, string[]>();\n const add = (canonical: string, alias: string): void => {\n if (!alias || alias === canonical) return;\n const list = out.get(canonical) ?? [];\n if (!list.includes(alias)) list.push(alias);\n out.set(canonical, list);\n };\n // ESM named imports: `import { A as B, C as D } from '...'`.\n const esm = /import\\s*(?:type\\s+)?\\{([^}]*)\\}\\s*from\\s*['\"][^'\"]*['\"]/g;\n for (let m = esm.exec(content); m; m = esm.exec(content)) {\n const spec = /([A-Za-z_$][\\w$]*)\\s+as\\s+([A-Za-z_$][\\w$]*)/g;\n for (let s = spec.exec(m[1]); s; s = spec.exec(m[1])) {\n if (ALIASABLE.includes(s[1])) add(s[1], s[2]);\n }\n }\n // CommonJS destructure-rename: `const { A: B } = require('...')`.\n const cjs = /(?:const|let|var)\\s*\\{([^}]*)\\}\\s*=\\s*require\\s*\\(\\s*['\"][^'\"]*['\"]\\s*\\)/g;\n for (let m = cjs.exec(content); m; m = cjs.exec(content)) {\n const spec = /([A-Za-z_$][\\w$]*)\\s*:\\s*([A-Za-z_$][\\w$]*)/g;\n for (let s = spec.exec(m[1]); s; s = spec.exec(m[1])) {\n if (ALIASABLE.includes(s[1])) add(s[1], s[2]);\n }\n }\n return out;\n}\n\n/** Escape a string for safe interpolation into a dynamically-built RegExp. */\nfunction escapeRe(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\nconst RE_CREATE_SIGN_VERIFY = /create(?:Sign|Verify)\\s*\\(/g;\n// One-shot crypto.sign/verify(algorithm, data, key). A LOOKBEHIND (not a\n// consumed char) anchors it so it doesn't fire inside identifiers like `assign(`\n// or `createSign(` (handled by the dedicated createSign/createVerify rule) —\n// consuming the preceding char used to push the match onto the previous line,\n// corrupting the reported line/snippet and SARIF/baseline fingerprints. The\n// first argument is either a quoted digest-algorithm string (RSA/ECDSA) or\n// `null` — Node's EdDSA one-shot form is `crypto.sign(null, data, edKey)`.\nconst RE_ONESHOT_SIGN_VERIFY =\n /(?<![.\\w])(?:crypto\\.)?(sign|verify)\\s*\\(\\s*(?:['\"`][\\w.-]+['\"`]|null)\\s*,/g;\nconst RE_CREATE_DH = /createDiffieHellman(?:Group)?\\s*\\(/g;\nconst RE_GET_DH = /getDiffieHellman\\s*\\(\\s*['\"`](modp\\d+)['\"`]\\s*\\)/g;\nconst RE_CREATE_ECDH = /createECDH\\s*\\(/g;\nconst RE_RSA_ENCRYPT = /(?:crypto\\.)?(?:publicEncrypt|privateDecrypt)\\s*\\(/g;\nconst RE_DH_KEYOBJECT = /(?:crypto\\.)?diffieHellman\\s*\\(\\s*\\{/g;\n\n// WebCrypto. Includes the newer curve algorithms (Ed25519/Ed448 signatures,\n// X25519/X448 key agreement) shipping in modern SubtleCrypto implementations.\nconst RE_WEBCRYPTO_ALGO =\n /\\b(RSA-OAEP|RSA-PSS|RSASSA-PKCS1-v1_5|ECDH|ECDSA|Ed25519|Ed448|X25519|X448)\\b/gi;\nconst RE_SUBTLE_CALL =\n /subtle\\s*\\.\\s*(generateKey|importKey|exportKey|deriveKey|deriveBits|sign|verify|encrypt|decrypt|wrapKey|unwrapKey)\\s*\\(/g;\n\n// Libraries.\nconst RE_FORGE_RSA = /pki\\.rsa\\.generateKeyPair\\s*\\(/g;\nconst RE_FORGE_ED25519 = /forge\\.ed25519\\b/g;\n// Require a curve-like first argument so `new EC(\"request-scope\")` (a non-crypto\n// `EC` class) is not flagged; the elliptic library is always constructed with a\n// named curve (`new EC('secp256k1')`, `new EC('p256')`, …).\nconst RE_ELLIPTIC_EC =\n /new\\s+(?:elliptic\\.)?ec\\s*\\(\\s*['\"`](?:sec[pt]|prime|nistp|curve|ed25519|ed448|brainpool|p-?(?:192|224|256|384|521)|x25519|x448)/gi;\nconst RE_JSRSASIGN_KEYGEN = /KEYUTIL\\.generateKeypair\\s*\\(/g;\nconst RE_JSRSASIGN_SIGN = /KJUR\\.crypto\\.(?:Signature|ECDSA)\\b/g;\nconst RE_NODE_RSA = /new\\s+NodeRSA\\s*\\(/g;\n// secp256k1 — direct @noble/secp256k1 / secp256k1-style API usage in source.\nconst RE_SECP256K1 =\n /\\b(?:secp(?:256k1)?|secp)\\s*\\.\\s*(sign|verify|getPublicKey|getSharedSecret|ecdh|recoverPublicKey)\\s*\\(/g;\n\n// JWT/JOSE.\nconst RE_JWT_ALG = /['\"`](RS(?:256|384|512)|PS(?:256|384|512)|ES(?:256|384|512|256K)|EdDSA)['\"`]/g;\n// JOSE ECDH-ES key agreement (HNDL) and COSE algorithm identifiers.\nconst RE_JOSE_ECDH = /['\"`](ECDH-ES(?:\\+A(?:128|192|256)KW)?)['\"`]/g;\n\n// TLS config.\nconst RE_TLS_LEGACY_VERSION =\n /(?:minVersion|maxVersion)\\s*:\\s*['\"`]TLSv1(?:\\.1)?['\"`]|secureProtocol\\s*:\\s*['\"`]TLSv1(?:_1)?_method['\"`]/g;\nconst RE_TLS_REJECT = /rejectUnauthorized\\s*:\\s*false/g;\n// Hardened cipher regex: bounded spans (no unbounded `[^'\"`]*` straddling the\n// alternation), single-quote-style anchoring removed in favour of {0,256} bounds\n// so worst-case backtracking is linear in the bound, not the file (P0-6).\n// Skip OpenSSL EXCLUSION syntax — `!MD5` / `:-RC4` / `!ECDHE-RSA-RC4-SHA` DISABLE\n// those ciphers, so a hardened list must not be flagged as weak (audit: crypto #7). The\n// single variable-length lookbehind walks back over the suite-name chars to the\n// ELEMENT boundary (`:` / whitespace / comma / quote / start) and rejects the match\n// when that element begins with `!` or `-` — covering a bare `!RC4`, a space-separated\n// `HIGH !RC4`, and a full-suite `!ECDHE-RSA-RC4-SHA`. The intra-name hyphen in a\n// genuinely-enabled `ECDHE-RSA-RC4-SHA` (no leading `!`/`-`) still matches.\nconst RE_TLS_WEAK_CIPHER =\n /ciphers\\s*:\\s*['\"`][^'\"`\\n]{0,256}?\\b(?<![:'\"`,\\s]\\s*[!-][\\w-]{0,64})(RC4|DES|3DES|MD5|NULL|EXPORT|aNULL|eNULL)\\b[^'\"`\\n]{0,256}?['\"`]/gi;\n\n/* -------------------------------------------------------------------------- */\n/* Node.js `crypto` module */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Rule catalog for the Node `crypto` detector. `node-crypto-keygen` and\n * `node-crypto-dh-modp` refine some fields per match; the rest emit findings\n * straight from these declarations.\n */\nconst RULE_NODE_KEYGEN: RuleMeta = {\n id: \"node-crypto-keygen\",\n title: \"Classical key generation\",\n description: \"crypto.generateKeyPair(Sync)('rsa'|'ec'|'dsa'|'dh'|…)\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Generates a classical asymmetric key pair, which is not quantum-safe.\",\n};\nconst RULE_NODE_SIGN: RuleMeta = {\n id: \"node-crypto-sign\",\n title: \"Classical signature (createSign/createVerify)\",\n description: \"crypto.createSign / crypto.createVerify\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Uses createSign/createVerify, typically RSA, ECDSA or DSA — all forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n};\nconst RULE_NODE_SIGN_ONESHOT: RuleMeta = {\n id: \"node-crypto-sign-oneshot\",\n title: \"Classical one-shot signature (crypto.sign/verify)\",\n description: \"one-shot crypto.sign / crypto.verify (Node ≥ 12)\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Uses the one-shot crypto.sign/crypto.verify API, typically RSA/ECDSA/EdDSA — forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n};\nconst RULE_NODE_DH: RuleMeta = {\n id: \"node-crypto-dh\",\n title: \"Diffie-Hellman key exchange\",\n description: \"crypto.createDiffieHellman(Group)\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"DH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Finite-field Diffie-Hellman is broken by Shor's algorithm (harvest-now-decrypt-later).\",\n};\nconst RULE_NODE_DH_MODP: RuleMeta = {\n id: \"node-crypto-dh-modp\",\n title: \"Diffie-Hellman MODP group\",\n description: \"crypto.getDiffieHellman('modpN')\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"DH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Named finite-field DH MODP group is broken by Shor's algorithm (harvest-now-decrypt-later).\",\n};\nconst RULE_NODE_ECDH: RuleMeta = {\n id: \"node-crypto-ecdh\",\n title: \"ECDH key exchange\",\n description: \"crypto.createECDH\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Elliptic-curve Diffie-Hellman is broken by Shor's algorithm (harvest-now-decrypt-later).\",\n};\nconst RULE_NODE_RSA_ENCRYPT: RuleMeta = {\n id: \"node-crypto-rsa-encrypt\",\n title: \"RSA public-key encryption\",\n description: \"crypto.publicEncrypt / crypto.privateDecrypt\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"RSA public-key encryption is broken by Shor's algorithm and exposed to harvest-now-decrypt-later.\",\n};\nconst RULE_NODE_DH_KEYOBJECT: RuleMeta = {\n id: \"node-crypto-dh-keyobject\",\n title: \"Diffie-Hellman (KeyObject) key exchange\",\n description: \"crypto.diffieHellman({ privateKey, publicKey })\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"crypto.diffieHellman() performs a classical (EC)DH agreement (harvest-now-decrypt-later).\",\n};\n\n/** Detects classical asymmetric usage from Node's built-in `crypto` module. */\nconst nodeCryptoDetector: Detector = {\n id: \"node-crypto\",\n description: \"Classical asymmetric crypto via the Node.js `crypto` module\",\n scope: \"source\",\n language: \"js\",\n rules: [\n RULE_NODE_KEYGEN,\n RULE_NODE_SIGN,\n RULE_NODE_SIGN_ONESHOT,\n RULE_NODE_DH,\n RULE_NODE_DH_MODP,\n RULE_NODE_ECDH,\n RULE_NODE_RSA_ENCRYPT,\n RULE_NODE_DH_KEYOBJECT,\n ],\n appliesTo: (f) => hasExtension(f, JS_TS_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n\n // generateKeyPair(Sync)('rsa' | 'ec' | 'dsa' | 'dh' | 'x25519' | 'ed25519', ...)\n eachMatch(RE_GENERATE_KEYPAIR, content, (m) => {\n pushKeygenFinding(findings, m[1], file, content, m.index, m[0].length);\n });\n\n // Import-alias resolution: follow `import { generateKeyPairSync as gk }` (and\n // the CommonJS destructure-rename) so an aliased call still detects. Only the\n // keygen / ECDH / DH constructors are resolved — their classification is\n // unambiguous. The alias regexes run on the ORIGINAL content, so locations\n // stay exact; it fires only when the alias was explicitly bound to a known\n // crypto symbol, so precision is unaffected.\n const aliases = collectCryptoAliases(content);\n for (const [canonical, names] of aliases) {\n for (const alias of names) {\n const a = escapeRe(alias);\n if (canonical === \"generateKeyPairSync\" || canonical === \"generateKeyPair\") {\n const re = new RegExp(\n `\\\\b${a}\\\\s*\\\\(\\\\s*['\"\\`](rsa-pss|rsa|ec|dsa|dh|x25519|x448|ed25519|ed448)['\"\\`]`,\n \"g\",\n );\n eachMatch(re, content, (m) =>\n pushKeygenFinding(findings, m[1], file, content, m.index, m[0].length),\n );\n } else if (canonical === \"createECDH\") {\n eachMatch(new RegExp(`\\\\b${a}\\\\s*\\\\(`, \"g\"), content, (m) =>\n findings.push(\n findingFromRule(RULE_NODE_ECDH, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n ),\n );\n } else {\n // createDiffieHellman / createDiffieHellmanGroup.\n eachMatch(new RegExp(`\\\\b${a}\\\\s*\\\\(`, \"g\"), content, (m) =>\n findings.push(\n findingFromRule(RULE_NODE_DH, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n ),\n );\n }\n }\n }\n\n // createSign / createVerify — RSA / ECDSA / DSA signatures.\n eachMatch(RE_CREATE_SIGN_VERIFY, content, (m) => {\n findings.push(\n findingFromRule(RULE_NODE_SIGN, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // One-shot crypto.sign(algorithm, data, key) / crypto.verify(...) (Node ≥ 12).\n eachMatch(RE_ONESHOT_SIGN_VERIFY, content, (m) => {\n findings.push(\n findingFromRule(RULE_NODE_SIGN_ONESHOT, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // createDiffieHellman / createDiffieHellmanGroup — finite-field DH key exchange.\n eachMatch(RE_CREATE_DH, content, (m) => {\n findings.push(\n findingFromRule(RULE_NODE_DH, { file, content, index: m.index, matchLength: m[0].length }),\n );\n });\n\n // getDiffieHellman('modpN') — named built-in finite-field MODP groups.\n eachMatch(RE_GET_DH, content, (m) => {\n findings.push(\n findingFromRule(\n RULE_NODE_DH_MODP,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `Diffie-Hellman MODP group (${m[1]})`,\n message: `Named finite-field DH MODP group \"${m[1]}\" is broken by Shor's algorithm (harvest-now-decrypt-later).`,\n },\n ),\n );\n });\n\n // createECDH — elliptic-curve Diffie-Hellman key exchange.\n eachMatch(RE_CREATE_ECDH, content, (m) => {\n findings.push(\n findingFromRule(RULE_NODE_ECDH, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // publicEncrypt / privateDecrypt — RSA encryption (KEM-like confidentiality).\n eachMatch(RE_RSA_ENCRYPT, content, (m) => {\n findings.push(\n findingFromRule(RULE_NODE_RSA_ENCRYPT, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // diffieHellman({ privateKey, publicKey }) — KeyObject-based DH/ECDH.\n eachMatch(RE_DH_KEYOBJECT, content, (m) => {\n findings.push(\n findingFromRule(RULE_NODE_DH_KEYOBJECT, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n return findings;\n },\n};\n\n/* -------------------------------------------------------------------------- */\n/* WebCrypto (SubtleCrypto) */\n/* -------------------------------------------------------------------------- */\n\nconst RULE_WEBCRYPTO: RuleMeta = {\n id: \"webcrypto-classical\",\n title: \"WebCrypto classical algorithm\",\n description: \"classical asymmetric algorithm passed to SubtleCrypto\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"A classical asymmetric WebCrypto algorithm is used, which is not quantum-safe.\",\n};\n\n/**\n * Detects classical algorithms passed to WebCrypto's SubtleCrypto methods. The\n * algorithm name can appear as a bare string (\"RSA-OAEP\") or as\n * `{ name: \"ECDH\" }`; we scan both forms within a window after a subtle call.\n */\nconst webCryptoDetector: Detector = {\n id: \"webcrypto\",\n description: \"Classical asymmetric algorithms via WebCrypto SubtleCrypto\",\n scope: \"source\",\n language: \"js\",\n rules: [RULE_WEBCRYPTO],\n appliesTo: (f) => hasExtension(f, JS_TS_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n\n // Only consider names that appear near a subtle.* call to reduce noise.\n // callIndexes is collected in ascending order (regex scans left→right), so\n // proximity is resolved with a binary search instead of an O(M·C) scan.\n const callIndexes: number[] = [];\n eachMatch(RE_SUBTLE_CALL, content, (m) => callIndexes.push(m.index));\n if (callIndexes.length === 0) return findings;\n\n eachMatch(RE_WEBCRYPTO_ALGO, content, (m) => {\n if (!nearSortedCall(callIndexes, m.index, 400)) return;\n const name = m[1].toUpperCase();\n // Classify by algorithm: RSA-OAEP is KEM (HNDL); ECDH/X25519/X448 are key\n // agreement (HNDL); RSA-PSS/RSASSA/ECDSA/Ed25519/Ed448 are signatures.\n let algorithm: Finding[\"algorithm\"];\n let category: Finding[\"category\"];\n let hndl: boolean;\n let severity: Finding[\"severity\"] | undefined;\n if (name.startsWith(\"RSA\")) {\n algorithm = \"RSA\";\n const isKem = name === \"RSA-OAEP\";\n category = isKem ? \"kem\" : \"signature\";\n hndl = isKem;\n } else if (name === \"ECDH\") {\n algorithm = \"ECDH\";\n category = \"key-exchange\";\n hndl = true;\n } else if (name === \"X25519\" || name === \"X448\") {\n algorithm = name === \"X448\" ? \"X448\" : \"X25519\";\n category = \"key-exchange\";\n hndl = true;\n // `medium`, aligned with X25519/X448 key agreement in node/rust/go — HNDL-exposed\n // key agreement scores the same regardless of which surface uses it.\n severity = \"medium\";\n } else if (name === \"ED25519\" || name === \"ED448\") {\n algorithm = \"EdDSA\";\n category = \"signature\";\n hndl = false;\n severity = \"low\";\n } else {\n algorithm = \"ECDSA\";\n category = \"signature\";\n hndl = false;\n }\n findings.push(\n findingFromRule(\n RULE_WEBCRYPTO,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `WebCrypto ${m[1]}`,\n category,\n algorithm,\n hndl,\n ...(severity ? { severity } : {}),\n message: `WebCrypto algorithm \"${m[1]}\" is classical asymmetric crypto and not quantum-safe.`,\n },\n ),\n );\n });\n\n return findings;\n },\n};\n\n/* -------------------------------------------------------------------------- */\n/* Popular crypto libraries */\n/* -------------------------------------------------------------------------- */\n\nconst RULE_FORGE_RSA: RuleMeta = {\n id: \"forge-rsa-keygen\",\n title: \"node-forge RSA key generation\",\n description: \"node-forge pki.rsa.generateKeyPair\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"node-forge generates a classical RSA key pair, which is not quantum-safe.\",\n};\nconst RULE_FORGE_ED25519: RuleMeta = {\n id: \"forge-ed25519\",\n title: \"node-forge Ed25519 usage\",\n description: \"node-forge forge.ed25519.*\",\n category: \"signature\",\n severity: \"low\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"node-forge Ed25519 is a modern but still classical signature scheme.\",\n};\nconst RULE_ELLIPTIC_EC: RuleMeta = {\n id: \"elliptic-ec\",\n title: \"elliptic curve instantiation\",\n description: \"the `elliptic` library — new EC(...)\",\n // `new EC(...)` is a dual-use curve context (ECDSA sign AND ECDH `key.derive()`).\n // Per this scanner's own EC-ambiguity policy, ambiguous EC is treated as\n // key-agreement-capable and HNDL-exposed (audit: crypto #8).\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"The `elliptic` library implements classical ECDSA/ECDH, both broken by Shor's algorithm.\",\n};\nconst RULE_SECP256K1: RuleMeta = {\n id: \"secp256k1-usage\",\n title: \"secp256k1 ECDSA/ECDH usage\",\n description: \"direct @noble/secp256k1-style API usage\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"medium\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Direct secp256k1 usage (ECDSA signatures / ECDH agreement) is classical and broken by Shor's algorithm.\",\n remediation: \"ML-DSA-65 (FIPS 204) for signatures; hybrid X25519MLKEM768 for key agreement.\",\n};\nconst RULE_JSRSASIGN_KEYGEN: RuleMeta = {\n id: \"jsrsasign-keygen\",\n title: \"jsrsasign key generation\",\n description: \"jsrsasign KEYUTIL.generateKeypair\",\n // KEYUTIL.generateKeypair(\"RSA\"|\"EC\") makes keys usable for RSA-OAEP encryption\n // and ECDH — HNDL-exposed, like Node's generateKeyPair (audit: crypto #13).\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"jsrsasign generates classical RSA/EC key pairs, which are not quantum-safe.\",\n remediation: \"ML-KEM-768 (FIPS 203) / ML-DSA-65 (FIPS 204)\",\n};\nconst RULE_JSRSASIGN_SIGN: RuleMeta = {\n id: \"jsrsasign-sign\",\n title: \"jsrsasign signature\",\n description: \"jsrsasign KJUR.crypto.Signature / ECDSA\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"jsrsasign signing uses classical RSA/ECDSA signatures, forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204)\",\n};\nconst RULE_NODE_RSA_LIB: RuleMeta = {\n id: \"node-rsa\",\n title: \"node-rsa key/usage\",\n description: \"the `node-rsa` library — new NodeRSA(...)\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"node-rsa wraps classical RSA encryption/signing, which is not quantum-safe.\",\n};\n\n/** Detects classical crypto from popular npm libraries used in source. */\nconst libraryDetector: Detector = {\n id: \"crypto-libs\",\n description: \"Classical asymmetric crypto via node-forge, elliptic, jsrsasign, node-rsa\",\n scope: \"source\",\n language: \"js\",\n rules: [\n RULE_FORGE_RSA,\n RULE_FORGE_ED25519,\n RULE_ELLIPTIC_EC,\n RULE_SECP256K1,\n RULE_JSRSASIGN_KEYGEN,\n RULE_JSRSASIGN_SIGN,\n RULE_NODE_RSA_LIB,\n ],\n appliesTo: (f) => hasExtension(f, JS_TS_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n const add = (re: RegExp, rule: RuleMeta) =>\n eachMatch(re, content, (m) =>\n findings.push(\n findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }),\n ),\n );\n\n add(RE_FORGE_RSA, RULE_FORGE_RSA); // node-forge: pki.rsa.generateKeyPair(...)\n add(RE_FORGE_ED25519, RULE_FORGE_ED25519); // node-forge: forge.ed25519.*\n add(RE_ELLIPTIC_EC, RULE_ELLIPTIC_EC); // elliptic: new EC('secp256k1')\n // secp256k1: classify per method — getSharedSecret/ecdh are key AGREEMENT\n // (ECDH, harvest-now-decrypt-later); sign/verify/getPublicKey/recover are\n // ECDSA signatures (not HNDL). The old rule flagged everything as ECDSA.\n eachMatch(RE_SECP256K1, content, (m) => {\n const kex = m[1] === \"getSharedSecret\" || m[1] === \"ecdh\";\n findings.push(\n findingFromRule(\n RULE_SECP256K1,\n { file, content, index: m.index, matchLength: m[0].length },\n kex\n ? {\n title: \"secp256k1 ECDH key agreement\",\n category: \"key-exchange\",\n algorithm: \"ECDH\",\n hndl: true,\n message: `secp256k1 ECDH key agreement (.${m[1]}()) is classical and harvest-now-decrypt-later exposed.`,\n }\n : undefined,\n ),\n );\n });\n add(RE_JSRSASIGN_KEYGEN, RULE_JSRSASIGN_KEYGEN); // jsrsasign: KEYUTIL.generateKeypair(...)\n add(RE_JSRSASIGN_SIGN, RULE_JSRSASIGN_SIGN); // jsrsasign: KJUR.crypto.*\n add(RE_NODE_RSA, RULE_NODE_RSA_LIB); // node-rsa: new NodeRSA(...)\n\n return findings;\n },\n};\n\n/* -------------------------------------------------------------------------- */\n/* JWT / JOSE / COSE algorithm strings */\n/* -------------------------------------------------------------------------- */\n\n// JOSE RSA key-transport algorithms (JWE `alg`): quoted RSA-OAEP / RSA-OAEP-256\n// /384/512 / RSA1_5. Classical RSA *encryption* (key transport) — distinct from\n// the RS*/PS* *signature* tokens above, and a harvest-now-decrypt-later surface.\nconst RE_JOSE_KEM = /['\"`](RSA-OAEP(?:-(?:256|384|512))?|RSA1_5)['\"`]/g;\n\nconst RULE_JWT_ALG: RuleMeta = {\n id: \"jwt-classical-alg\",\n title: \"Classical JWT/JOSE algorithm\",\n description: \"JWS alg tokens (RS/PS/ES/EdDSA)\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"A classical JWT/JOSE signature algorithm is used, forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204); track IETF PQC JOSE/COSE algorithms\",\n};\nconst RULE_JOSE_ECDH: RuleMeta = {\n id: \"jose-ecdh-es\",\n title: \"JOSE ECDH-ES key agreement\",\n description: \"JOSE ECDH-ES / ECDH-ES+A*KW key agreement\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"medium\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"JOSE ECDH-ES performs classical ECDH key agreement — harvest-now-decrypt-later exposed.\",\n remediation: \"Track IETF PQC JOSE/COSE; adopt hybrid X25519MLKEM768 KEM-based encryption.\",\n};\nconst RULE_JOSE_RSA_OAEP: RuleMeta = {\n id: \"jose-rsa-oaep\",\n title: \"JOSE RSA key-transport algorithm\",\n description: \"JWE RSA-OAEP / RSA-OAEP-256/384/512 / RSA1_5 key encryption\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"medium\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"JOSE RSA key transport (RSA-OAEP / RSA1_5) is classical RSA encryption — harvest-now-decrypt-later exposed.\",\n remediation: \"Track IETF PQC JOSE/COSE; adopt hybrid X25519MLKEM768 KEM-based encryption.\",\n};\n\n/**\n * Detects classical signature algorithm identifiers used by JWT/JOSE, plus\n * ECDH-ES key-agreement identifiers (HNDL-exposed). These appear as string\n * literals: `alg: \"RS256\"`, `algorithms: [\"ES256\"]`, `enc: \"ECDH-ES+A256KW\"`.\n */\nconst jwtDetector: Detector = {\n id: \"jwt-jose\",\n description: \"Classical JWT/JOSE algorithms (RS/PS/ES/EdDSA) and ECDH-ES key agreement\",\n scope: \"source\",\n // Language-agnostic evidence: a quoted \"RS256\"/\"ES256\" alg token is the same\n // signal in JS/TS or Python (e.g. PyJWT `algorithm=\"RS256\"`), so this detector\n // is un-gated from JS-only to the JWT host surfaces.\n language: \"any\",\n rules: [RULE_JWT_ALG, RULE_JOSE_ECDH, RULE_JOSE_RSA_OAEP],\n appliesTo: (f) => hasExtension(f, JWT_HOST_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n\n // Deferral guards against double-counting:\n // - webCryptoDetector owns a quoted `RSA-OAEP`/`ECDH-ES` sitting next to a\n // `subtle.*(` call (it matches the `RSA-OAEP`/`ECDH` name). Collect the subtle\n // call offsets so the JOSE key-management loops can skip those. (In non-JS host\n // files there are no subtle calls, so nothing is skipped.)\n // - jwkDetector owns any alg/`kty` that lives inside a JWK object; skip a token\n // whose enclosing `{…}` carries a `\"kty\"` so a JWK's own `alg` is not counted by\n // both detectors. Mirrors the same guard jose.ts applies for other languages.\n const subtleCalls: number[] = [];\n eachMatch(RE_SUBTLE_CALL, content, (m) => subtleCalls.push(m.index));\n const inJwk = (index: number): boolean => enclosingObject(content, index).includes('\"kty\"');\n\n // Classical JWS signature alg tokens. Anchored to quotes to avoid words.\n eachMatch(RE_JWT_ALG, content, (m) => {\n if (inJwk(m.index)) return; // jwk-{rsa,ec,eddsa} owns a JWK's own alg\n const alg = m[1];\n let algorithm: Finding[\"algorithm\"];\n if (alg.startsWith(\"RS\") || alg.startsWith(\"PS\")) algorithm = \"RSA\";\n else if (alg === \"EdDSA\") algorithm = \"EdDSA\";\n else algorithm = \"ECDSA\"; // ES*\n findings.push(\n findingFromRule(\n RULE_JWT_ALG,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `JWT/JOSE algorithm ${alg}`,\n algorithm,\n message: `JWT/JOSE algorithm \"${alg}\" is a classical signature, forgeable by a quantum attacker.`,\n },\n ),\n );\n });\n\n // JOSE ECDH-ES key agreement (and ECDH-ES+A*KW) — confidentiality, HNDL.\n eachMatch(RE_JOSE_ECDH, content, (m) => {\n if (inJwk(m.index)) return; // jwk-ec owns a JWK's own alg\n if (nearSortedCall(subtleCalls, m.index, 400)) return; // webcrypto owns it\n findings.push(\n findingFromRule(\n RULE_JOSE_ECDH,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `JOSE key agreement ${m[1]}`,\n message: `JOSE \"${m[1]}\" performs classical ECDH key agreement — harvest-now-decrypt-later exposed.`,\n },\n ),\n );\n });\n\n // JOSE RSA key transport (RSA-OAEP / RSA1_5) — classical RSA encryption, HNDL.\n eachMatch(RE_JOSE_KEM, content, (m) => {\n if (inJwk(m.index)) return; // jwk-rsa owns a JWK's own alg\n // webCryptoDetector's regex matches `RSA-OAEP` but NOT `RSA1_5`, so only defer the\n // OAEP form near a subtle call — deferring RSA1_5 would drop it entirely.\n if (m[1].startsWith(\"RSA-OAEP\") && nearSortedCall(subtleCalls, m.index, 400)) return;\n findings.push(\n findingFromRule(\n RULE_JOSE_RSA_OAEP,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `JOSE RSA key transport ${m[1]}`,\n message: `JOSE \"${m[1]}\" is classical RSA key transport — harvest-now-decrypt-later exposed.`,\n },\n ),\n );\n });\n\n return findings;\n },\n};\n\n/* -------------------------------------------------------------------------- */\n/* TLS legacy configuration */\n/* -------------------------------------------------------------------------- */\n\nconst RULE_TLS_LEGACY: RuleMeta = {\n id: \"tls-legacy-version\",\n title: \"Legacy TLS version pinned\",\n description: \"minVersion/maxVersion/secureProtocol pinned to TLS 1.0/1.1\",\n category: \"tls\",\n severity: \"medium\",\n confidence: \"high\",\n hndl: false,\n cwe: CWE_WEAK_STRENGTH,\n message: \"TLS 1.0/1.1 are deprecated and insecure; require TLS 1.3.\",\n remediation: \"Set minVersion: 'TLSv1.3' and prefer PQC-hybrid key exchange.\",\n};\nconst RULE_TLS_REJECT: RuleMeta = {\n id: \"tls-reject-unauthorized\",\n title: \"TLS certificate verification disabled\",\n description: \"rejectUnauthorized: false\",\n category: \"tls\",\n severity: \"high\",\n confidence: \"high\",\n hndl: false,\n cwe: CWE_CERT_VALIDATION,\n message: \"rejectUnauthorized:false disables TLS certificate verification (MITM risk).\",\n remediation: \"Remove rejectUnauthorized:false; verify certificates properly.\",\n};\nconst RULE_TLS_WEAK_CIPHER: RuleMeta = {\n id: \"tls-weak-cipher\",\n title: \"Weak TLS cipher configured\",\n description: \"weak/export cipher in a `ciphers` string\",\n category: \"tls\",\n severity: \"medium\",\n confidence: \"medium\",\n hndl: false,\n cwe: CWE_WEAK_STRENGTH,\n message: \"A weak cipher is configured in the TLS ciphers list.\",\n remediation: \"Use a modern AEAD cipher suite (TLS 1.3 defaults).\",\n};\n\n/**\n * Detects legacy / insecure TLS configuration expressed as JS object literals:\n * forced TLS 1.0/1.1, disabled certificate verification, and weak ciphers.\n * These aren't quantum-specific but materially weaken transport security and\n * are squarely in qScan's \"config\" scope.\n */\nconst tlsDetector: Detector = {\n id: \"tls-config\",\n description: \"Legacy / insecure TLS configuration in JS objects\",\n scope: \"config\",\n language: \"js\",\n rules: [RULE_TLS_LEGACY, RULE_TLS_REJECT, RULE_TLS_WEAK_CIPHER],\n appliesTo: (f) => hasExtension(f, JS_TS_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n\n // minVersion / maxVersion / secureProtocol pinned to TLS 1.0 or 1.1.\n eachMatch(RE_TLS_LEGACY_VERSION, content, (m) => {\n findings.push(\n findingFromRule(RULE_TLS_LEGACY, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // rejectUnauthorized: false — disables certificate verification.\n eachMatch(RE_TLS_REJECT, content, (m) => {\n findings.push(\n findingFromRule(RULE_TLS_REJECT, {\n file,\n content,\n index: m.index,\n matchLength: m[0].length,\n }),\n );\n });\n\n // Weak / export ciphers referenced in a ciphers string (bounded regex).\n eachMatch(RE_TLS_WEAK_CIPHER, content, (m) => {\n findings.push(\n findingFromRule(\n RULE_TLS_WEAK_CIPHER,\n { file, content, index: m.index, matchLength: m[0].length },\n { message: `Weak cipher (${m[1]}) configured in the TLS ciphers list.` },\n ),\n );\n });\n\n return findings;\n },\n};\n\n/* -------------------------------------------------------------------------- */\n/* SSH public keys + TLS certificate signature algorithms (config scope) */\n/* -------------------------------------------------------------------------- */\n\nconst RE_SSH_PUBKEY = /\\b(ssh-rsa|ssh-ed25519|ssh-dss|ecdsa-sha2-nistp(?:256|384|521))\\b/g;\nconst RE_CERT_SIG_ALG =\n /\\b(sha(?:1|256|384|512)WithRSAEncryption|ecdsa-with-SHA(?:1|256|384|512)|rsassaPss|dsaWithSHA(?:1|256))\\b/g;\n// Classical SSH key-exchange algorithm identifiers: finite-field DH groups\n// (diffie-hellman-group{1,14,15,16,17,18} + group-exchange), ECDH over NIST\n// curves (ecdh-sha2-nistp*), and Curve25519 (curve25519-sha256). All are\n// Shor-broken key agreement — the harvest-now-decrypt-later surface a lexical\n// scan misses when only the `crypto/*` API is matched, not the negotiated kex.\nconst RE_SSH_KEX =\n /\\b(diffie-hellman-group(?:1|14|15|16|17|18)(?:-sha1|-sha256|-sha512)?|diffie-hellman-group-exchange-sha(?:1|256)|ecdh-sha2-nistp(?:256|384|521)|curve25519-sha256)\\b/g;\n\n/**\n * True when the match at `index` sits inside a DOCUMENTATION field value — a\n * `description` / `help` / `summary` / `doc` / `comment` / `note` assignment\n * (`key = \"…\"` or `key: \"…\"`), as used by Terraform/Packer variable descriptions,\n * JSON-schema docs, etc. Classical KEX/cipher algorithm names LISTED in such a field\n * are prose (\"acceptable values include ecdh-sha2-nistp256, …\"), not an active\n * setting, so a transport-token rule must not fire on them. Scans the current line's\n * prefix only (cheap; the common single-line description case).\n */\nfunction inDocFieldValue(content: string, index: number): boolean {\n const lineStart = content.lastIndexOf(\"\\n\", index - 1) + 1;\n const prefix = content.slice(lineStart, index);\n return /\\b(?:description|help|summary|doc|comment|note)\\b\\s*[:=]/i.test(prefix);\n}\n\n// A bare key-type token (`ssh-rsa`, `ssh-ed25519`, …) is real SSH crypto only\n// when it is EITHER (a) followed by base64 key material — an actual\n// authorized_keys / known_hosts entry — OR (b) one of ≥2 DISTINCT ssh key/host-key\n// algorithm tokens on the same line — an algorithm-preference list\n// (`HostKeyAlgorithms ssh-ed25519,ecdsa-sha2-nistp256,ssh-rsa`, `%w[…]`, …). A\n// lone token, e.g. a UI label / i18n value like `\"ssh-rsa\": \"ssh-rsa\"`, is\n// neither, so it must NOT be flagged. `RE_SSH_ALGO_TOKEN` is a separate (cloned-\n// on-use) copy so counting per line never disturbs the outer `eachMatch` state.\nconst RE_SSH_ALGO_TOKEN = /\\b(ssh-rsa|ssh-ed25519|ssh-dss|ecdsa-sha2-nistp(?:256|384|521))\\b/g;\n/** How far around a token we look for a sibling algorithm on the same line. A\n * real `HostKeyAlgorithms` list is short; bounding the window keeps the per-token\n * work O(1) so a pathological single huge line can't make detection quadratic. */\nconst SSH_LINE_WINDOW = 512;\nfunction isRealSshKeyOrAlgoList(content: string, index: number, matchLen: number): boolean {\n // (a) base64 key material immediately after the token → a real SSH public key.\n if (/^\\s+[A-Za-z0-9+/]{20,}/.test(content.slice(index + matchLen, index + matchLen + 80))) {\n return true;\n }\n // (b) ≥2 distinct ssh key/host-key algorithm tokens on the same line → a list.\n // Bound both the back-scan for the line start and the window itself so the work\n // is constant per token and never crosses a line boundary (i18n entries live on\n // separate lines, so a lone repeated token stays a single distinct token).\n const from = Math.max(0, index - SSH_LINE_WINDOW);\n const pre = content.slice(from, index);\n const preNl = pre.lastIndexOf(\"\\n\");\n const lineStart = preNl === -1 ? from : from + preNl + 1;\n const to = Math.min(content.length, index + matchLen + SSH_LINE_WINDOW);\n const post = content.slice(index, to);\n const postNl = post.indexOf(\"\\n\");\n const lineEnd = postNl === -1 ? to : index + postNl;\n const distinct = new Set<string>();\n for (const t of content.slice(lineStart, lineEnd).matchAll(RE_SSH_ALGO_TOKEN)) distinct.add(t[1]);\n return distinct.size >= 2;\n}\n\nconst RULE_SSH_PUBKEY: RuleMeta = {\n id: \"ssh-public-key\",\n title: \"Classical SSH public key\",\n description: \"ssh-rsa / ssh-ed25519 / ssh-dss / ecdsa-sha2-* public keys\",\n category: \"certificate\",\n severity: \"low\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n sensitive: true,\n message: \"A classical SSH public key is forgeable by a quantum attacker.\",\n remediation:\n \"Plan migration to PQC-capable SSH: prefer the mlkem768x25519-sha256 KEX (ML-KEM-768 hybrid, OpenSSH 10's default since Apr 2025); sntrup761x25519 is an acceptable interim. Rotate to PQC host keys as they land.\",\n};\nconst RULE_CERT_SIG_ALG: RuleMeta = {\n id: \"cert-signature-algorithm\",\n title: \"Classical certificate signature algorithm\",\n description: \"X.509/TLS certificate signature-algorithm identifiers\",\n category: \"certificate\",\n severity: \"low\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"A classical certificate signature algorithm (RSA/ECDSA/DSA) is a quantum forgery surface.\",\n remediation: \"Plan re-issuance with PQC-capable CAs as ML-DSA certificate profiles mature.\",\n};\nconst RULE_SSH_KEX: RuleMeta = {\n id: \"ssh-kex-classical\",\n title: \"Classical SSH key exchange\",\n description: \"diffie-hellman-group* / group-exchange / ecdh-sha2-* / curve25519-sha256 kex\",\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"A classical SSH key-exchange algorithm (finite-field DH / ECDH / X25519) is harvest-now-decrypt-later exposed.\",\n remediation:\n \"Prefer the mlkem768x25519-sha256 KEX (ML-KEM-768 hybrid, OpenSSH 10 default); sntrup761x25519 is an acceptable interim.\",\n};\n\n/**\n * Detects classical SSH public keys (`authorized_keys` / `known_hosts` lines)\n * and X.509 certificate signature-algorithm identifiers in any text file. These\n * are language-agnostic config surfaces — the SSH-key forgery surface and the\n * PKI signature surface that lexical PEM detection misses.\n */\nconst sshCertDetector: Detector = {\n id: \"ssh-cert\",\n description: \"SSH public keys and TLS/X.509 certificate signature algorithms in config\",\n scope: \"config\",\n language: \"any\",\n rules: [RULE_SSH_PUBKEY, RULE_CERT_SIG_ALG, RULE_SSH_KEX],\n // Skip prose/docs: a changelog or README that merely mentions `ssh-rsa` in a\n // sentence is not crypto config. PEM material is caught by its own detector.\n appliesTo: (f) => !hasExtension(f, DOC_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n\n // SSH public keys: ssh-rsa AAAA…, ecdsa-sha2-nistp256 …, ssh-ed25519 …\n eachMatch(RE_SSH_PUBKEY, content, (m) => {\n // Skip a bare token that is neither a real key nor an algorithm list (e.g.\n // a `\"ssh-rsa\": \"ssh-rsa\"` i18n label) — see `isRealSshKeyOrAlgoList`.\n if (!isRealSshKeyOrAlgoList(content, m.index, m[0].length)) return;\n const tok = m[1];\n const algorithm: Finding[\"algorithm\"] = tok.startsWith(\"ssh-rsa\")\n ? \"RSA\"\n : tok === \"ssh-ed25519\"\n ? \"EdDSA\"\n : tok === \"ssh-dss\"\n ? \"DSA\"\n : \"ECDSA\";\n findings.push(\n findingFromRule(\n RULE_SSH_PUBKEY,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `Classical SSH public key (${tok})`,\n algorithm,\n message: `SSH public key type \"${tok}\" is a classical key forgeable by a quantum attacker.`,\n },\n ),\n );\n });\n\n // X.509 / TLS certificate signature algorithm identifiers (forgery surface).\n eachMatch(RE_CERT_SIG_ALG, content, (m) => {\n const tok = m[1];\n const algorithm: Finding[\"algorithm\"] = /RSA|rsassa/i.test(tok)\n ? \"RSA\"\n : tok.startsWith(\"ecdsa\")\n ? \"ECDSA\"\n : \"DSA\";\n findings.push(\n findingFromRule(\n RULE_CERT_SIG_ALG,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `Classical certificate signature algorithm (${tok})`,\n algorithm,\n message: `Certificate signature algorithm \"${tok}\" is classical (RSA/ECDSA/DSA) — a quantum forgery surface.`,\n },\n ),\n );\n });\n\n // SSH key-exchange algorithm identifiers (finite-field DH / ECDH / X25519).\n eachMatch(RE_SSH_KEX, content, (m) => {\n if (inDocFieldValue(content, m.index)) return; // names listed in a doc string\n const tok = m[1];\n const algorithm: Finding[\"algorithm\"] = tok.startsWith(\"diffie-hellman\")\n ? \"DH\"\n : tok.startsWith(\"ecdh\")\n ? \"ECDH\"\n : \"X25519\";\n findings.push(\n findingFromRule(\n RULE_SSH_KEX,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n title: `Classical SSH key exchange (${tok})`,\n algorithm,\n message: `SSH key-exchange \"${tok}\" is classical (${algorithm}) — harvest-now-decrypt-later exposed.`,\n },\n ),\n );\n });\n\n return findings;\n },\n};\n\n/* -------------------------------------------------------------------------- */\n/* Classical TLS key-exchange cipher suites (language-agnostic config) */\n/* -------------------------------------------------------------------------- */\n\n// Classical KEX cipher-suite identifiers, in both the OpenSSL (`ECDHE-RSA-…`) and\n// IANA (`TLS_ECDHE_RSA_WITH_…`) spellings, with `-` or `_` separators. These name\n// a Shor-broken key exchange (ECDHE/DHE), so they are the harvest-now surface a\n// PQC scanner should flag — distinct from the legacy-*version* / weak-cipher rules\n// above. Case-sensitive on purpose: cipher-suite tokens are upper-case constants,\n// so prose like \"ecdhe rsa\" does not misfire. No trailing \\b so the IANA\n// `TLS_ECDHE_RSA_WITH_…` form (a `_` follows `RSA`) still matches.\nconst RE_TLS_CLASSICAL_KEX = /\\b(?:TLS_)?(?:ECDHE|ECDH|DHE)[-_](?:RSA|ECDSA|DSS)/g;\n\nconst RULE_TLS_CLASSICAL_KEX: RuleMeta = {\n id: \"tls-classical-kex\",\n title: \"Classical TLS key-exchange cipher suite\",\n description: \"ECDHE / DHE cipher suites negotiate Shor-broken key exchange\",\n category: \"tls\",\n severity: \"medium\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Classical TLS key exchange (ECDHE/DHE) is harvest-now-decrypt-later exposed — the session key can be recorded now and recovered by a quantum attacker.\",\n remediation:\n \"Adopt a PQC-hybrid TLS 1.3 key exchange (e.g. X25519MLKEM768) as your stack and peers support it; keep classical suites only as a transitional fallback.\",\n};\n\n/**\n * Detects classical TLS key-exchange cipher suites in any text/config file\n * (OpenSSL cipher lists, IANA suite constants in Go/Java/C#/Rust, `.properties`,\n * etc.). Language-agnostic because the suite identifiers are the same tokens\n * everywhere — this is the cross-language TLS gap the legacy-version rule misses.\n */\nconst tlsClassicalKexDetector: Detector = {\n id: \"tls-cipher-suite\",\n description: \"Classical TLS key-exchange cipher suites (ECDHE/DHE) in any config\",\n scope: \"config\",\n language: \"any\",\n rules: [RULE_TLS_CLASSICAL_KEX],\n appliesTo: (f) => !hasExtension(f, DOC_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const findings: Finding[] = [];\n eachMatch(RE_TLS_CLASSICAL_KEX, content, (m) => {\n if (inDocFieldValue(content, m.index)) return; // names listed in a doc string\n const tok = m[0];\n const algorithm: Finding[\"algorithm\"] = tok.includes(\"ECDH\") ? \"ECDH\" : \"DH\";\n findings.push(\n findingFromRule(\n RULE_TLS_CLASSICAL_KEX,\n { file, content, index: m.index, matchLength: m[0].length },\n {\n algorithm,\n message: `Classical TLS key-exchange suite \"${tok}…\" (${algorithm}) is harvest-now-decrypt-later exposed.`,\n },\n ),\n );\n });\n return findings;\n },\n};\n\n/** All built-in source/config detectors, in run order. */\nexport const sourceDetectors: Detector[] = [\n nodeCryptoDetector,\n webCryptoDetector,\n libraryDetector,\n jwtDetector,\n tlsDetector,\n sshCertDetector,\n tlsClassicalKexDetector,\n];\n"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config detector: classical key types configured for SPIFFE X.509 SVIDs in
|
|
3
|
+
* SPIRE server/agent configuration (HCL, and the `.conf`/YAML/JSON variants
|
|
4
|
+
* SPIRE deployments ship).
|
|
5
|
+
*
|
|
6
|
+
* SPIRE is the reference SPIFFE implementation: it issues each workload a
|
|
7
|
+
* short-lived X.509-SVID certificate, signed by the SPIRE server's CA (itself
|
|
8
|
+
* often chained to an UpstreamAuthority). The SVID leaf key and the CA signing
|
|
9
|
+
* key are configured by explicit key-type strings:
|
|
10
|
+
* - server `ca_key_type = "rsa-2048" | "rsa-4096" | "ec-p256" | "ec-p384"` —
|
|
11
|
+
* the CA that signs every workload SVID in the trust domain (the identity
|
|
12
|
+
* ROOT: forge this and you forge the whole trust domain).
|
|
13
|
+
* - agent/server `svid_key_type = "rsa-2048" | "ec-p256"` — the per-workload
|
|
14
|
+
* leaf key type.
|
|
15
|
+
* - per-plugin `key_type = "rsa-2048" | "ec-p256"` on UpstreamAuthority /
|
|
16
|
+
* KeyManager plugins.
|
|
17
|
+
*
|
|
18
|
+
* These are SIGNING / identity keys, not confidentiality keys: an SVID X.509
|
|
19
|
+
* signature is verified, never used to wrap harvestable ciphertext. So there is
|
|
20
|
+
* nothing to "harvest now, decrypt later" — `hndl: false` — but every SVID
|
|
21
|
+
* signature (and the CA signature over it) becomes FORGEABLE the moment a
|
|
22
|
+
* cryptographically-relevant quantum computer (CRQC) exists, letting an attacker
|
|
23
|
+
* mint certificates for any SPIFFE ID in the trust domain. Findings are
|
|
24
|
+
* therefore `category: "certificate"` (X.509 / PKI material), `severity:
|
|
25
|
+
* "medium"`, `confidence: "high"`.
|
|
26
|
+
*
|
|
27
|
+
* Algorithm mapping (SPIRE key-type value → {@link AlgorithmFamily}):
|
|
28
|
+
* - `rsa-2048` / `rsa-4096` / any `rsa-*` → RSA
|
|
29
|
+
* - `ec-p256` / `ec-p384` / `ecdsa` → ECDSA
|
|
30
|
+
*
|
|
31
|
+
* Match shape: the key-type attribute name (`ca_key_type`, `svid_key_type`, or
|
|
32
|
+
* the bare per-plugin `key_type`) followed by `=`/`:` and a quoted value, in
|
|
33
|
+
* both HCL (`=`) and YAML/JSON (`:`) forms. The `\b(?:ca_|svid_)?key_type\b`
|
|
34
|
+
* anchor covers all three names in one pattern — the leading `\b` won't fire
|
|
35
|
+
* inside `ca_key_type`/`svid_key_type` for the bare `key_type` alternative
|
|
36
|
+
* because `_` is a word character, so those longer names are matched whole.
|
|
37
|
+
*
|
|
38
|
+
* Fast reject: `detect()` bails unless the file carries a SPIFFE/SPIRE-specific
|
|
39
|
+
* marker (`spiffe`, `spire`, the distinctive `ca_key_type`, or `svid`). A bare
|
|
40
|
+
* `key_type = "rsa-2048"` is deliberately NOT a sufficient marker — `key_type`
|
|
41
|
+
* is a generic attribute (Vault PKI roles, cloud IaC, …), so without a
|
|
42
|
+
* spiffe/spire/svid/ca_key_type anchor an unrelated config must not fire. This
|
|
43
|
+
* keeps the generic per-plugin `key_type` rule precise while still catching a
|
|
44
|
+
* real SPIRE config, which always names its trust domain / server / SVIDs.
|
|
45
|
+
*/
|
|
46
|
+
import type { Detector } from "../types.js";
|
|
47
|
+
/** Detects classical key types configured for SPIFFE X.509 SVIDs in SPIRE config. */
|
|
48
|
+
export declare const spireDetector: Detector;
|
|
49
|
+
//# sourceMappingURL=spire.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spire.d.ts","sourceRoot":"","sources":["../../src/detectors/spire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAqE/D,qFAAqF;AACrF,eAAO,MAAM,aAAa,EAAE,QA2B3B,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { DOC_EXTENSIONS, eachMatch, findingFromRule, hasExtension, maskCommentLines, } from "../detect-utils.js";
|
|
2
|
+
import { CWE_BROKEN_CRYPTO } from "../cwe.js";
|
|
3
|
+
// SPIRE config is HCL/conf, but deployments also template it as YAML (Helm
|
|
4
|
+
// values / ConfigMaps) or JSON. Prose (`.md`, …) is excluded in `appliesTo`.
|
|
5
|
+
const SPIRE_EXTENSIONS = [".conf", ".hcl", ".yaml", ".yml", ".json"];
|
|
6
|
+
// The three SPIRE key-type attribute names in one anchor: `ca_key_type`,
|
|
7
|
+
// `svid_key_type`, and the bare per-plugin `key_type`.
|
|
8
|
+
const KEY_ATTR = "(?:ca_|svid_)?key_type";
|
|
9
|
+
// HCL `=`, unquoted YAML `:`, and JSON `"key_type": "..."` assignment forms. The
|
|
10
|
+
// attribute-name and value quotes are BOTH optional (`"?`): HCL uses `key_type =
|
|
11
|
+
// "rsa-2048"`, Helm/YAML uses the unquoted `key_type: rsa-2048`, and JSON quotes
|
|
12
|
+
// the key (`"key_type": "rsa-2048"`) — a required-quote regex missed the latter
|
|
13
|
+
// two entirely. Case-insensitive, though SPIRE writes these lowercase.
|
|
14
|
+
const RE_SPIRE_RSA = new RegExp(`\\b${KEY_ATTR}"?\\s*[:=]\\s*"?rsa-\\d+`, "gi");
|
|
15
|
+
const RE_SPIRE_ECDSA = new RegExp(`\\b${KEY_ATTR}"?\\s*[:=]\\s*"?(?:ec-p\\d+|ecdsa)\\b`, "gi");
|
|
16
|
+
const RULE_SPIRE_RSA = {
|
|
17
|
+
id: "spire-rsa-key",
|
|
18
|
+
title: "SPIRE/SPIFFE RSA SVID key type",
|
|
19
|
+
description: 'SPIRE ca_key_type/svid_key_type/key_type = "rsa-*" (classical X.509-SVID key)',
|
|
20
|
+
category: "certificate",
|
|
21
|
+
severity: "medium",
|
|
22
|
+
confidence: "high",
|
|
23
|
+
algorithm: "RSA",
|
|
24
|
+
hndl: false,
|
|
25
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
26
|
+
message: "SPIRE issues SPIFFE X.509-SVIDs with a classical RSA key; the SVID (and CA) signatures become forgeable once a CRQC exists, letting an attacker mint identities for the trust domain.",
|
|
27
|
+
remediation: "SPIFFE/SPIRE has no PQC SVID key type yet — track the SPIFFE roadmap for PQC signature support. Prioritise the SPIRE server ca_key_type: the classical CA is the identity root, so its forgeability compromises every workload SVID.",
|
|
28
|
+
};
|
|
29
|
+
const RULE_SPIRE_ECDSA = {
|
|
30
|
+
id: "spire-ec-key",
|
|
31
|
+
title: "SPIRE/SPIFFE ECDSA SVID key type",
|
|
32
|
+
description: 'SPIRE ca_key_type/svid_key_type/key_type = "ec-p256|ec-p384|ecdsa" (classical X.509-SVID key)',
|
|
33
|
+
category: "certificate",
|
|
34
|
+
severity: "medium",
|
|
35
|
+
confidence: "high",
|
|
36
|
+
algorithm: "ECDSA",
|
|
37
|
+
hndl: false,
|
|
38
|
+
cwe: CWE_BROKEN_CRYPTO,
|
|
39
|
+
message: "SPIRE issues SPIFFE X.509-SVIDs with a classical ECDSA (P-256/P-384) key; the SVID (and CA) signatures become forgeable once a CRQC exists, letting an attacker mint identities for the trust domain.",
|
|
40
|
+
remediation: "SPIFFE/SPIRE has no PQC SVID key type yet — track the SPIFFE roadmap for PQC signature support. Prioritise the SPIRE server ca_key_type: the classical CA is the identity root, so its forgeability compromises every workload SVID.",
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* True when `content` carries a SPIFFE/SPIRE-specific marker. A bare generic
|
|
44
|
+
* `key_type` is intentionally NOT enough — only `spiffe`/`spire` context, the
|
|
45
|
+
* distinctive `ca_key_type`, or an `svid` token qualifies — so an unrelated
|
|
46
|
+
* config that merely sets `key_type = "rsa-2048"` cannot fire.
|
|
47
|
+
*/
|
|
48
|
+
function hasSpireMarker(content) {
|
|
49
|
+
// Word-anchored so `inspired` / `aspire` / a `svid` substring inside a longer
|
|
50
|
+
// token don't qualify; `ca_key_type` is distinctive enough to match unanchored.
|
|
51
|
+
return /\b(?:spiffe|spire|svid)\b/i.test(content) || content.includes("ca_key_type");
|
|
52
|
+
}
|
|
53
|
+
/** Detects classical key types configured for SPIFFE X.509 SVIDs in SPIRE config. */
|
|
54
|
+
export const spireDetector = {
|
|
55
|
+
id: "spire-crypto",
|
|
56
|
+
description: "Classical key types for SPIFFE X.509 SVIDs in SPIRE server/agent config",
|
|
57
|
+
scope: "config",
|
|
58
|
+
language: "any",
|
|
59
|
+
rules: [RULE_SPIRE_RSA, RULE_SPIRE_ECDSA],
|
|
60
|
+
// Gate to SPIRE's config extensions, and never run on prose (a README that
|
|
61
|
+
// describes `ca_key_type = "rsa-2048"` is documentation, not live config).
|
|
62
|
+
appliesTo: (f) => hasExtension(f, SPIRE_EXTENSIONS) && !hasExtension(f, DOC_EXTENSIONS),
|
|
63
|
+
detect({ file, content }) {
|
|
64
|
+
if (!hasSpireMarker(content))
|
|
65
|
+
return [];
|
|
66
|
+
// Mask whole comment lines (HCL/YAML `#`, HCL/JSON5 `//`) so a commented-out
|
|
67
|
+
// key-type directive can't fire. Offsets are preserved, so finding
|
|
68
|
+
// line/column/snippet for the remaining live config stay exact.
|
|
69
|
+
const scan = maskCommentLines(content, ["#", "//"]);
|
|
70
|
+
const findings = [];
|
|
71
|
+
const add = (re, rule) => eachMatch(re, scan, (m) => findings.push(findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length })));
|
|
72
|
+
add(RE_SPIRE_RSA, RULE_SPIRE_RSA);
|
|
73
|
+
add(RE_SPIRE_ECDSA, RULE_SPIRE_ECDSA);
|
|
74
|
+
return findings;
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=spire.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spire.js","sourceRoot":"","sources":["../../src/detectors/spire.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Config detector: classical key types configured for SPIFFE X.509 SVIDs in\n * SPIRE server/agent configuration (HCL, and the `.conf`/YAML/JSON variants\n * SPIRE deployments ship).\n *\n * SPIRE is the reference SPIFFE implementation: it issues each workload a\n * short-lived X.509-SVID certificate, signed by the SPIRE server's CA (itself\n * often chained to an UpstreamAuthority). The SVID leaf key and the CA signing\n * key are configured by explicit key-type strings:\n * - server `ca_key_type = \"rsa-2048\" | \"rsa-4096\" | \"ec-p256\" | \"ec-p384\"` —\n * the CA that signs every workload SVID in the trust domain (the identity\n * ROOT: forge this and you forge the whole trust domain).\n * - agent/server `svid_key_type = \"rsa-2048\" | \"ec-p256\"` — the per-workload\n * leaf key type.\n * - per-plugin `key_type = \"rsa-2048\" | \"ec-p256\"` on UpstreamAuthority /\n * KeyManager plugins.\n *\n * These are SIGNING / identity keys, not confidentiality keys: an SVID X.509\n * signature is verified, never used to wrap harvestable ciphertext. So there is\n * nothing to \"harvest now, decrypt later\" — `hndl: false` — but every SVID\n * signature (and the CA signature over it) becomes FORGEABLE the moment a\n * cryptographically-relevant quantum computer (CRQC) exists, letting an attacker\n * mint certificates for any SPIFFE ID in the trust domain. Findings are\n * therefore `category: \"certificate\"` (X.509 / PKI material), `severity:\n * \"medium\"`, `confidence: \"high\"`.\n *\n * Algorithm mapping (SPIRE key-type value → {@link AlgorithmFamily}):\n * - `rsa-2048` / `rsa-4096` / any `rsa-*` → RSA\n * - `ec-p256` / `ec-p384` / `ecdsa` → ECDSA\n *\n * Match shape: the key-type attribute name (`ca_key_type`, `svid_key_type`, or\n * the bare per-plugin `key_type`) followed by `=`/`:` and a quoted value, in\n * both HCL (`=`) and YAML/JSON (`:`) forms. The `\\b(?:ca_|svid_)?key_type\\b`\n * anchor covers all three names in one pattern — the leading `\\b` won't fire\n * inside `ca_key_type`/`svid_key_type` for the bare `key_type` alternative\n * because `_` is a word character, so those longer names are matched whole.\n *\n * Fast reject: `detect()` bails unless the file carries a SPIFFE/SPIRE-specific\n * marker (`spiffe`, `spire`, the distinctive `ca_key_type`, or `svid`). A bare\n * `key_type = \"rsa-2048\"` is deliberately NOT a sufficient marker — `key_type`\n * is a generic attribute (Vault PKI roles, cloud IaC, …), so without a\n * spiffe/spire/svid/ca_key_type anchor an unrelated config must not fire. This\n * keeps the generic per-plugin `key_type` rule precise while still catching a\n * real SPIRE config, which always names its trust domain / server / SVIDs.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport {\n DOC_EXTENSIONS,\n eachMatch,\n findingFromRule,\n hasExtension,\n maskCommentLines,\n} from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO } from \"../cwe.js\";\n\n// SPIRE config is HCL/conf, but deployments also template it as YAML (Helm\n// values / ConfigMaps) or JSON. Prose (`.md`, …) is excluded in `appliesTo`.\nconst SPIRE_EXTENSIONS: readonly string[] = [\".conf\", \".hcl\", \".yaml\", \".yml\", \".json\"];\n\n// The three SPIRE key-type attribute names in one anchor: `ca_key_type`,\n// `svid_key_type`, and the bare per-plugin `key_type`.\nconst KEY_ATTR = \"(?:ca_|svid_)?key_type\";\n// HCL `=`, unquoted YAML `:`, and JSON `\"key_type\": \"...\"` assignment forms. The\n// attribute-name and value quotes are BOTH optional (`\"?`): HCL uses `key_type =\n// \"rsa-2048\"`, Helm/YAML uses the unquoted `key_type: rsa-2048`, and JSON quotes\n// the key (`\"key_type\": \"rsa-2048\"`) — a required-quote regex missed the latter\n// two entirely. Case-insensitive, though SPIRE writes these lowercase.\nconst RE_SPIRE_RSA = new RegExp(`\\\\b${KEY_ATTR}\"?\\\\s*[:=]\\\\s*\"?rsa-\\\\d+`, \"gi\");\nconst RE_SPIRE_ECDSA = new RegExp(`\\\\b${KEY_ATTR}\"?\\\\s*[:=]\\\\s*\"?(?:ec-p\\\\d+|ecdsa)\\\\b`, \"gi\");\n\nconst RULE_SPIRE_RSA: RuleMeta = {\n id: \"spire-rsa-key\",\n title: \"SPIRE/SPIFFE RSA SVID key type\",\n description: 'SPIRE ca_key_type/svid_key_type/key_type = \"rsa-*\" (classical X.509-SVID key)',\n category: \"certificate\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"SPIRE issues SPIFFE X.509-SVIDs with a classical RSA key; the SVID (and CA) signatures become forgeable once a CRQC exists, letting an attacker mint identities for the trust domain.\",\n remediation:\n \"SPIFFE/SPIRE has no PQC SVID key type yet — track the SPIFFE roadmap for PQC signature support. Prioritise the SPIRE server ca_key_type: the classical CA is the identity root, so its forgeability compromises every workload SVID.\",\n};\nconst RULE_SPIRE_ECDSA: RuleMeta = {\n id: \"spire-ec-key\",\n title: \"SPIRE/SPIFFE ECDSA SVID key type\",\n description:\n 'SPIRE ca_key_type/svid_key_type/key_type = \"ec-p256|ec-p384|ecdsa\" (classical X.509-SVID key)',\n category: \"certificate\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"SPIRE issues SPIFFE X.509-SVIDs with a classical ECDSA (P-256/P-384) key; the SVID (and CA) signatures become forgeable once a CRQC exists, letting an attacker mint identities for the trust domain.\",\n remediation:\n \"SPIFFE/SPIRE has no PQC SVID key type yet — track the SPIFFE roadmap for PQC signature support. Prioritise the SPIRE server ca_key_type: the classical CA is the identity root, so its forgeability compromises every workload SVID.\",\n};\n\n/**\n * True when `content` carries a SPIFFE/SPIRE-specific marker. A bare generic\n * `key_type` is intentionally NOT enough — only `spiffe`/`spire` context, the\n * distinctive `ca_key_type`, or an `svid` token qualifies — so an unrelated\n * config that merely sets `key_type = \"rsa-2048\"` cannot fire.\n */\nfunction hasSpireMarker(content: string): boolean {\n // Word-anchored so `inspired` / `aspire` / a `svid` substring inside a longer\n // token don't qualify; `ca_key_type` is distinctive enough to match unanchored.\n return /\\b(?:spiffe|spire|svid)\\b/i.test(content) || content.includes(\"ca_key_type\");\n}\n\n/** Detects classical key types configured for SPIFFE X.509 SVIDs in SPIRE config. */\nexport const spireDetector: Detector = {\n id: \"spire-crypto\",\n description: \"Classical key types for SPIFFE X.509 SVIDs in SPIRE server/agent config\",\n scope: \"config\",\n language: \"any\",\n rules: [RULE_SPIRE_RSA, RULE_SPIRE_ECDSA],\n // Gate to SPIRE's config extensions, and never run on prose (a README that\n // describes `ca_key_type = \"rsa-2048\"` is documentation, not live config).\n appliesTo: (f) => hasExtension(f, SPIRE_EXTENSIONS) && !hasExtension(f, DOC_EXTENSIONS),\n detect({ file, content }): Finding[] {\n if (!hasSpireMarker(content)) return [];\n\n // Mask whole comment lines (HCL/YAML `#`, HCL/JSON5 `//`) so a commented-out\n // key-type directive can't fire. Offsets are preserved, so finding\n // line/column/snippet for the remaining live config stay exact.\n const scan = maskCommentLines(content, [\"#\", \"//\"]);\n const findings: Finding[] = [];\n const add = (re: RegExp, rule: RuleMeta) =>\n eachMatch(re, scan, (m) =>\n findings.push(\n findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length }),\n ),\n );\n add(RE_SPIRE_RSA, RULE_SPIRE_RSA);\n add(RE_SPIRE_ECDSA, RULE_SPIRE_ECDSA);\n return findings;\n },\n};\n"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config detector: classical SSH **certificate-authority** cryptography — the
|
|
3
|
+
* OpenSSH certificate mechanism, in which a CA key signs host/user certificates
|
|
4
|
+
* (`*-cert-v01@openssh.com`) that servers and clients then trust in place of
|
|
5
|
+
* bare public keys.
|
|
6
|
+
*
|
|
7
|
+
* This is DIFFERENT from the `ssh-kex-classical` rule in `source.ts`, and from
|
|
8
|
+
* the `ssh-public-key` rule there — deliberately non-overlapping:
|
|
9
|
+
* - `ssh-kex-classical` is about the SSH *key-exchange* (finite-field DH, ECDH,
|
|
10
|
+
* curve25519): session-key *agreement*, `category: "key-exchange"`,
|
|
11
|
+
* `hndl: true` — a passively-recorded handshake is decryptable once a CRQC
|
|
12
|
+
* exists (harvest-now-decrypt-later confidentiality loss).
|
|
13
|
+
* - `ssh-public-key` flags bare `ssh-rsa AAAA…` / `ecdsa-sha2-* …` key lines.
|
|
14
|
+
* - THIS detector flags the SSH **certificate / CA signing** surface: the
|
|
15
|
+
* `*-cert-v01@openssh.com` cert key types, the `@cert-authority` known_hosts
|
|
16
|
+
* marker, the `TrustedUserCAKeys` / `HostCertificate` sshd directives, and
|
|
17
|
+
* `ssh-keygen -s` (the command that signs a certificate with a CA key).
|
|
18
|
+
*
|
|
19
|
+
* WHY it matters for PQC: an SSH certificate is a *signature* made by a CA key
|
|
20
|
+
* over a principal's public key + validity constraints. There is no
|
|
21
|
+
* confidentiality to harvest (so `hndl: false`), but every such signature
|
|
22
|
+
* becomes FORGEABLE the moment a cryptographically-relevant quantum computer
|
|
23
|
+
* (CRQC) can recover the classical CA private key from its public key. Forging a
|
|
24
|
+
* CA signature lets an attacker mint host or user certificates that every relying
|
|
25
|
+
* party accepts — a full trust-root compromise. SSH CA keys are also unusually
|
|
26
|
+
* long-lived (they are the anchor an entire fleet trusts and are rotated
|
|
27
|
+
* rarely), so the exposure window is large. Hence `category: "signature"`,
|
|
28
|
+
* `severity: "medium"`, `confidence: "high"`.
|
|
29
|
+
*
|
|
30
|
+
* Two match shapes:
|
|
31
|
+
* 1. The cert key type, which NAMES the signing algorithm → an accurate
|
|
32
|
+
* {@link AlgorithmFamily}:
|
|
33
|
+
* - `ssh-rsa-cert-v01@openssh.com`, `rsa-sha2-256/512-cert-v01@openssh.com` → RSA
|
|
34
|
+
* - `ecdsa-sha2-nistp256/384/521-cert-v01@openssh.com` → ECDSA
|
|
35
|
+
* - `ssh-ed25519-cert-v01@openssh.com` → EdDSA
|
|
36
|
+
* 2. The CA *deployment* directives — `TrustedUserCAKeys` / `HostCertificate`
|
|
37
|
+
* (sshd_config) and `ssh-keygen -s` (the CA signing command). These are the
|
|
38
|
+
* MOST COMMON way an SSH CA is configured, but they don't name the algorithm
|
|
39
|
+
* (that lives in the referenced key file), so they emit the `ssh-ca-config`
|
|
40
|
+
* rule with `algorithm: "unknown"` and `confidence: "medium"`.
|
|
41
|
+
*
|
|
42
|
+
* Precision:
|
|
43
|
+
* - Fast reject: `detect()` bails unless the file carries an SSH-CA marker
|
|
44
|
+
* (`cert-v01@openssh.com`, `@cert-authority`, `TrustedUserCAKeys`,
|
|
45
|
+
* `HostCertificate`, or `ssh-keygen -s`) — so the algorithm tokens can't be
|
|
46
|
+
* reached on unrelated config.
|
|
47
|
+
* - The cert-type tokens are the full `*-cert-v01@openssh.com` strings. The
|
|
48
|
+
* trailing `-cert-v01@openssh.com` suffix distinguishes a CA certificate type
|
|
49
|
+
* from the plain `ssh-rsa` / `ssh-ed25519` public-key tokens handled by
|
|
50
|
+
* `ssh-public-key`, so a non-cert `ssh-ed25519 AAAA…` line NEVER fires a cert
|
|
51
|
+
* rule here.
|
|
52
|
+
* - Comment lines (`#`) are masked with {@link maskCommentLines} (offsets
|
|
53
|
+
* preserved) so a commented-out cert line can't fire. Known_hosts
|
|
54
|
+
* `@cert-authority` lines start with `@`, not `#`, so masking leaves them
|
|
55
|
+
* live — exactly what we want.
|
|
56
|
+
* - Doc/prose files are excluded ({@link DOC_EXTENSIONS}), and so are program
|
|
57
|
+
* SOURCE files ({@link ANALYZABLE_SOURCE_EXTENSIONS}) — a vendored SSH library
|
|
58
|
+
* or constants table that spells a cert type as a string literal is not live
|
|
59
|
+
* CA config. SSH CA config lives in extensionless / `.conf` / `.pub` files.
|
|
60
|
+
*
|
|
61
|
+
* The matched line frequently carries the CA public key's base64 blob (a
|
|
62
|
+
* `@cert-authority` known_hosts entry), so findings are marked `sensitive` and
|
|
63
|
+
* reporters drop the snippet, consistent with `ssh-public-key`.
|
|
64
|
+
*/
|
|
65
|
+
import type { Detector } from "../types.js";
|
|
66
|
+
/**
|
|
67
|
+
* Detects classical SSH certificate-authority signing (OpenSSH cert key types)
|
|
68
|
+
* in SSH config, sshd_config, and known_hosts files. Distinct from SSH
|
|
69
|
+
* key-exchange (`ssh-kex-classical`): this is the certificate SIGNATURE surface.
|
|
70
|
+
*/
|
|
71
|
+
export declare const sshCaDetector: Detector;
|
|
72
|
+
//# sourceMappingURL=ssh-ca.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-ca.d.ts","sourceRoot":"","sources":["../../src/detectors/ssh-ca.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAmH/D;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,QA8B3B,CAAC"}
|