@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.
Files changed (314) hide show
  1. package/README.md +76 -27
  2. package/dist/cbom-merge.d.ts +9 -0
  3. package/dist/cbom-merge.d.ts.map +1 -0
  4. package/dist/cbom-merge.js +121 -0
  5. package/dist/cbom-merge.js.map +1 -0
  6. package/dist/cbom.d.ts +5 -0
  7. package/dist/cbom.d.ts.map +1 -1
  8. package/dist/cbom.js +132 -37
  9. package/dist/cbom.js.map +1 -1
  10. package/dist/comments.d.ts +6 -26
  11. package/dist/comments.d.ts.map +1 -1
  12. package/dist/comments.js +77 -38
  13. package/dist/comments.js.map +1 -1
  14. package/dist/dependencies.d.ts.map +1 -1
  15. package/dist/dependencies.js +1 -1
  16. package/dist/dependencies.js.map +1 -1
  17. package/dist/detect-utils.d.ts +59 -21
  18. package/dist/detect-utils.d.ts.map +1 -1
  19. package/dist/detect-utils.js +143 -8
  20. package/dist/detect-utils.js.map +1 -1
  21. package/dist/detectors/age.d.ts +16 -0
  22. package/dist/detectors/age.d.ts.map +1 -0
  23. package/dist/detectors/age.js +40 -0
  24. package/dist/detectors/age.js.map +1 -0
  25. package/dist/detectors/ansible.d.ts +13 -0
  26. package/dist/detectors/ansible.d.ts.map +1 -0
  27. package/dist/detectors/ansible.js +108 -0
  28. package/dist/detectors/ansible.js.map +1 -0
  29. package/dist/detectors/bicep.d.ts +20 -0
  30. package/dist/detectors/bicep.d.ts.map +1 -0
  31. package/dist/detectors/bicep.js +74 -0
  32. package/dist/detectors/bicep.js.map +1 -0
  33. package/dist/detectors/c.d.ts +4 -2
  34. package/dist/detectors/c.d.ts.map +1 -1
  35. package/dist/detectors/c.js +222 -4
  36. package/dist/detectors/c.js.map +1 -1
  37. package/dist/detectors/cicd.d.ts +27 -0
  38. package/dist/detectors/cicd.d.ts.map +1 -0
  39. package/dist/detectors/cicd.js +129 -0
  40. package/dist/detectors/cicd.js.map +1 -0
  41. package/dist/detectors/cloud-kms.d.ts +24 -0
  42. package/dist/detectors/cloud-kms.d.ts.map +1 -0
  43. package/dist/detectors/cloud-kms.js +99 -0
  44. package/dist/detectors/cloud-kms.js.map +1 -0
  45. package/dist/detectors/cloudformation.d.ts +38 -0
  46. package/dist/detectors/cloudformation.d.ts.map +1 -0
  47. package/dist/detectors/cloudformation.js +201 -0
  48. package/dist/detectors/cloudformation.js.map +1 -0
  49. package/dist/detectors/codesign.d.ts +50 -0
  50. package/dist/detectors/codesign.d.ts.map +1 -0
  51. package/dist/detectors/codesign.js +143 -0
  52. package/dist/detectors/codesign.js.map +1 -0
  53. package/dist/detectors/csharp.d.ts.map +1 -1
  54. package/dist/detectors/csharp.js +13 -3
  55. package/dist/detectors/csharp.js.map +1 -1
  56. package/dist/detectors/dart.d.ts +35 -0
  57. package/dist/detectors/dart.d.ts.map +1 -0
  58. package/dist/detectors/dart.js +177 -0
  59. package/dist/detectors/dart.js.map +1 -0
  60. package/dist/detectors/database.d.ts +19 -0
  61. package/dist/detectors/database.d.ts.map +1 -0
  62. package/dist/detectors/database.js +97 -0
  63. package/dist/detectors/database.js.map +1 -0
  64. package/dist/detectors/dkim.d.ts +54 -0
  65. package/dist/detectors/dkim.d.ts.map +1 -0
  66. package/dist/detectors/dkim.js +92 -0
  67. package/dist/detectors/dkim.js.map +1 -0
  68. package/dist/detectors/dnssec.d.ts +55 -0
  69. package/dist/detectors/dnssec.d.ts.map +1 -0
  70. package/dist/detectors/dnssec.js +116 -0
  71. package/dist/detectors/dnssec.js.map +1 -0
  72. package/dist/detectors/elixir.d.ts +20 -0
  73. package/dist/detectors/elixir.d.ts.map +1 -0
  74. package/dist/detectors/elixir.js +227 -0
  75. package/dist/detectors/elixir.js.map +1 -0
  76. package/dist/detectors/java.d.ts.map +1 -1
  77. package/dist/detectors/java.js +34 -4
  78. package/dist/detectors/java.js.map +1 -1
  79. package/dist/detectors/jose.d.ts +20 -0
  80. package/dist/detectors/jose.d.ts.map +1 -0
  81. package/dist/detectors/jose.js +72 -0
  82. package/dist/detectors/jose.js.map +1 -0
  83. package/dist/detectors/jwk.d.ts +25 -0
  84. package/dist/detectors/jwk.d.ts.map +1 -0
  85. package/dist/detectors/jwk.js +131 -0
  86. package/dist/detectors/jwk.js.map +1 -0
  87. package/dist/detectors/k8s.d.ts +17 -0
  88. package/dist/detectors/k8s.d.ts.map +1 -0
  89. package/dist/detectors/k8s.js +88 -0
  90. package/dist/detectors/k8s.js.map +1 -0
  91. package/dist/detectors/keystore.d.ts +19 -0
  92. package/dist/detectors/keystore.d.ts.map +1 -0
  93. package/dist/detectors/keystore.js +76 -0
  94. package/dist/detectors/keystore.js.map +1 -0
  95. package/dist/detectors/mesh.d.ts +34 -0
  96. package/dist/detectors/mesh.d.ts.map +1 -0
  97. package/dist/detectors/mesh.js +91 -0
  98. package/dist/detectors/mesh.js.map +1 -0
  99. package/dist/detectors/messaging.d.ts +16 -0
  100. package/dist/detectors/messaging.d.ts.map +1 -0
  101. package/dist/detectors/messaging.js +79 -0
  102. package/dist/detectors/messaging.js.map +1 -0
  103. package/dist/detectors/objc.d.ts +41 -0
  104. package/dist/detectors/objc.d.ts.map +1 -0
  105. package/dist/detectors/objc.js +146 -0
  106. package/dist/detectors/objc.js.map +1 -0
  107. package/dist/detectors/openpgp.d.ts +20 -0
  108. package/dist/detectors/openpgp.d.ts.map +1 -0
  109. package/dist/detectors/openpgp.js +151 -0
  110. package/dist/detectors/openpgp.js.map +1 -0
  111. package/dist/detectors/pem.d.ts.map +1 -1
  112. package/dist/detectors/pem.js +33 -1
  113. package/dist/detectors/pem.js.map +1 -1
  114. package/dist/detectors/php.d.ts +25 -0
  115. package/dist/detectors/php.d.ts.map +1 -0
  116. package/dist/detectors/php.js +171 -0
  117. package/dist/detectors/php.js.map +1 -0
  118. package/dist/detectors/pkcs11.d.ts +17 -0
  119. package/dist/detectors/pkcs11.d.ts.map +1 -0
  120. package/dist/detectors/pkcs11.js +87 -0
  121. package/dist/detectors/pkcs11.js.map +1 -0
  122. package/dist/detectors/proxy.d.ts +52 -0
  123. package/dist/detectors/proxy.d.ts.map +1 -0
  124. package/dist/detectors/proxy.js +157 -0
  125. package/dist/detectors/proxy.js.map +1 -0
  126. package/dist/detectors/pulumi.d.ts +19 -0
  127. package/dist/detectors/pulumi.d.ts.map +1 -0
  128. package/dist/detectors/pulumi.js +80 -0
  129. package/dist/detectors/pulumi.js.map +1 -0
  130. package/dist/detectors/python.d.ts.map +1 -1
  131. package/dist/detectors/python.js +70 -0
  132. package/dist/detectors/python.js.map +1 -1
  133. package/dist/detectors/rust.d.ts.map +1 -1
  134. package/dist/detectors/rust.js +73 -0
  135. package/dist/detectors/rust.js.map +1 -1
  136. package/dist/detectors/secrets.d.ts +24 -0
  137. package/dist/detectors/secrets.d.ts.map +1 -0
  138. package/dist/detectors/secrets.js +63 -0
  139. package/dist/detectors/secrets.js.map +1 -0
  140. package/dist/detectors/solidity.d.ts +50 -0
  141. package/dist/detectors/solidity.d.ts.map +1 -0
  142. package/dist/detectors/solidity.js +108 -0
  143. package/dist/detectors/solidity.js.map +1 -0
  144. package/dist/detectors/source.d.ts.map +1 -1
  145. package/dist/detectors/source.js +243 -53
  146. package/dist/detectors/source.js.map +1 -1
  147. package/dist/detectors/spire.d.ts +49 -0
  148. package/dist/detectors/spire.d.ts.map +1 -0
  149. package/dist/detectors/spire.js +77 -0
  150. package/dist/detectors/spire.js.map +1 -0
  151. package/dist/detectors/ssh-ca.d.ts +72 -0
  152. package/dist/detectors/ssh-ca.d.ts.map +1 -0
  153. package/dist/detectors/ssh-ca.js +119 -0
  154. package/dist/detectors/ssh-ca.js.map +1 -0
  155. package/dist/detectors/stateful-hbs.d.ts.map +1 -1
  156. package/dist/detectors/stateful-hbs.js +9 -6
  157. package/dist/detectors/stateful-hbs.js.map +1 -1
  158. package/dist/detectors/supply-chain.d.ts +17 -0
  159. package/dist/detectors/supply-chain.d.ts.map +1 -0
  160. package/dist/detectors/supply-chain.js +89 -0
  161. package/dist/detectors/supply-chain.js.map +1 -0
  162. package/dist/detectors/swift.d.ts +22 -0
  163. package/dist/detectors/swift.d.ts.map +1 -0
  164. package/dist/detectors/swift.js +120 -0
  165. package/dist/detectors/swift.js.map +1 -0
  166. package/dist/detectors/terraform.d.ts +21 -0
  167. package/dist/detectors/terraform.d.ts.map +1 -0
  168. package/dist/detectors/terraform.js +150 -0
  169. package/dist/detectors/terraform.js.map +1 -0
  170. package/dist/detectors/vault.d.ts +15 -0
  171. package/dist/detectors/vault.d.ts.map +1 -0
  172. package/dist/detectors/vault.js +97 -0
  173. package/dist/detectors/vault.js.map +1 -0
  174. package/dist/detectors/vpn.d.ts +22 -0
  175. package/dist/detectors/vpn.d.ts.map +1 -0
  176. package/dist/detectors/vpn.js +73 -0
  177. package/dist/detectors/vpn.js.map +1 -0
  178. package/dist/detectors/weak-hash.d.ts +71 -0
  179. package/dist/detectors/weak-hash.d.ts.map +1 -0
  180. package/dist/detectors/weak-hash.js +116 -0
  181. package/dist/detectors/weak-hash.js.map +1 -0
  182. package/dist/detectors/webauthn.d.ts +61 -0
  183. package/dist/detectors/webauthn.d.ts.map +1 -0
  184. package/dist/detectors/webauthn.js +109 -0
  185. package/dist/detectors/webauthn.js.map +1 -0
  186. package/dist/detectors/xmldsig.d.ts +23 -0
  187. package/dist/detectors/xmldsig.d.ts.map +1 -0
  188. package/dist/detectors/xmldsig.js +84 -0
  189. package/dist/detectors/xmldsig.js.map +1 -0
  190. package/dist/evidence.d.ts +79 -4
  191. package/dist/evidence.d.ts.map +1 -1
  192. package/dist/evidence.js +76 -0
  193. package/dist/evidence.js.map +1 -1
  194. package/dist/index.d.ts +17 -9
  195. package/dist/index.d.ts.map +1 -1
  196. package/dist/index.js +21 -9
  197. package/dist/index.js.map +1 -1
  198. package/dist/inventory.d.ts +0 -2
  199. package/dist/inventory.d.ts.map +1 -1
  200. package/dist/inventory.js +15 -6
  201. package/dist/inventory.js.map +1 -1
  202. package/dist/policy.d.ts +67 -0
  203. package/dist/policy.d.ts.map +1 -0
  204. package/dist/policy.js +115 -0
  205. package/dist/policy.js.map +1 -0
  206. package/dist/registry.d.ts +9 -4
  207. package/dist/registry.d.ts.map +1 -1
  208. package/dist/registry.js +81 -4
  209. package/dist/registry.js.map +1 -1
  210. package/dist/remediate-pipeline.d.ts +0 -3
  211. package/dist/remediate-pipeline.d.ts.map +1 -1
  212. package/dist/remediate-pipeline.js +23 -2
  213. package/dist/remediate-pipeline.js.map +1 -1
  214. package/dist/remediation.d.ts +10 -0
  215. package/dist/remediation.d.ts.map +1 -1
  216. package/dist/remediation.js +32 -0
  217. package/dist/remediation.js.map +1 -1
  218. package/dist/report.d.ts +9 -0
  219. package/dist/report.d.ts.map +1 -1
  220. package/dist/report.js +38 -1
  221. package/dist/report.js.map +1 -1
  222. package/dist/scan-worker.js +5 -3
  223. package/dist/scan-worker.js.map +1 -1
  224. package/dist/scan.d.ts.map +1 -1
  225. package/dist/scan.js +35 -6
  226. package/dist/scan.js.map +1 -1
  227. package/dist/standards-profiles.d.ts +58 -0
  228. package/dist/standards-profiles.d.ts.map +1 -0
  229. package/dist/standards-profiles.js +100 -0
  230. package/dist/standards-profiles.js.map +1 -0
  231. package/dist/standards.d.ts +96 -0
  232. package/dist/standards.d.ts.map +1 -0
  233. package/dist/standards.js +107 -0
  234. package/dist/standards.js.map +1 -0
  235. package/dist/types.d.ts +6 -5
  236. package/dist/types.d.ts.map +1 -1
  237. package/dist/types.js.map +1 -1
  238. package/dist/version.d.ts +1 -1
  239. package/dist/version.js +1 -1
  240. package/dist/version.js.map +1 -1
  241. package/dist/vex.d.ts +39 -0
  242. package/dist/vex.d.ts.map +1 -0
  243. package/dist/vex.js +87 -0
  244. package/dist/vex.js.map +1 -0
  245. package/dist/walk.d.ts +8 -3
  246. package/dist/walk.d.ts.map +1 -1
  247. package/dist/walk.js +32 -1
  248. package/dist/walk.js.map +1 -1
  249. package/package.json +1 -1
  250. package/src/cbom-merge.ts +146 -0
  251. package/src/cbom.ts +153 -39
  252. package/src/comments.ts +84 -39
  253. package/src/dependencies.ts +2 -1
  254. package/src/detect-utils.ts +146 -12
  255. package/src/detectors/age.ts +60 -0
  256. package/src/detectors/ansible.ts +140 -0
  257. package/src/detectors/bicep.ts +107 -0
  258. package/src/detectors/c.ts +240 -6
  259. package/src/detectors/cicd.ts +171 -0
  260. package/src/detectors/cloud-kms.ts +141 -0
  261. package/src/detectors/cloudformation.ts +250 -0
  262. package/src/detectors/codesign.ts +214 -0
  263. package/src/detectors/csharp.ts +13 -3
  264. package/src/detectors/dart.ts +237 -0
  265. package/src/detectors/database.ts +141 -0
  266. package/src/detectors/dkim.ts +172 -0
  267. package/src/detectors/dnssec.ts +195 -0
  268. package/src/detectors/elixir.ts +268 -0
  269. package/src/detectors/java.ts +39 -4
  270. package/src/detectors/jose.ts +110 -0
  271. package/src/detectors/jwk.ts +170 -0
  272. package/src/detectors/k8s.ts +115 -0
  273. package/src/detectors/keystore.ts +109 -0
  274. package/src/detectors/mesh.ts +130 -0
  275. package/src/detectors/messaging.ts +106 -0
  276. package/src/detectors/objc.ts +209 -0
  277. package/src/detectors/openpgp.ts +194 -0
  278. package/src/detectors/pem.ts +31 -1
  279. package/src/detectors/php.ts +230 -0
  280. package/src/detectors/pkcs11.ts +113 -0
  281. package/src/detectors/proxy.ts +236 -0
  282. package/src/detectors/pulumi.ts +106 -0
  283. package/src/detectors/python.ts +71 -0
  284. package/src/detectors/rust.ts +76 -0
  285. package/src/detectors/secrets.ts +103 -0
  286. package/src/detectors/solidity.ts +176 -0
  287. package/src/detectors/source.ts +283 -73
  288. package/src/detectors/spire.ts +143 -0
  289. package/src/detectors/ssh-ca.ts +215 -0
  290. package/src/detectors/stateful-hbs.ts +9 -6
  291. package/src/detectors/supply-chain.ts +117 -0
  292. package/src/detectors/swift.ts +149 -0
  293. package/src/detectors/terraform.ts +188 -0
  294. package/src/detectors/vault.ts +120 -0
  295. package/src/detectors/vpn.ts +103 -0
  296. package/src/detectors/weak-hash.ts +217 -0
  297. package/src/detectors/webauthn.ts +205 -0
  298. package/src/detectors/xmldsig.ts +115 -0
  299. package/src/evidence.ts +138 -4
  300. package/src/index.ts +50 -12
  301. package/src/inventory.ts +15 -7
  302. package/src/policy.ts +180 -0
  303. package/src/registry.ts +81 -4
  304. package/src/remediate-pipeline.ts +26 -3
  305. package/src/remediation.ts +39 -0
  306. package/src/report.ts +43 -1
  307. package/src/scan-worker.ts +5 -3
  308. package/src/scan.ts +41 -6
  309. package/src/standards-profiles.ts +136 -0
  310. package/src/standards.ts +186 -0
  311. package/src/types.ts +11 -4
  312. package/src/version.ts +1 -1
  313. package/src/vex.ts +122 -0
  314. package/src/walk.ts +33 -2
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Config detector: classical key material in JSON Web Keys (JWK / JWKS, RFC 7517
3
+ * / 7518). JWKs appear in `.json` / `.jwks` files, OIDC discovery documents, and
4
+ * config — a real key-material surface the source packs (which look at *code*)
5
+ * and the PEM detector (which looks at PEM markers) both miss.
6
+ *
7
+ * Detection keys off the JWK's distinctive JSON fields:
8
+ * - `"kty":"RSA"` → classical RSA key.
9
+ * - `"crv":"P-256"|"P-384"|"P-521"|…` → classical EC key (ECDSA + ECDH).
10
+ * - `"crv":"Ed25519"|"Ed448"` → EdDSA signing key.
11
+ * - `"crv":"X25519"|"X448"` → classical Montgomery-curve key agreement.
12
+ *
13
+ * Usage-aware classification: when a key's surrounding `"use"` / `"alg"` marks it
14
+ * as a SIGNING key (`use:"sig"`, or an `RS`/`PS`/`ES` signature alg), the finding
15
+ * is a `signature` (`hndl:false`) — a signing key is forgeable at a CRQC but not
16
+ * harvest-now exposed. An encryption/unspecified key stays `hndl:true`.
17
+ *
18
+ * Deferrals to avoid double-counting: skipped on doc extensions (a README JWK
19
+ * example is not live) and inside CloudFormation/ARM templates, where the
20
+ * cloudformation detector owns the `kty` of a `Microsoft.KeyVault` key resource.
21
+ */
22
+ import type { Detector } from "../types.js";
23
+ /** Detects classical JSON Web Key (JWK/JWKS) material in any JSON/text file. */
24
+ export declare const jwkDetector: Detector;
25
+ //# sourceMappingURL=jwk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwk.d.ts","sourceRoot":"","sources":["../../src/detectors/jwk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAqG/D,gFAAgF;AAChF,eAAO,MAAM,WAAW,EAAE,QA8CzB,CAAC"}
@@ -0,0 +1,131 @@
1
+ import { DOC_EXTENSIONS, eachMatch, enclosingObject, findingFromRule, hasExtension, } from "../detect-utils.js";
2
+ import { isCloudTemplateFile } from "./cloudformation.js";
3
+ import { CWE_BROKEN_CRYPTO } from "../cwe.js";
4
+ const JWK_RULES = [
5
+ {
6
+ re: /"kty"\s*:\s*"RSA"/g,
7
+ meta: {
8
+ id: "jwk-rsa",
9
+ title: "RSA JSON Web Key (JWK)",
10
+ description: 'JWK with "kty":"RSA" (RFC 7518)',
11
+ category: "certificate",
12
+ severity: "medium",
13
+ confidence: "high",
14
+ algorithm: "RSA",
15
+ hndl: true,
16
+ cwe: CWE_BROKEN_CRYPTO,
17
+ message: "RSA JSON Web Key (JWK); classical RSA, not quantum-safe.",
18
+ remediation: "Re-issue with PQC keys (ML-KEM-768 for encryption, ML-DSA-65 for signatures).",
19
+ },
20
+ },
21
+ {
22
+ re: /"crv"\s*:\s*"(?:P-256K?|P-384|P-521|secp256k1)"/g,
23
+ meta: {
24
+ id: "jwk-ec",
25
+ title: "EC JSON Web Key (JWK)",
26
+ description: 'JWK with an "crv" naming a NIST/secp curve (RFC 7518)',
27
+ category: "key-exchange",
28
+ severity: "medium",
29
+ confidence: "high",
30
+ algorithm: "ECDH",
31
+ hndl: true,
32
+ cwe: CWE_BROKEN_CRYPTO,
33
+ message: "Elliptic-curve JSON Web Key (JWK); a classical EC key feeds BOTH ECDSA signatures and ECDH key agreement — the ECDH path is harvest-now-decrypt-later exposed.",
34
+ remediation: "For key agreement: hybrid X25519MLKEM768 (ML-KEM-768). For signatures: ML-DSA-65 (FIPS 204).",
35
+ },
36
+ },
37
+ {
38
+ re: /"crv"\s*:\s*"Ed(?:25519|448)"/g,
39
+ meta: {
40
+ id: "jwk-eddsa",
41
+ title: "EdDSA JSON Web Key (JWK)",
42
+ description: 'JWK OKP key with "crv":"Ed25519"/"Ed448" (RFC 8037)',
43
+ category: "signature",
44
+ severity: "low",
45
+ confidence: "high",
46
+ algorithm: "EdDSA",
47
+ hndl: false,
48
+ cwe: CWE_BROKEN_CRYPTO,
49
+ message: "EdDSA (Ed25519/Ed448) JSON Web Key (JWK); classical and forgeable by a quantum attacker.",
50
+ remediation: "ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205).",
51
+ },
52
+ },
53
+ {
54
+ re: /"crv"\s*:\s*"X(?:25519|448)"/g,
55
+ meta: {
56
+ id: "jwk-xdh",
57
+ title: "X25519/X448 JSON Web Key (JWK)",
58
+ description: 'JWK OKP key with "crv":"X25519"/"X448" (RFC 8037)',
59
+ category: "key-exchange",
60
+ severity: "medium",
61
+ confidence: "high",
62
+ algorithm: "X25519",
63
+ hndl: true,
64
+ cwe: CWE_BROKEN_CRYPTO,
65
+ message: "X25519/X448 JSON Web Key (JWK); modern but classical key agreement, and harvest-now-decrypt-later exposed.",
66
+ remediation: "Migrate key agreement to hybrid X25519MLKEM768 (ML-KEM-768).",
67
+ },
68
+ },
69
+ ];
70
+ /**
71
+ * True when THIS key's own object marks it as a signing key via `use`/`alg`. The
72
+ * caller passes the enclosing `{…}` object so a neighbouring key in a JWKS array
73
+ * can't contaminate the result, and an explicit `"use":"enc"` on the key always
74
+ * wins (never classify an encryption key as a signature).
75
+ */
76
+ function isSigningUse(objectText, sigAlg) {
77
+ if (/"use"\s*:\s*"enc"/.test(objectText))
78
+ return false;
79
+ return /"use"\s*:\s*"sig"/.test(objectText) || sigAlg.test(objectText);
80
+ }
81
+ const RSA_SIG_ALG = /"alg"\s*:\s*"(?:RS|PS)(?:256|384|512)"/;
82
+ const EC_SIG_ALG = /"alg"\s*:\s*"ES(?:256K?|384|512)"/;
83
+ /** Detects classical JSON Web Key (JWK/JWKS) material in any JSON/text file. */
84
+ export const jwkDetector = {
85
+ id: "jwk-material",
86
+ description: "Classical key material in JSON Web Keys (JWK / JWKS)",
87
+ scope: "config",
88
+ language: "any",
89
+ rules: JWK_RULES.map((r) => r.meta),
90
+ appliesTo: (f) => !hasExtension(f, DOC_EXTENSIONS),
91
+ detect({ file, content }) {
92
+ // Fast reject: a JWK always has one of these two members.
93
+ if (!content.includes('"kty"') && !content.includes('"crv"'))
94
+ return [];
95
+ // The ONLY overlap with the cloudformation detector is the ARM Key Vault key
96
+ // `kty:"RSA"` (cfn-arm-keyvault-rsa), which only fires when Microsoft.KeyVault is
97
+ // present. Defer just the RSA rule in that case — everything else (crv keys, and
98
+ // JWKs embedded in AWS CloudFormation, which cfn does not own) is still reported.
99
+ const isArm = isCloudTemplateFile(file, content) && content.includes("Microsoft.KeyVault");
100
+ const findings = [];
101
+ for (const rule of JWK_RULES) {
102
+ eachMatch(rule.re, content, (m) => {
103
+ if (rule.meta.id === "jwk-rsa" && isArm)
104
+ return; // cfn-arm-keyvault-rsa owns it
105
+ const at = { file, content, index: m.index, matchLength: m[0].length };
106
+ // Analyse the key's OWN enclosing object so a neighbouring key in a JWKS
107
+ // array can't flip this key's sig/enc classification.
108
+ const obj = enclosingObject(content, m.index);
109
+ let overrides;
110
+ if (rule.meta.id === "jwk-rsa" && isSigningUse(obj, RSA_SIG_ALG)) {
111
+ overrides = {
112
+ category: "signature",
113
+ hndl: false,
114
+ message: "RSA JSON Web Key (JWK) used for signing (RS*/PS*); forgeable by a quantum attacker.",
115
+ };
116
+ }
117
+ else if (rule.meta.id === "jwk-ec" && isSigningUse(obj, EC_SIG_ALG)) {
118
+ overrides = {
119
+ category: "signature",
120
+ algorithm: "ECDSA",
121
+ hndl: false,
122
+ message: "Elliptic-curve JSON Web Key (JWK) used for ECDSA signing; forgeable by a quantum attacker.",
123
+ };
124
+ }
125
+ findings.push(findingFromRule(rule.meta, at, overrides));
126
+ });
127
+ }
128
+ return findings;
129
+ },
130
+ };
131
+ //# sourceMappingURL=jwk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwk.js","sourceRoot":"","sources":["../../src/detectors/jwk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Config detector: classical key material in JSON Web Keys (JWK / JWKS, RFC 7517\n * / 7518). JWKs appear in `.json` / `.jwks` files, OIDC discovery documents, and\n * config — a real key-material surface the source packs (which look at *code*)\n * and the PEM detector (which looks at PEM markers) both miss.\n *\n * Detection keys off the JWK's distinctive JSON fields:\n * - `\"kty\":\"RSA\"` → classical RSA key.\n * - `\"crv\":\"P-256\"|\"P-384\"|\"P-521\"|…` → classical EC key (ECDSA + ECDH).\n * - `\"crv\":\"Ed25519\"|\"Ed448\"` → EdDSA signing key.\n * - `\"crv\":\"X25519\"|\"X448\"` → classical Montgomery-curve key agreement.\n *\n * Usage-aware classification: when a key's surrounding `\"use\"` / `\"alg\"` marks it\n * as a SIGNING key (`use:\"sig\"`, or an `RS`/`PS`/`ES` signature alg), the finding\n * is a `signature` (`hndl:false`) — a signing key is forgeable at a CRQC but not\n * harvest-now exposed. An encryption/unspecified key stays `hndl:true`.\n *\n * Deferrals to avoid double-counting: skipped on doc extensions (a README JWK\n * example is not live) and inside CloudFormation/ARM templates, where the\n * cloudformation detector owns the `kty` of a `Microsoft.KeyVault` key resource.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport {\n DOC_EXTENSIONS,\n eachMatch,\n enclosingObject,\n findingFromRule,\n hasExtension,\n} from \"../detect-utils.js\";\nimport { isCloudTemplateFile } from \"./cloudformation.js\";\nimport { CWE_BROKEN_CRYPTO } from \"../cwe.js\";\n\ninterface JwkRule {\n re: RegExp;\n meta: RuleMeta;\n}\n\nconst JWK_RULES: JwkRule[] = [\n {\n re: /\"kty\"\\s*:\\s*\"RSA\"/g,\n meta: {\n id: \"jwk-rsa\",\n title: \"RSA JSON Web Key (JWK)\",\n description: 'JWK with \"kty\":\"RSA\" (RFC 7518)',\n category: \"certificate\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"RSA JSON Web Key (JWK); classical RSA, not quantum-safe.\",\n remediation: \"Re-issue with PQC keys (ML-KEM-768 for encryption, ML-DSA-65 for signatures).\",\n },\n },\n {\n re: /\"crv\"\\s*:\\s*\"(?:P-256K?|P-384|P-521|secp256k1)\"/g,\n meta: {\n id: \"jwk-ec\",\n title: \"EC JSON Web Key (JWK)\",\n description: 'JWK with an \"crv\" naming a NIST/secp curve (RFC 7518)',\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Elliptic-curve JSON Web Key (JWK); a classical EC key feeds BOTH ECDSA signatures 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 },\n {\n re: /\"crv\"\\s*:\\s*\"Ed(?:25519|448)\"/g,\n meta: {\n id: \"jwk-eddsa\",\n title: \"EdDSA JSON Web Key (JWK)\",\n description: 'JWK OKP key with \"crv\":\"Ed25519\"/\"Ed448\" (RFC 8037)',\n category: \"signature\",\n severity: \"low\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"EdDSA (Ed25519/Ed448) JSON Web Key (JWK); classical and forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205).\",\n },\n },\n {\n re: /\"crv\"\\s*:\\s*\"X(?:25519|448)\"/g,\n meta: {\n id: \"jwk-xdh\",\n title: \"X25519/X448 JSON Web Key (JWK)\",\n description: 'JWK OKP key with \"crv\":\"X25519\"/\"X448\" (RFC 8037)',\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"X25519\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"X25519/X448 JSON Web Key (JWK); modern but classical key agreement, and harvest-now-decrypt-later exposed.\",\n remediation: \"Migrate key agreement to hybrid X25519MLKEM768 (ML-KEM-768).\",\n },\n },\n];\n\n/**\n * True when THIS key's own object marks it as a signing key via `use`/`alg`. The\n * caller passes the enclosing `{…}` object so a neighbouring key in a JWKS array\n * can't contaminate the result, and an explicit `\"use\":\"enc\"` on the key always\n * wins (never classify an encryption key as a signature).\n */\nfunction isSigningUse(objectText: string, sigAlg: RegExp): boolean {\n if (/\"use\"\\s*:\\s*\"enc\"/.test(objectText)) return false;\n return /\"use\"\\s*:\\s*\"sig\"/.test(objectText) || sigAlg.test(objectText);\n}\n\nconst RSA_SIG_ALG = /\"alg\"\\s*:\\s*\"(?:RS|PS)(?:256|384|512)\"/;\nconst EC_SIG_ALG = /\"alg\"\\s*:\\s*\"ES(?:256K?|384|512)\"/;\n\n/** Detects classical JSON Web Key (JWK/JWKS) material in any JSON/text file. */\nexport const jwkDetector: Detector = {\n id: \"jwk-material\",\n description: \"Classical key material in JSON Web Keys (JWK / JWKS)\",\n scope: \"config\",\n language: \"any\",\n rules: JWK_RULES.map((r) => r.meta),\n appliesTo: (f) => !hasExtension(f, DOC_EXTENSIONS),\n detect({ file, content }): Finding[] {\n // Fast reject: a JWK always has one of these two members.\n if (!content.includes('\"kty\"') && !content.includes('\"crv\"')) return [];\n // The ONLY overlap with the cloudformation detector is the ARM Key Vault key\n // `kty:\"RSA\"` (cfn-arm-keyvault-rsa), which only fires when Microsoft.KeyVault is\n // present. Defer just the RSA rule in that case — everything else (crv keys, and\n // JWKs embedded in AWS CloudFormation, which cfn does not own) is still reported.\n const isArm = isCloudTemplateFile(file, content) && content.includes(\"Microsoft.KeyVault\");\n\n const findings: Finding[] = [];\n for (const rule of JWK_RULES) {\n eachMatch(rule.re, content, (m) => {\n if (rule.meta.id === \"jwk-rsa\" && isArm) return; // cfn-arm-keyvault-rsa owns it\n const at = { file, content, index: m.index, matchLength: m[0].length };\n // Analyse the key's OWN enclosing object so a neighbouring key in a JWKS\n // array can't flip this key's sig/enc classification.\n const obj = enclosingObject(content, m.index);\n let overrides;\n if (rule.meta.id === \"jwk-rsa\" && isSigningUse(obj, RSA_SIG_ALG)) {\n overrides = {\n category: \"signature\" as const,\n hndl: false,\n message:\n \"RSA JSON Web Key (JWK) used for signing (RS*/PS*); forgeable by a quantum attacker.\",\n };\n } else if (rule.meta.id === \"jwk-ec\" && isSigningUse(obj, EC_SIG_ALG)) {\n overrides = {\n category: \"signature\" as const,\n algorithm: \"ECDSA\" as const,\n hndl: false,\n message:\n \"Elliptic-curve JSON Web Key (JWK) used for ECDSA signing; forgeable by a quantum attacker.\",\n };\n }\n findings.push(findingFromRule(rule.meta, at, overrides));\n });\n }\n return findings;\n },\n};\n"]}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Config detector: classical crypto in Kubernetes manifests — cert-manager key
3
+ * algorithms and service-mesh (Istio) TLS floors. These mint the certificates
4
+ * and secure the pod-to-pod traffic of a cluster, a surface neither the language
5
+ * packs nor the Terraform detector see.
6
+ *
7
+ * Covered (gated by a cert-manager / Istio marker in the document to keep the
8
+ * generic `algorithm:` / `minProtocolVersion:` keys from firing on unrelated YAML):
9
+ * - cert-manager `Certificate`/`Issuer` `privateKey.algorithm` (or legacy
10
+ * `keyAlgorithm`): `RSA` | `ECDSA` | `Ed25519`.
11
+ * - Istio `minProtocolVersion: TLSV1_0 | TLSV1_1` — a legacy TLS floor on mesh
12
+ * traffic, whose (EC)DHE key exchange is classical and harvestable.
13
+ */
14
+ import type { Detector } from "../types.js";
15
+ /** Detects classical cert-manager keys and legacy Istio TLS floors in K8s YAML. */
16
+ export declare const k8sDetector: Detector;
17
+ //# sourceMappingURL=k8s.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"k8s.d.ts","sourceRoot":"","sources":["../../src/detectors/k8s.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAoE/D,mFAAmF;AACnF,eAAO,MAAM,WAAW,EAAE,QAgCzB,CAAC"}
@@ -0,0 +1,88 @@
1
+ import { eachMatch, findingFromRule, hasExtension, maskCommentLines } from "../detect-utils.js";
2
+ import { CWE_BROKEN_CRYPTO, CWE_RISKY_PRIMITIVE } from "../cwe.js";
3
+ const K8S_EXTENSIONS = [".yaml", ".yml", ".json"];
4
+ const RE_CM_RSA = /(?:algorithm|keyAlgorithm):\s*["']?RSA\b/g;
5
+ const RE_CM_ECDSA = /(?:algorithm|keyAlgorithm):\s*["']?ECDSA\b/g;
6
+ const RE_CM_ED25519 = /(?:algorithm|keyAlgorithm):\s*["']?Ed25519\b/g;
7
+ const RE_ISTIO_LEGACY_TLS = /minProtocolVersion:\s*["']?TLSV1_[01]\b/g;
8
+ const RULE_CM_RSA = {
9
+ id: "k8s-certmanager-rsa",
10
+ title: "cert-manager RSA key",
11
+ description: "cert-manager Certificate/Issuer privateKey.algorithm = RSA",
12
+ category: "certificate",
13
+ severity: "medium",
14
+ confidence: "high",
15
+ algorithm: "RSA",
16
+ hndl: true,
17
+ cwe: CWE_BROKEN_CRYPTO,
18
+ message: "cert-manager mints certificates with a classical RSA key, which is not quantum-safe.",
19
+ remediation: "Plan migration to PQC certificate keys (ML-DSA-65) as the CA/issuer chain adds support.",
20
+ };
21
+ const RULE_CM_ECDSA = {
22
+ id: "k8s-certmanager-ecdsa",
23
+ title: "cert-manager ECDSA key",
24
+ description: "cert-manager Certificate/Issuer privateKey.algorithm = ECDSA",
25
+ category: "certificate",
26
+ severity: "medium",
27
+ confidence: "high",
28
+ algorithm: "ECDSA",
29
+ hndl: false,
30
+ cwe: CWE_BROKEN_CRYPTO,
31
+ message: "cert-manager mints certificates with a classical ECDSA key, forgeable by a quantum attacker.",
32
+ remediation: "Plan migration to ML-DSA-65 (FIPS 204) certificate keys.",
33
+ };
34
+ const RULE_CM_ED25519 = {
35
+ id: "k8s-certmanager-ed25519",
36
+ title: "cert-manager Ed25519 key",
37
+ description: "cert-manager Certificate/Issuer privateKey.algorithm = Ed25519",
38
+ category: "certificate",
39
+ severity: "low",
40
+ confidence: "high",
41
+ algorithm: "EdDSA",
42
+ hndl: false,
43
+ cwe: CWE_BROKEN_CRYPTO,
44
+ message: "cert-manager mints certificates with a classical Ed25519 key, forgeable by a quantum attacker.",
45
+ remediation: "Plan migration to ML-DSA-65 (FIPS 204) certificate keys.",
46
+ };
47
+ const RULE_ISTIO_LEGACY_TLS = {
48
+ id: "k8s-istio-legacy-tls",
49
+ title: "Istio legacy TLS floor",
50
+ description: "Istio minProtocolVersion allows TLS 1.0 / 1.1 on mesh traffic",
51
+ category: "tls",
52
+ severity: "medium",
53
+ confidence: "high",
54
+ hndl: false,
55
+ cwe: CWE_RISKY_PRIMITIVE,
56
+ message: "Istio mesh TLS floor allows TLS 1.0/1.1; its classical (EC)DHE key exchange is weak and harvestable.",
57
+ remediation: "Raise minProtocolVersion to TLSV1_3 and track PQC-hybrid mesh KEX (X25519MLKEM768).",
58
+ };
59
+ /** Detects classical cert-manager keys and legacy Istio TLS floors in K8s YAML. */
60
+ export const k8sDetector = {
61
+ id: "k8s-crypto",
62
+ description: "Classical crypto in Kubernetes manifests (cert-manager keys, Istio TLS floors)",
63
+ scope: "config",
64
+ language: "any",
65
+ rules: [RULE_CM_RSA, RULE_CM_ECDSA, RULE_CM_ED25519, RULE_ISTIO_LEGACY_TLS],
66
+ appliesTo: (f) => hasExtension(f, K8S_EXTENSIONS),
67
+ detect({ file, content }) {
68
+ const isCertManager = content.includes("cert-manager.io") ||
69
+ /kind:\s*["']?(?:Certificate|Issuer|ClusterIssuer)\b/.test(content);
70
+ const isIstio = content.includes("minProtocolVersion");
71
+ if (!isCertManager && !isIstio)
72
+ return [];
73
+ // A `# algorithm: RSA` YAML comment is not an active setting; match over
74
+ // comment-masked content (offsets preserved).
75
+ const scan = maskCommentLines(content, ["#"]);
76
+ const findings = [];
77
+ const add = (re, rule) => eachMatch(re, scan, (m) => findings.push(findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length })));
78
+ if (isCertManager) {
79
+ add(RE_CM_RSA, RULE_CM_RSA);
80
+ add(RE_CM_ECDSA, RULE_CM_ECDSA);
81
+ add(RE_CM_ED25519, RULE_CM_ED25519);
82
+ }
83
+ if (isIstio)
84
+ add(RE_ISTIO_LEGACY_TLS, RULE_ISTIO_LEGACY_TLS);
85
+ return findings;
86
+ },
87
+ };
88
+ //# sourceMappingURL=k8s.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"k8s.js","sourceRoot":"","sources":["../../src/detectors/k8s.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAChG,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEnE,MAAM,cAAc,GAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAErE,MAAM,SAAS,GAAG,2CAA2C,CAAC;AAC9D,MAAM,WAAW,GAAG,6CAA6C,CAAC;AAClE,MAAM,aAAa,GAAG,+CAA+C,CAAC;AACtE,MAAM,mBAAmB,GAAG,0CAA0C,CAAC;AAEvE,MAAM,WAAW,GAAa;IAC5B,EAAE,EAAE,qBAAqB;IACzB,KAAK,EAAE,sBAAsB;IAC7B,WAAW,EAAE,4DAA4D;IACzE,QAAQ,EAAE,aAAa;IACvB,QAAQ,EAAE,QAAQ;IAClB,UAAU,EAAE,MAAM;IAClB,SAAS,EAAE,KAAK;IAChB,IAAI,EAAE,IAAI;IACV,GAAG,EAAE,iBAAiB;IACtB,OAAO,EAAE,sFAAsF;IAC/F,WAAW,EACT,yFAAyF;CAC5F,CAAC;AACF,MAAM,aAAa,GAAa;IAC9B,EAAE,EAAE,uBAAuB;IAC3B,KAAK,EAAE,wBAAwB;IAC/B,WAAW,EAAE,8DAA8D;IAC3E,QAAQ,EAAE,aAAa;IACvB,QAAQ,EAAE,QAAQ;IAClB,UAAU,EAAE,MAAM;IAClB,SAAS,EAAE,OAAO;IAClB,IAAI,EAAE,KAAK;IACX,GAAG,EAAE,iBAAiB;IACtB,OAAO,EACL,8FAA8F;IAChG,WAAW,EAAE,0DAA0D;CACxE,CAAC;AACF,MAAM,eAAe,GAAa;IAChC,EAAE,EAAE,yBAAyB;IAC7B,KAAK,EAAE,0BAA0B;IACjC,WAAW,EAAE,gEAAgE;IAC7E,QAAQ,EAAE,aAAa;IACvB,QAAQ,EAAE,KAAK;IACf,UAAU,EAAE,MAAM;IAClB,SAAS,EAAE,OAAO;IAClB,IAAI,EAAE,KAAK;IACX,GAAG,EAAE,iBAAiB;IACtB,OAAO,EACL,gGAAgG;IAClG,WAAW,EAAE,0DAA0D;CACxE,CAAC;AACF,MAAM,qBAAqB,GAAa;IACtC,EAAE,EAAE,sBAAsB;IAC1B,KAAK,EAAE,wBAAwB;IAC/B,WAAW,EAAE,+DAA+D;IAC5E,QAAQ,EAAE,KAAK;IACf,QAAQ,EAAE,QAAQ;IAClB,UAAU,EAAE,MAAM;IAClB,IAAI,EAAE,KAAK;IACX,GAAG,EAAE,mBAAmB;IACxB,OAAO,EACL,sGAAsG;IACxG,WAAW,EACT,qFAAqF;CACxF,CAAC;AAEF,mFAAmF;AACnF,MAAM,CAAC,MAAM,WAAW,GAAa;IACnC,EAAE,EAAE,YAAY;IAChB,WAAW,EAAE,gFAAgF;IAC7F,KAAK,EAAE,QAAQ;IACf,QAAQ,EAAE,KAAK;IACf,KAAK,EAAE,CAAC,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,qBAAqB,CAAC;IAC3E,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,cAAc,CAAC;IACjD,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE;QACtB,MAAM,aAAa,GACjB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YACnC,qDAAqD,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtE,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;QACvD,IAAI,CAAC,aAAa,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,CAAC;QAE1C,yEAAyE;QACzE,8CAA8C;QAC9C,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,CAAC,EAAU,EAAE,IAAc,EAAE,EAAE,CACzC,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CACxB,QAAQ,CAAC,IAAI,CACX,eAAe,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CACnF,CACF,CAAC;QACJ,IAAI,aAAa,EAAE,CAAC;YAClB,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;YAC5B,GAAG,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;YAChC,GAAG,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;QACtC,CAAC;QACD,IAAI,OAAO;YAAE,GAAG,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,CAAC;QAC7D,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC","sourcesContent":["/**\n * Config detector: classical crypto in Kubernetes manifests — cert-manager key\n * algorithms and service-mesh (Istio) TLS floors. These mint the certificates\n * and secure the pod-to-pod traffic of a cluster, a surface neither the language\n * packs nor the Terraform detector see.\n *\n * Covered (gated by a cert-manager / Istio marker in the document to keep the\n * generic `algorithm:` / `minProtocolVersion:` keys from firing on unrelated YAML):\n * - cert-manager `Certificate`/`Issuer` `privateKey.algorithm` (or legacy\n * `keyAlgorithm`): `RSA` | `ECDSA` | `Ed25519`.\n * - Istio `minProtocolVersion: TLSV1_0 | TLSV1_1` — a legacy TLS floor on mesh\n * traffic, whose (EC)DHE key exchange is classical and harvestable.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport { eachMatch, findingFromRule, hasExtension, maskCommentLines } from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO, CWE_RISKY_PRIMITIVE } from \"../cwe.js\";\n\nconst K8S_EXTENSIONS: readonly string[] = [\".yaml\", \".yml\", \".json\"];\n\nconst RE_CM_RSA = /(?:algorithm|keyAlgorithm):\\s*[\"']?RSA\\b/g;\nconst RE_CM_ECDSA = /(?:algorithm|keyAlgorithm):\\s*[\"']?ECDSA\\b/g;\nconst RE_CM_ED25519 = /(?:algorithm|keyAlgorithm):\\s*[\"']?Ed25519\\b/g;\nconst RE_ISTIO_LEGACY_TLS = /minProtocolVersion:\\s*[\"']?TLSV1_[01]\\b/g;\n\nconst RULE_CM_RSA: RuleMeta = {\n id: \"k8s-certmanager-rsa\",\n title: \"cert-manager RSA key\",\n description: \"cert-manager Certificate/Issuer privateKey.algorithm = RSA\",\n category: \"certificate\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"cert-manager mints certificates with a classical RSA key, which is not quantum-safe.\",\n remediation:\n \"Plan migration to PQC certificate keys (ML-DSA-65) as the CA/issuer chain adds support.\",\n};\nconst RULE_CM_ECDSA: RuleMeta = {\n id: \"k8s-certmanager-ecdsa\",\n title: \"cert-manager ECDSA key\",\n description: \"cert-manager Certificate/Issuer privateKey.algorithm = ECDSA\",\n category: \"certificate\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"cert-manager mints certificates with a classical ECDSA key, forgeable by a quantum attacker.\",\n remediation: \"Plan migration to ML-DSA-65 (FIPS 204) certificate keys.\",\n};\nconst RULE_CM_ED25519: RuleMeta = {\n id: \"k8s-certmanager-ed25519\",\n title: \"cert-manager Ed25519 key\",\n description: \"cert-manager Certificate/Issuer privateKey.algorithm = Ed25519\",\n category: \"certificate\",\n severity: \"low\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"cert-manager mints certificates with a classical Ed25519 key, forgeable by a quantum attacker.\",\n remediation: \"Plan migration to ML-DSA-65 (FIPS 204) certificate keys.\",\n};\nconst RULE_ISTIO_LEGACY_TLS: RuleMeta = {\n id: \"k8s-istio-legacy-tls\",\n title: \"Istio legacy TLS floor\",\n description: \"Istio minProtocolVersion allows TLS 1.0 / 1.1 on mesh traffic\",\n category: \"tls\",\n severity: \"medium\",\n confidence: \"high\",\n hndl: false,\n cwe: CWE_RISKY_PRIMITIVE,\n message:\n \"Istio mesh TLS floor allows TLS 1.0/1.1; its classical (EC)DHE key exchange is weak and harvestable.\",\n remediation:\n \"Raise minProtocolVersion to TLSV1_3 and track PQC-hybrid mesh KEX (X25519MLKEM768).\",\n};\n\n/** Detects classical cert-manager keys and legacy Istio TLS floors in K8s YAML. */\nexport const k8sDetector: Detector = {\n id: \"k8s-crypto\",\n description: \"Classical crypto in Kubernetes manifests (cert-manager keys, Istio TLS floors)\",\n scope: \"config\",\n language: \"any\",\n rules: [RULE_CM_RSA, RULE_CM_ECDSA, RULE_CM_ED25519, RULE_ISTIO_LEGACY_TLS],\n appliesTo: (f) => hasExtension(f, K8S_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const isCertManager =\n content.includes(\"cert-manager.io\") ||\n /kind:\\s*[\"']?(?:Certificate|Issuer|ClusterIssuer)\\b/.test(content);\n const isIstio = content.includes(\"minProtocolVersion\");\n if (!isCertManager && !isIstio) return [];\n\n // A `# algorithm: RSA` YAML comment is not an active setting; match over\n // comment-masked content (offsets preserved).\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 if (isCertManager) {\n add(RE_CM_RSA, RULE_CM_RSA);\n add(RE_CM_ECDSA, RULE_CM_ECDSA);\n add(RE_CM_ED25519, RULE_CM_ED25519);\n }\n if (isIstio) add(RE_ISTIO_LEGACY_TLS, RULE_ISTIO_LEGACY_TLS);\n return findings;\n },\n};\n"]}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Config detector: classical cryptographic KEYSTORES committed to a repository —
3
+ * Java KeyStore (JKS), JCEKS, PKCS#12 (.p12/.pfx), and BouncyCastle (.bks). These
4
+ * binary containers hold private keys and certificate chains, essentially always
5
+ * classical (RSA / EC / DSA). A keystore in version control is committed key
6
+ * material: harvest-now-decrypt-later exposed and retroactively un-fixable.
7
+ *
8
+ * The scan pipeline reads these extensions byte-preserving (latin1; see
9
+ * {@link ../walk.ts isKeystorePath} and scan.ts), so `content.charCodeAt(i)` is the
10
+ * i-th file byte and we can identify the container by its magic number. We do NOT
11
+ * parse the enclosed key algorithm (that needs full ASN.1 / proprietary parsing);
12
+ * flagging the presence of a classical keystore is the actionable signal.
13
+ *
14
+ * The match is sensitive key material, so reporters drop the (binary) snippet.
15
+ */
16
+ import type { Detector } from "../types.js";
17
+ /** Detects committed classical keystores by magic number / extension. */
18
+ export declare const keystoreDetector: Detector;
19
+ //# sourceMappingURL=keystore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keystore.d.ts","sourceRoot":"","sources":["../../src/detectors/keystore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AA4D/D,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,EAAE,QAgC9B,CAAC"}
@@ -0,0 +1,76 @@
1
+ import { findingFromRule, hasExtension } from "../detect-utils.js";
2
+ import { CWE_HARDCODED_KEY } from "../cwe.js";
3
+ const KEYSTORE_EXTENSIONS = [
4
+ ".jks",
5
+ ".keystore",
6
+ ".jceks",
7
+ ".bks",
8
+ ".p12",
9
+ ".pfx",
10
+ ];
11
+ function baseRule(id, title, message) {
12
+ return {
13
+ id,
14
+ title,
15
+ description: message,
16
+ category: "certificate",
17
+ severity: "high",
18
+ confidence: "high",
19
+ hndl: true,
20
+ cwe: CWE_HARDCODED_KEY,
21
+ sensitive: true,
22
+ message,
23
+ remediation: "Remove key material from version control and rotate it; store keys in a secret manager / HSM. Plan re-issuance with PQC keys (ML-DSA-65 / ML-KEM-768) as tooling supports it.",
24
+ };
25
+ }
26
+ const RULE_JKS = baseRule("keystore-jks", "Java KeyStore (JKS)", "A Java KeyStore (JKS) holds classical private keys / certificates (RSA/EC/DSA); a keystore in version control is committed, harvest-now-decrypt-later exposed key material.");
27
+ const RULE_JCEKS = baseRule("keystore-jceks", "Java JCEKS keystore", "A JCEKS keystore holds classical key material (RSA/EC/DSA); committed to version control it is harvest-now-decrypt-later exposed.");
28
+ const RULE_PKCS12 = baseRule("keystore-pkcs12", "PKCS#12 keystore", "A PKCS#12 container (a `.p12`/`.pfx`, or a modern `.jks`/`.keystore` — keytool writes PKCS#12 by default since Java 9) holds classical private keys / certificate chains (RSA/EC); committed to version control it is harvest-now-decrypt-later exposed.");
29
+ const RULE_BKS = baseRule("keystore-bks", "BouncyCastle keystore (.bks)", "A BouncyCastle (.bks) keystore holds classical key material; committed to version control it is harvest-now-decrypt-later exposed.");
30
+ /** Bytes-equal check against `content` read as latin1 (charCodeAt == file byte). */
31
+ function magic(content, ...bytes) {
32
+ if (content.length < bytes.length)
33
+ return false;
34
+ for (let i = 0; i < bytes.length; i++) {
35
+ if (content.charCodeAt(i) !== bytes[i])
36
+ return false;
37
+ }
38
+ return true;
39
+ }
40
+ /** Detects committed classical keystores by magic number / extension. */
41
+ export const keystoreDetector = {
42
+ id: "keystore-material",
43
+ description: "Committed classical cryptographic keystores (JKS, JCEKS, PKCS#12, BKS)",
44
+ scope: "config",
45
+ language: "any",
46
+ rules: [RULE_JKS, RULE_JCEKS, RULE_PKCS12, RULE_BKS],
47
+ appliesTo: (f) => hasExtension(f, KEYSTORE_EXTENSIONS),
48
+ detect({ file, content }) {
49
+ const at = { file, content, index: 0, matchLength: 4 };
50
+ // JKS: 0xFEEDFEED. JCEKS: 0xCECECECE.
51
+ if (magic(content, 0xfe, 0xed, 0xfe, 0xed))
52
+ return [findingFromRule(RULE_JKS, at)];
53
+ if (magic(content, 0xce, 0xce, 0xce, 0xce))
54
+ return [findingFromRule(RULE_JCEKS, at)];
55
+ // PKCS#12 is a DER SEQUENCE. Since Java 9, `keytool` writes PKCS#12 BY DEFAULT
56
+ // even for files named `.jks`/`.keystore` (and Android release keystores are
57
+ // PKCS#12), so this runs for ANY keystore extension once the JKS/JCEKS magics
58
+ // fail. Accept the long-form length octets 0x81/0x82/0x83 (real PKCS#12 is
59
+ // always >127 bytes, so short-form would be a false positive).
60
+ if (content.length >= 2 && content.charCodeAt(0) === 0x30) {
61
+ const lenOctet = content.charCodeAt(1);
62
+ // Long-form DER length (0x81/0x82/0x83) or BER indefinite length (0x80, emitted
63
+ // by NSS/Firefox .p12 exports). Short-form is excluded (real PKCS#12 is >127 B).
64
+ if (lenOctet === 0x80 || lenOctet === 0x81 || lenOctet === 0x82 || lenOctet === 0x83) {
65
+ return [findingFromRule(RULE_PKCS12, { ...at, matchLength: 2 })];
66
+ }
67
+ }
68
+ // BouncyCastle keystores have no stable magic; key off the extension, but
69
+ // require some content so an empty `.bks` placeholder does not fire.
70
+ if (file.toLowerCase().endsWith(".bks") && content.length > 0) {
71
+ return [findingFromRule(RULE_BKS, { ...at, matchLength: 1 })];
72
+ }
73
+ return [];
74
+ },
75
+ };
76
+ //# sourceMappingURL=keystore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keystore.js","sourceRoot":"","sources":["../../src/detectors/keystore.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Config detector: classical cryptographic KEYSTORES committed to a repository —\n * Java KeyStore (JKS), JCEKS, PKCS#12 (.p12/.pfx), and BouncyCastle (.bks). These\n * binary containers hold private keys and certificate chains, essentially always\n * classical (RSA / EC / DSA). A keystore in version control is committed key\n * material: harvest-now-decrypt-later exposed and retroactively un-fixable.\n *\n * The scan pipeline reads these extensions byte-preserving (latin1; see\n * {@link ../walk.ts isKeystorePath} and scan.ts), so `content.charCodeAt(i)` is the\n * i-th file byte and we can identify the container by its magic number. We do NOT\n * parse the enclosed key algorithm (that needs full ASN.1 / proprietary parsing);\n * flagging the presence of a classical keystore is the actionable signal.\n *\n * The match is sensitive key material, so reporters drop the (binary) snippet.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport { findingFromRule, hasExtension } from \"../detect-utils.js\";\nimport { CWE_HARDCODED_KEY } from \"../cwe.js\";\n\nconst KEYSTORE_EXTENSIONS: readonly string[] = [\n \".jks\",\n \".keystore\",\n \".jceks\",\n \".bks\",\n \".p12\",\n \".pfx\",\n];\n\nfunction baseRule(id: string, title: string, message: string): RuleMeta {\n return {\n id,\n title,\n description: message,\n category: \"certificate\",\n severity: \"high\",\n confidence: \"high\",\n hndl: true,\n cwe: CWE_HARDCODED_KEY,\n sensitive: true,\n message,\n remediation:\n \"Remove key material from version control and rotate it; store keys in a secret manager / HSM. Plan re-issuance with PQC keys (ML-DSA-65 / ML-KEM-768) as tooling supports it.\",\n };\n}\n\nconst RULE_JKS = baseRule(\n \"keystore-jks\",\n \"Java KeyStore (JKS)\",\n \"A Java KeyStore (JKS) holds classical private keys / certificates (RSA/EC/DSA); a keystore in version control is committed, harvest-now-decrypt-later exposed key material.\",\n);\nconst RULE_JCEKS = baseRule(\n \"keystore-jceks\",\n \"Java JCEKS keystore\",\n \"A JCEKS keystore holds classical key material (RSA/EC/DSA); committed to version control it is harvest-now-decrypt-later exposed.\",\n);\nconst RULE_PKCS12 = baseRule(\n \"keystore-pkcs12\",\n \"PKCS#12 keystore\",\n \"A PKCS#12 container (a `.p12`/`.pfx`, or a modern `.jks`/`.keystore` — keytool writes PKCS#12 by default since Java 9) holds classical private keys / certificate chains (RSA/EC); committed to version control it is harvest-now-decrypt-later exposed.\",\n);\nconst RULE_BKS = baseRule(\n \"keystore-bks\",\n \"BouncyCastle keystore (.bks)\",\n \"A BouncyCastle (.bks) keystore holds classical key material; committed to version control it is harvest-now-decrypt-later exposed.\",\n);\n\n/** Bytes-equal check against `content` read as latin1 (charCodeAt == file byte). */\nfunction magic(content: string, ...bytes: number[]): boolean {\n if (content.length < bytes.length) return false;\n for (let i = 0; i < bytes.length; i++) {\n if (content.charCodeAt(i) !== bytes[i]) return false;\n }\n return true;\n}\n\n/** Detects committed classical keystores by magic number / extension. */\nexport const keystoreDetector: Detector = {\n id: \"keystore-material\",\n description: \"Committed classical cryptographic keystores (JKS, JCEKS, PKCS#12, BKS)\",\n scope: \"config\",\n language: \"any\",\n rules: [RULE_JKS, RULE_JCEKS, RULE_PKCS12, RULE_BKS],\n appliesTo: (f) => hasExtension(f, KEYSTORE_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const at = { file, content, index: 0, matchLength: 4 };\n // JKS: 0xFEEDFEED. JCEKS: 0xCECECECE.\n if (magic(content, 0xfe, 0xed, 0xfe, 0xed)) return [findingFromRule(RULE_JKS, at)];\n if (magic(content, 0xce, 0xce, 0xce, 0xce)) return [findingFromRule(RULE_JCEKS, at)];\n // PKCS#12 is a DER SEQUENCE. Since Java 9, `keytool` writes PKCS#12 BY DEFAULT\n // even for files named `.jks`/`.keystore` (and Android release keystores are\n // PKCS#12), so this runs for ANY keystore extension once the JKS/JCEKS magics\n // fail. Accept the long-form length octets 0x81/0x82/0x83 (real PKCS#12 is\n // always >127 bytes, so short-form would be a false positive).\n if (content.length >= 2 && content.charCodeAt(0) === 0x30) {\n const lenOctet = content.charCodeAt(1);\n // Long-form DER length (0x81/0x82/0x83) or BER indefinite length (0x80, emitted\n // by NSS/Firefox .p12 exports). Short-form is excluded (real PKCS#12 is >127 B).\n if (lenOctet === 0x80 || lenOctet === 0x81 || lenOctet === 0x82 || lenOctet === 0x83) {\n return [findingFromRule(RULE_PKCS12, { ...at, matchLength: 2 })];\n }\n }\n // BouncyCastle keystores have no stable magic; key off the extension, but\n // require some content so an empty `.bks` placeholder does not fire.\n if (file.toLowerCase().endsWith(\".bks\") && content.length > 0) {\n return [findingFromRule(RULE_BKS, { ...at, matchLength: 1 })];\n }\n return [];\n },\n};\n"]}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Config detector: classical crypto in SERVICE MESH configuration — the
3
+ * control-plane identity/CA systems and mesh-internal TLS settings of
4
+ * Linkerd, HashiCorp Consul Connect, and Istio. These mint the mTLS identity
5
+ * certificates that secure sidecar-to-sidecar traffic and are configured in
6
+ * their own Helm values / HCL / CRD surfaces, distinct from what `k8s.ts`
7
+ * already covers (cert-manager `Certificate`/`Issuer` keys and Istio's
8
+ * `minProtocolVersion` TLS floor — NOT duplicated here).
9
+ *
10
+ * Covered (gated by a mesh marker in the document to keep generic keys like
11
+ * `scheme:` / `private_key_type` from firing on unrelated YAML/HCL):
12
+ * - Linkerd control-plane identity issuer: Helm values `identityTrustAnchorsPEM`
13
+ * and `identity.issuer.scheme` / nested `issuer.scheme: linkerd.io/tls` — the
14
+ * default self-managed Linkerd identity scheme, which mints workload
15
+ * certificates from an ECDSA P-256 trust anchor. Flagged as a classical mesh
16
+ * CA (certificate, ECDSA, hndl:false) since Linkerd's identity issuer signs
17
+ * forgeable-by-quantum leaf certs, not a confidentiality key.
18
+ * - HashiCorp Consul Connect: the `connect { ca_config { private_key_type =
19
+ * "ec" | "rsa" } } }` mesh CA provider setting (also `ca_provider`). Flagged
20
+ * as a classical mesh CA (certificate; ECDSA for "ec", RSA for "rsa").
21
+ * Istio `tls.cipherSuites:` `ECDHE-RSA-*` / `ECDHE-ECDSA-*` suites are NOT handled
22
+ * here — the language-agnostic `tls-classical-kex` token rule in `source.ts`
23
+ * already flags those cipher strings in any config file, so a rule here would
24
+ * double-count.
25
+ */
26
+ import type { Detector } from "../types.js";
27
+ /**
28
+ * Detects classical asymmetric crypto in service-mesh configuration: Linkerd's
29
+ * default ECDSA identity issuer and Consul Connect's mesh CA private key type.
30
+ * (Istio ECDHE cipher-suite strings are covered by `source.ts`'s
31
+ * `tls-classical-kex` token rule, so they are not duplicated here.)
32
+ */
33
+ export declare const meshDetector: Detector;
34
+ //# sourceMappingURL=mesh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mesh.d.ts","sourceRoot":"","sources":["../../src/detectors/mesh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAoE/D;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,QA8B1B,CAAC"}
@@ -0,0 +1,91 @@
1
+ import { eachMatch, findingFromRule, hasExtension, maskCommentLines } from "../detect-utils.js";
2
+ import { CWE_BROKEN_CRYPTO } from "../cwe.js";
3
+ // `.json` is included because Consul agent config is commonly JSON (the
4
+ // `private_key_type` rules already support the JSON `:` form); the content gates
5
+ // keep unrelated generic JSON/YAML out.
6
+ const MESH_EXTENSIONS = [".yaml", ".yml", ".hcl", ".json"];
7
+ // Linkerd's default self-managed identity scheme (`linkerd.io/tls`, as opposed
8
+ // to a `kubernetes.io/tls` bring-your-own-cert secret) mints its trust anchor
9
+ // and issuer credentials as ECDSA P-256 by default. Matched in both nested
10
+ // YAML form (`scheme: linkerd.io/tls`) and the flattened Helm `--set`/values
11
+ // key form (`identity.issuer.scheme: linkerd.io/tls`), plus the distinctive
12
+ // `identityTrustAnchorsPEM` values key which only exists in Linkerd charts.
13
+ const RE_MESH_LINKERD_ECDSA = /identityTrustAnchorsPEM\b|(?:identity\.issuer\.scheme|scheme)\s*[:=]\s*["']?linkerd\.io\/tls\b/g;
14
+ // Consul Connect's CA provider config: `private_key_type = "ec" | "rsa"`
15
+ // inside a `ca_config` block. Matched in both HCL (`=`) and JSON (`:`) forms,
16
+ // mirroring the terraform.ts attribute-matching convention.
17
+ const RE_MESH_CONSUL_RSA = /(?<![\w"-])"?private_key_type"?\s*[:=]\s*"rsa"/gi;
18
+ const RE_MESH_CONSUL_EC = /(?<![\w"-])"?private_key_type"?\s*[:=]\s*"ec"/gi;
19
+ const RULE_MESH_LINKERD_ECDSA = {
20
+ id: "mesh-linkerd-identity-ecdsa",
21
+ title: "Linkerd ECDSA identity issuer",
22
+ description: "Linkerd control-plane identity issuer (default ECDSA P-256 mesh CA)",
23
+ category: "certificate",
24
+ severity: "medium",
25
+ confidence: "high",
26
+ algorithm: "ECDSA",
27
+ hndl: false,
28
+ cwe: CWE_BROKEN_CRYPTO,
29
+ message: "Linkerd's control-plane identity issuer mints workload certificates from a classical ECDSA P-256 trust anchor by default, forgeable by a quantum attacker.",
30
+ remediation: "Plan migration to ML-DSA-65 (FIPS 204) once Linkerd's identity issuer supports PQC signing.",
31
+ };
32
+ const RULE_MESH_CONSUL_RSA = {
33
+ id: "mesh-consul-connect-rsa",
34
+ title: "Consul Connect RSA mesh CA",
35
+ description: 'Consul Connect ca_config private_key_type = "rsa"',
36
+ category: "certificate",
37
+ severity: "medium",
38
+ confidence: "high",
39
+ algorithm: "RSA",
40
+ hndl: true,
41
+ cwe: CWE_BROKEN_CRYPTO,
42
+ message: "Consul Connect's mesh CA issues leaf certificates from a classical RSA private key, which is not quantum-safe.",
43
+ remediation: "Plan migration to PQC certificate keys (ML-DSA-65) as the Connect CA provider adds support.",
44
+ };
45
+ const RULE_MESH_CONSUL_EC = {
46
+ id: "mesh-consul-connect-ec",
47
+ title: "Consul Connect EC mesh CA",
48
+ description: 'Consul Connect ca_config private_key_type = "ec"',
49
+ category: "certificate",
50
+ severity: "medium",
51
+ confidence: "high",
52
+ algorithm: "ECDSA",
53
+ hndl: false,
54
+ cwe: CWE_BROKEN_CRYPTO,
55
+ message: "Consul Connect's mesh CA issues leaf certificates from a classical EC private key, forgeable by a quantum attacker.",
56
+ remediation: "Plan migration to ML-DSA-65 (FIPS 204) as the Connect CA provider adds support.",
57
+ };
58
+ /**
59
+ * Detects classical asymmetric crypto in service-mesh configuration: Linkerd's
60
+ * default ECDSA identity issuer and Consul Connect's mesh CA private key type.
61
+ * (Istio ECDHE cipher-suite strings are covered by `source.ts`'s
62
+ * `tls-classical-kex` token rule, so they are not duplicated here.)
63
+ */
64
+ export const meshDetector = {
65
+ id: "service-mesh-crypto",
66
+ description: "Classical crypto in service-mesh config (Linkerd identity, Consul Connect CA)",
67
+ scope: "config",
68
+ language: "any",
69
+ rules: [RULE_MESH_LINKERD_ECDSA, RULE_MESH_CONSUL_RSA, RULE_MESH_CONSUL_EC],
70
+ appliesTo: (f) => hasExtension(f, MESH_EXTENSIONS),
71
+ detect({ file, content }) {
72
+ const isLinkerd = content.includes("linkerd") || content.includes("identityTrustAnchors");
73
+ const isConsulConnect = content.includes("consul") && content.includes("connect");
74
+ if (!isLinkerd && !isConsulConnect)
75
+ return [];
76
+ // Mask whole comment lines (YAML/HCL `#`, HCL/JSON5 `//`) so a commented-out
77
+ // directive can't fire — `.yaml`/`.hcl`/`.json` are not centrally stripped.
78
+ // Offsets are preserved, so the finding location stays exact.
79
+ const scan = maskCommentLines(content, ["#", "//"]);
80
+ const findings = [];
81
+ const add = (re, rule) => eachMatch(re, scan, (m) => findings.push(findingFromRule(rule, { file, content, index: m.index, matchLength: m[0].length })));
82
+ if (isLinkerd)
83
+ add(RE_MESH_LINKERD_ECDSA, RULE_MESH_LINKERD_ECDSA);
84
+ if (isConsulConnect) {
85
+ add(RE_MESH_CONSUL_RSA, RULE_MESH_CONSUL_RSA);
86
+ add(RE_MESH_CONSUL_EC, RULE_MESH_CONSUL_EC);
87
+ }
88
+ return findings;
89
+ },
90
+ };
91
+ //# sourceMappingURL=mesh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mesh.js","sourceRoot":"","sources":["../../src/detectors/mesh.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Config detector: classical crypto in SERVICE MESH configuration — the\n * control-plane identity/CA systems and mesh-internal TLS settings of\n * Linkerd, HashiCorp Consul Connect, and Istio. These mint the mTLS identity\n * certificates that secure sidecar-to-sidecar traffic and are configured in\n * their own Helm values / HCL / CRD surfaces, distinct from what `k8s.ts`\n * already covers (cert-manager `Certificate`/`Issuer` keys and Istio's\n * `minProtocolVersion` TLS floor — NOT duplicated here).\n *\n * Covered (gated by a mesh marker in the document to keep generic keys like\n * `scheme:` / `private_key_type` from firing on unrelated YAML/HCL):\n * - Linkerd control-plane identity issuer: Helm values `identityTrustAnchorsPEM`\n * and `identity.issuer.scheme` / nested `issuer.scheme: linkerd.io/tls` — the\n * default self-managed Linkerd identity scheme, which mints workload\n * certificates from an ECDSA P-256 trust anchor. Flagged as a classical mesh\n * CA (certificate, ECDSA, hndl:false) since Linkerd's identity issuer signs\n * forgeable-by-quantum leaf certs, not a confidentiality key.\n * - HashiCorp Consul Connect: the `connect { ca_config { private_key_type =\n * \"ec\" | \"rsa\" } } }` mesh CA provider setting (also `ca_provider`). Flagged\n * as a classical mesh CA (certificate; ECDSA for \"ec\", RSA for \"rsa\").\n * Istio `tls.cipherSuites:` `ECDHE-RSA-*` / `ECDHE-ECDSA-*` suites are NOT handled\n * here — the language-agnostic `tls-classical-kex` token rule in `source.ts`\n * already flags those cipher strings in any config file, so a rule here would\n * double-count.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport { eachMatch, findingFromRule, hasExtension, maskCommentLines } from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO } from \"../cwe.js\";\n\n// `.json` is included because Consul agent config is commonly JSON (the\n// `private_key_type` rules already support the JSON `:` form); the content gates\n// keep unrelated generic JSON/YAML out.\nconst MESH_EXTENSIONS: readonly string[] = [\".yaml\", \".yml\", \".hcl\", \".json\"];\n\n// Linkerd's default self-managed identity scheme (`linkerd.io/tls`, as opposed\n// to a `kubernetes.io/tls` bring-your-own-cert secret) mints its trust anchor\n// and issuer credentials as ECDSA P-256 by default. Matched in both nested\n// YAML form (`scheme: linkerd.io/tls`) and the flattened Helm `--set`/values\n// key form (`identity.issuer.scheme: linkerd.io/tls`), plus the distinctive\n// `identityTrustAnchorsPEM` values key which only exists in Linkerd charts.\nconst RE_MESH_LINKERD_ECDSA =\n /identityTrustAnchorsPEM\\b|(?:identity\\.issuer\\.scheme|scheme)\\s*[:=]\\s*[\"']?linkerd\\.io\\/tls\\b/g;\n\n// Consul Connect's CA provider config: `private_key_type = \"ec\" | \"rsa\"`\n// inside a `ca_config` block. Matched in both HCL (`=`) and JSON (`:`) forms,\n// mirroring the terraform.ts attribute-matching convention.\nconst RE_MESH_CONSUL_RSA = /(?<![\\w\"-])\"?private_key_type\"?\\s*[:=]\\s*\"rsa\"/gi;\nconst RE_MESH_CONSUL_EC = /(?<![\\w\"-])\"?private_key_type\"?\\s*[:=]\\s*\"ec\"/gi;\n\nconst RULE_MESH_LINKERD_ECDSA: RuleMeta = {\n id: \"mesh-linkerd-identity-ecdsa\",\n title: \"Linkerd ECDSA identity issuer\",\n description: \"Linkerd control-plane identity issuer (default ECDSA P-256 mesh CA)\",\n category: \"certificate\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Linkerd's control-plane identity issuer mints workload certificates from a classical ECDSA P-256 trust anchor by default, forgeable by a quantum attacker.\",\n remediation:\n \"Plan migration to ML-DSA-65 (FIPS 204) once Linkerd's identity issuer supports PQC signing.\",\n};\nconst RULE_MESH_CONSUL_RSA: RuleMeta = {\n id: \"mesh-consul-connect-rsa\",\n title: \"Consul Connect RSA mesh CA\",\n description: 'Consul Connect ca_config private_key_type = \"rsa\"',\n category: \"certificate\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Consul Connect's mesh CA issues leaf certificates from a classical RSA private key, which is not quantum-safe.\",\n remediation:\n \"Plan migration to PQC certificate keys (ML-DSA-65) as the Connect CA provider adds support.\",\n};\nconst RULE_MESH_CONSUL_EC: RuleMeta = {\n id: \"mesh-consul-connect-ec\",\n title: \"Consul Connect EC mesh CA\",\n description: 'Consul Connect ca_config private_key_type = \"ec\"',\n category: \"certificate\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Consul Connect's mesh CA issues leaf certificates from a classical EC private key, forgeable by a quantum attacker.\",\n remediation: \"Plan migration to ML-DSA-65 (FIPS 204) as the Connect CA provider adds support.\",\n};\n/**\n * Detects classical asymmetric crypto in service-mesh configuration: Linkerd's\n * default ECDSA identity issuer and Consul Connect's mesh CA private key type.\n * (Istio ECDHE cipher-suite strings are covered by `source.ts`'s\n * `tls-classical-kex` token rule, so they are not duplicated here.)\n */\nexport const meshDetector: Detector = {\n id: \"service-mesh-crypto\",\n description: \"Classical crypto in service-mesh config (Linkerd identity, Consul Connect CA)\",\n scope: \"config\",\n language: \"any\",\n rules: [RULE_MESH_LINKERD_ECDSA, RULE_MESH_CONSUL_RSA, RULE_MESH_CONSUL_EC],\n appliesTo: (f) => hasExtension(f, MESH_EXTENSIONS),\n detect({ file, content }): Finding[] {\n const isLinkerd = content.includes(\"linkerd\") || content.includes(\"identityTrustAnchors\");\n const isConsulConnect = content.includes(\"consul\") && content.includes(\"connect\");\n if (!isLinkerd && !isConsulConnect) return [];\n\n // Mask whole comment lines (YAML/HCL `#`, HCL/JSON5 `//`) so a commented-out\n // directive can't fire — `.yaml`/`.hcl`/`.json` are not centrally stripped.\n // Offsets are preserved, so the finding location stays 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 if (isLinkerd) add(RE_MESH_LINKERD_ECDSA, RULE_MESH_LINKERD_ECDSA);\n if (isConsulConnect) {\n add(RE_MESH_CONSUL_RSA, RULE_MESH_CONSUL_RSA);\n add(RE_MESH_CONSUL_EC, RULE_MESH_CONSUL_EC);\n }\n return findings;\n },\n};\n"]}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Config detector: classical transport crypto in message brokers / event streams
3
+ * (Kafka, RabbitMQ, MQTT/Mosquitto, NATS). Broker traffic is "communication
4
+ * between things"; a legacy TLS floor or a classical (EC)DHE cipher suite makes
5
+ * every message in flight harvest-now-decrypt-later exposed.
6
+ *
7
+ * Covered in broker config files (`.properties`, `.conf`, `.cfg`, `.ini`):
8
+ * - Kafka `ssl.protocol` / `ssl.enabled.protocols = TLSv1 | TLSv1.1` (legacy).
9
+ * - MQTT/Mosquitto `tls_version tlsv1 | tlsv1.1` (legacy).
10
+ * - Kafka `ssl.cipher.suites` naming a static-RSA `TLS_RSA_WITH_*` key-transport
11
+ * suite (the ECDHE/DHE suites are owned by source.ts's `tls-classical-kex`).
12
+ */
13
+ import type { Detector } from "../types.js";
14
+ /** Detects classical transport crypto in message-broker / event-stream config. */
15
+ export declare const messagingDetector: Detector;
16
+ //# sourceMappingURL=messaging.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messaging.d.ts","sourceRoot":"","sources":["../../src/detectors/messaging.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAsE/D,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,EAAE,QAsB/B,CAAC"}