@quantakrypto/core 0.4.1 → 0.4.3

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 (140) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +38 -10
  3. package/dist/agent-types.js.map +1 -1
  4. package/dist/baseline.js.map +1 -1
  5. package/dist/cache.js.map +1 -1
  6. package/dist/cbom.d.ts.map +1 -1
  7. package/dist/cbom.js +13 -4
  8. package/dist/cbom.js.map +1 -1
  9. package/dist/changed.js.map +1 -1
  10. package/dist/codemods/config-toggle.js.map +1 -1
  11. package/dist/codemods/registry.js.map +1 -1
  12. package/dist/comments.d.ts +26 -0
  13. package/dist/comments.d.ts.map +1 -1
  14. package/dist/comments.js +141 -1
  15. package/dist/comments.js.map +1 -1
  16. package/dist/config.js.map +1 -1
  17. package/dist/cwe.js.map +1 -1
  18. package/dist/dependencies.d.ts +3 -2
  19. package/dist/dependencies.d.ts.map +1 -1
  20. package/dist/dependencies.js +151 -4
  21. package/dist/dependencies.js.map +1 -1
  22. package/dist/detect-utils.d.ts +14 -3
  23. package/dist/detect-utils.d.ts.map +1 -1
  24. package/dist/detect-utils.js +32 -4
  25. package/dist/detect-utils.js.map +1 -1
  26. package/dist/detectors/c.d.ts.map +1 -1
  27. package/dist/detectors/c.js +190 -2
  28. package/dist/detectors/c.js.map +1 -1
  29. package/dist/detectors/csharp.d.ts.map +1 -1
  30. package/dist/detectors/csharp.js +141 -3
  31. package/dist/detectors/csharp.js.map +1 -1
  32. package/dist/detectors/go.d.ts +5 -3
  33. package/dist/detectors/go.d.ts.map +1 -1
  34. package/dist/detectors/go.js +187 -3
  35. package/dist/detectors/go.js.map +1 -1
  36. package/dist/detectors/java.d.ts.map +1 -1
  37. package/dist/detectors/java.js +168 -3
  38. package/dist/detectors/java.js.map +1 -1
  39. package/dist/detectors/pem.d.ts.map +1 -1
  40. package/dist/detectors/pem.js +49 -1
  41. package/dist/detectors/pem.js.map +1 -1
  42. package/dist/detectors/python.d.ts.map +1 -1
  43. package/dist/detectors/python.js +74 -3
  44. package/dist/detectors/python.js.map +1 -1
  45. package/dist/detectors/ruby.d.ts +9 -5
  46. package/dist/detectors/ruby.d.ts.map +1 -1
  47. package/dist/detectors/ruby.js +122 -2
  48. package/dist/detectors/ruby.js.map +1 -1
  49. package/dist/detectors/rust.d.ts +8 -3
  50. package/dist/detectors/rust.d.ts.map +1 -1
  51. package/dist/detectors/rust.js +185 -3
  52. package/dist/detectors/rust.js.map +1 -1
  53. package/dist/detectors/source.d.ts.map +1 -1
  54. package/dist/detectors/source.js +131 -13
  55. package/dist/detectors/source.js.map +1 -1
  56. package/dist/detectors/stateful-hbs.d.ts +22 -0
  57. package/dist/detectors/stateful-hbs.d.ts.map +1 -0
  58. package/dist/detectors/stateful-hbs.js +139 -0
  59. package/dist/detectors/stateful-hbs.js.map +1 -0
  60. package/dist/errors.js.map +1 -1
  61. package/dist/evidence.d.ts +48 -0
  62. package/dist/evidence.d.ts.map +1 -0
  63. package/dist/evidence.js +76 -0
  64. package/dist/evidence.js.map +1 -0
  65. package/dist/index.d.ts +4 -2
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +4 -2
  68. package/dist/index.js.map +1 -1
  69. package/dist/inventory.d.ts +2 -0
  70. package/dist/inventory.d.ts.map +1 -1
  71. package/dist/inventory.js +27 -1
  72. package/dist/inventory.js.map +1 -1
  73. package/dist/parallel.js +15 -0
  74. package/dist/parallel.js.map +1 -1
  75. package/dist/patch-policy.js.map +1 -1
  76. package/dist/redact.d.ts.map +1 -1
  77. package/dist/redact.js +122 -7
  78. package/dist/redact.js.map +1 -1
  79. package/dist/registry.d.ts +2 -2
  80. package/dist/registry.d.ts.map +1 -1
  81. package/dist/registry.js +4 -2
  82. package/dist/registry.js.map +1 -1
  83. package/dist/remediate-pipeline.d.ts +3 -0
  84. package/dist/remediate-pipeline.d.ts.map +1 -1
  85. package/dist/remediate-pipeline.js +50 -0
  86. package/dist/remediate-pipeline.js.map +1 -1
  87. package/dist/remediate-request.js.map +1 -1
  88. package/dist/remediation.d.ts +9 -3
  89. package/dist/remediation.d.ts.map +1 -1
  90. package/dist/remediation.js +33 -6
  91. package/dist/remediation.js.map +1 -1
  92. package/dist/report.d.ts +9 -0
  93. package/dist/report.d.ts.map +1 -1
  94. package/dist/report.js +31 -0
  95. package/dist/report.js.map +1 -1
  96. package/dist/scan-worker.js.map +1 -1
  97. package/dist/scan.d.ts.map +1 -1
  98. package/dist/scan.js +16 -2
  99. package/dist/scan.js.map +1 -1
  100. package/dist/severity.js.map +1 -1
  101. package/dist/triage.js.map +1 -1
  102. package/dist/types.d.ts +8 -1
  103. package/dist/types.d.ts.map +1 -1
  104. package/dist/types.js.map +1 -1
  105. package/dist/verify.js.map +1 -1
  106. package/dist/version.d.ts +1 -1
  107. package/dist/version.js +1 -1
  108. package/dist/version.js.map +1 -1
  109. package/dist/walk.js.map +1 -1
  110. package/dist/worktree.d.ts.map +1 -1
  111. package/dist/worktree.js +10 -1
  112. package/dist/worktree.js.map +1 -1
  113. package/package.json +1 -1
  114. package/src/cbom.ts +13 -4
  115. package/src/comments.ts +140 -1
  116. package/src/dependencies.ts +156 -6
  117. package/src/detect-utils.ts +33 -4
  118. package/src/detectors/c.ts +202 -2
  119. package/src/detectors/csharp.ts +154 -3
  120. package/src/detectors/go.ts +209 -6
  121. package/src/detectors/java.ts +189 -3
  122. package/src/detectors/pem.ts +53 -1
  123. package/src/detectors/python.ts +82 -3
  124. package/src/detectors/ruby.ts +138 -7
  125. package/src/detectors/rust.ts +211 -7
  126. package/src/detectors/source.ts +163 -12
  127. package/src/detectors/stateful-hbs.ts +177 -0
  128. package/src/evidence.ts +124 -0
  129. package/src/index.ts +5 -1
  130. package/src/inventory.ts +31 -1
  131. package/src/parallel.ts +15 -0
  132. package/src/redact.ts +125 -8
  133. package/src/registry.ts +4 -2
  134. package/src/remediate-pipeline.ts +55 -0
  135. package/src/remediation.ts +41 -9
  136. package/src/report.ts +41 -2
  137. package/src/scan.ts +21 -2
  138. package/src/types.ts +8 -1
  139. package/src/version.ts +1 -1
  140. package/src/worktree.ts +9 -1
@@ -1,13 +1,17 @@
1
1
  /**
2
2
  * Source-code detector for classical asymmetric cryptography in Ruby. Ruby's
3
3
  * asymmetric crypto is almost entirely `OpenSSL::PKey::{RSA,EC,DSA,DH}`, which
4
- * makes the signals precise. Lexical, same strategy as the other packs.
4
+ * makes the signals precise. Lexical, same strategy as the other packs. Beyond
5
+ * keygen it also covers RSA public-key encryption on a loaded key, DH key
6
+ * agreement, the type-agnostic `OpenSSL::PKey.read` loader, Ed25519 key
7
+ * generation, and disabled TLS peer verification (`VERIFY_NONE`).
5
8
  *
6
9
  * HNDL: RSA (keygen/encryption) and (EC)DH key agreement are harvest-now-
7
- * decrypt-later exposed (hndl:true); DSA signatures are hndl:false but forgeable.
8
- * `OpenSSL::PKey::EC` is ambiguous (feeds ECDSA + ECDH), so it is classified
9
- * conservatively as key-exchange-capable (hndl:true), like the other EC keygen
10
- * rules.
10
+ * decrypt-later exposed (hndl:true); DSA / Ed25519 signatures are hndl:false but
11
+ * forgeable. `OpenSSL::PKey::EC` is ambiguous (feeds ECDSA + ECDH), so it is
12
+ * classified conservatively as key-exchange-capable (hndl:true), like the other
13
+ * EC keygen rules; `OpenSSL::PKey.read` loads a key of unknown type and is
14
+ * likewise treated conservatively.
11
15
  */
12
16
  import type { Detector } from "../types.js";
13
17
  /** Detects classical asymmetric crypto in Ruby (OpenSSL::PKey). */
@@ -1 +1 @@
1
- {"version":3,"file":"ruby.d.ts","sourceRoot":"","sources":["../../src/detectors/ruby.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AA+D/D,mEAAmE;AACnE,eAAO,MAAM,YAAY,EAAE,QAqB1B,CAAC"}
1
+ {"version":3,"file":"ruby.d.ts","sourceRoot":"","sources":["../../src/detectors/ruby.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AA2K/D,mEAAmE;AACnE,eAAO,MAAM,YAAY,EAAE,QAwC1B,CAAC"}
@@ -1,9 +1,23 @@
1
1
  import { RUBY_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from "../detect-utils.js";
2
- import { CWE_BROKEN_CRYPTO } from "../cwe.js";
2
+ import { CWE_BROKEN_CRYPTO, CWE_CERT_VALIDATION } from "../cwe.js";
3
3
  const RE_RB_RSA = /\bOpenSSL::PKey::RSA\.(?:new|generate)\s*\(/g;
4
4
  const RE_RB_EC = /\bOpenSSL::PKey::EC\.(?:new|generate)\s*\(/g;
5
5
  const RE_RB_DSA = /\bOpenSSL::PKey::DSA\.(?:new|generate)\s*\(/g;
6
6
  const RE_RB_DH = /\bOpenSSL::PKey::DH\.new\s*\(/g;
7
+ // RSA public-key encryption on an already-loaded key (audit F4-ruby / F9).
8
+ const RE_RB_RSA_CRYPT = /\.public_encrypt\b|\.private_decrypt\b/g;
9
+ // Finite-field DH shared-secret agreement.
10
+ const RE_RB_DH_AGREE = /\bdh_compute_key\s*\(/g;
11
+ // Type-agnostic key loader — could be RSA/EC/DSA/DH (conservative).
12
+ const RE_RB_PKEY_READ = /\bOpenSSL::PKey\.read\s*\(/g;
13
+ // Ed25519 signing key via the generic generate_key factory.
14
+ const RE_RB_ED25519 = /\bOpenSSL::PKey\.generate_key\s*\(\s*["']ED25519["']/g;
15
+ // `ed25519` gem — Ed25519::SigningKey / VerifyKey (signature keys).
16
+ const RE_RB_ED25519_GEM = /\bEd25519::(?:SigningKey|VerifyKey)\b/g;
17
+ // `rbnacl` (libsodium) — Curve25519/X25519 key agreement: PrivateKey, Box, GroupElement.
18
+ const RE_RB_RBNACL = /\bRbNaCl::(?:PrivateKey|Box|GroupElement)\b/g;
19
+ // TLS peer verification disabled (mirrors the JS tlsDetector rejectUnauthorized rule).
20
+ const RE_RB_TLS_VERIFY_NONE = /\bOpenSSL::SSL::VERIFY_NONE\b/g;
7
21
  const RULE_RB_RSA = {
8
22
  id: "ruby-rsa",
9
23
  title: "Ruby RSA key/usage",
@@ -54,13 +68,112 @@ const RULE_RB_DH = {
54
68
  cwe: CWE_BROKEN_CRYPTO,
55
69
  message: "Finite-field Diffie-Hellman (Ruby/OpenSSL) is broken by Shor's algorithm (harvest-now-decrypt-later).",
56
70
  };
71
+ const RULE_RB_RSA_CRYPT = {
72
+ id: "ruby-rsa-crypt",
73
+ title: "Ruby RSA public-key encryption",
74
+ description: "OpenSSL::PKey::RSA#public_encrypt / #private_decrypt",
75
+ category: "kem",
76
+ severity: "high",
77
+ confidence: "high",
78
+ algorithm: "RSA",
79
+ hndl: true,
80
+ cwe: CWE_BROKEN_CRYPTO,
81
+ message: "RSA public-key encryption/decryption (Ruby/OpenSSL) is harvest-now-decrypt-later exposed.",
82
+ };
83
+ const RULE_RB_DH_AGREE = {
84
+ id: "ruby-dh-agree",
85
+ title: "Ruby Diffie-Hellman key agreement",
86
+ description: "OpenSSL DH compute_key shared-secret agreement",
87
+ category: "key-exchange",
88
+ severity: "high",
89
+ confidence: "high",
90
+ algorithm: "DH",
91
+ hndl: true,
92
+ cwe: CWE_BROKEN_CRYPTO,
93
+ message: "Finite-field Diffie-Hellman key agreement (Ruby/OpenSSL) is broken by Shor's algorithm (harvest-now-decrypt-later).",
94
+ };
95
+ const RULE_RB_PKEY_READ = {
96
+ id: "ruby-pkey-read",
97
+ title: "Ruby PKey loaded from serialized key",
98
+ description: "OpenSSL::PKey.read (type-agnostic key loader)",
99
+ category: "key-exchange",
100
+ severity: "high",
101
+ confidence: "medium",
102
+ algorithm: "unknown",
103
+ hndl: true,
104
+ cwe: CWE_BROKEN_CRYPTO,
105
+ message: "Loads a classical asymmetric key of unknown type (RSA/EC/DSA/DH) via OpenSSL::PKey.read. Treated conservatively as key-exchange-capable (harvest-now-decrypt-later).",
106
+ remediation: "For key agreement: hybrid X25519MLKEM768 (ML-KEM-768). For signatures: ML-DSA-65 (FIPS 204).",
107
+ };
108
+ const RULE_RB_ED25519 = {
109
+ id: "ruby-ed25519",
110
+ title: "Ruby Ed25519 key generation",
111
+ description: 'OpenSSL::PKey.generate_key("ED25519")',
112
+ category: "signature",
113
+ severity: "low",
114
+ confidence: "high",
115
+ algorithm: "EdDSA",
116
+ hndl: false,
117
+ cwe: CWE_BROKEN_CRYPTO,
118
+ message: "Generates an Ed25519 signing key (Ruby/OpenSSL) — modern but classical, and forgeable by a quantum attacker.",
119
+ remediation: "ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)",
120
+ };
121
+ const RULE_RB_ED25519_GEM = {
122
+ id: "ruby-ed25519-gem",
123
+ title: "Ruby Ed25519 signature (ed25519 gem)",
124
+ description: "ed25519 gem Ed25519::SigningKey / Ed25519::VerifyKey",
125
+ category: "signature",
126
+ severity: "low",
127
+ confidence: "high",
128
+ algorithm: "EdDSA",
129
+ hndl: false,
130
+ cwe: CWE_BROKEN_CRYPTO,
131
+ message: "Ed25519 signing/verification via the `ed25519` gem — modern but classical, and forgeable by a quantum attacker.",
132
+ remediation: "ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)",
133
+ };
134
+ const RULE_RB_RBNACL = {
135
+ id: "ruby-rbnacl",
136
+ title: "Ruby X25519 key agreement (rbnacl)",
137
+ description: "rbnacl (libsodium) RbNaCl::PrivateKey / Box / GroupElement",
138
+ category: "key-exchange",
139
+ severity: "medium",
140
+ confidence: "high",
141
+ algorithm: "X25519",
142
+ hndl: true,
143
+ cwe: CWE_BROKEN_CRYPTO,
144
+ message: "Curve25519/X25519 key agreement via the `rbnacl` gem (libsodium) — modern but classical key agreement, harvest-now-decrypt-later exposed.",
145
+ };
146
+ const RULE_RB_TLS_VERIFY_NONE = {
147
+ id: "ruby-tls-verify-none",
148
+ title: "Ruby TLS certificate verification disabled",
149
+ description: "OpenSSL::SSL::VERIFY_NONE",
150
+ category: "tls",
151
+ severity: "high",
152
+ confidence: "high",
153
+ hndl: false,
154
+ cwe: CWE_CERT_VALIDATION,
155
+ message: "OpenSSL::SSL::VERIFY_NONE disables TLS peer certificate verification (MITM risk).",
156
+ remediation: "Use OpenSSL::SSL::VERIFY_PEER and verify the certificate chain.",
157
+ };
57
158
  /** Detects classical asymmetric crypto in Ruby (OpenSSL::PKey). */
58
159
  export const rubyDetector = {
59
160
  id: "ruby-crypto",
60
161
  description: "Classical asymmetric crypto in Ruby (OpenSSL::PKey::{RSA,EC,DSA,DH})",
61
162
  scope: "source",
62
163
  language: "ruby",
63
- rules: [RULE_RB_RSA, RULE_RB_EC, RULE_RB_DSA, RULE_RB_DH],
164
+ rules: [
165
+ RULE_RB_RSA,
166
+ RULE_RB_EC,
167
+ RULE_RB_DSA,
168
+ RULE_RB_DH,
169
+ RULE_RB_RSA_CRYPT,
170
+ RULE_RB_DH_AGREE,
171
+ RULE_RB_PKEY_READ,
172
+ RULE_RB_ED25519,
173
+ RULE_RB_ED25519_GEM,
174
+ RULE_RB_RBNACL,
175
+ RULE_RB_TLS_VERIFY_NONE,
176
+ ],
64
177
  appliesTo: (f) => hasExtension(f, RUBY_EXTENSIONS),
65
178
  detect({ file, content }) {
66
179
  const findings = [];
@@ -69,6 +182,13 @@ export const rubyDetector = {
69
182
  add(RE_RB_EC, RULE_RB_EC);
70
183
  add(RE_RB_DSA, RULE_RB_DSA);
71
184
  add(RE_RB_DH, RULE_RB_DH);
185
+ add(RE_RB_RSA_CRYPT, RULE_RB_RSA_CRYPT);
186
+ add(RE_RB_DH_AGREE, RULE_RB_DH_AGREE);
187
+ add(RE_RB_PKEY_READ, RULE_RB_PKEY_READ);
188
+ add(RE_RB_ED25519, RULE_RB_ED25519);
189
+ add(RE_RB_ED25519_GEM, RULE_RB_ED25519_GEM);
190
+ add(RE_RB_RBNACL, RULE_RB_RBNACL);
191
+ add(RE_RB_TLS_VERIFY_NONE, RULE_RB_TLS_VERIFY_NONE);
72
192
  return findings;
73
193
  },
74
194
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ruby.js","sourceRoot":"","sources":["../../src/detectors/ruby.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ruby.js","sourceRoot":"","sources":["../../src/detectors/ruby.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Source-code detector for classical asymmetric cryptography in Ruby. Ruby's\n * asymmetric crypto is almost entirely `OpenSSL::PKey::{RSA,EC,DSA,DH}`, which\n * makes the signals precise. Lexical, same strategy as the other packs. Beyond\n * keygen it also covers RSA public-key encryption on a loaded key, DH key\n * agreement, the type-agnostic `OpenSSL::PKey.read` loader, Ed25519 key\n * generation, and disabled TLS peer verification (`VERIFY_NONE`).\n *\n * HNDL: RSA (keygen/encryption) and (EC)DH key agreement are harvest-now-\n * decrypt-later exposed (hndl:true); DSA / Ed25519 signatures are hndl:false but\n * forgeable. `OpenSSL::PKey::EC` is ambiguous (feeds ECDSA + ECDH), so it is\n * classified conservatively as key-exchange-capable (hndl:true), like the other\n * EC keygen rules; `OpenSSL::PKey.read` loads a key of unknown type and is\n * likewise treated conservatively.\n */\nimport type { Detector, Finding, RuleMeta } from \"../types.js\";\nimport { RUBY_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO, CWE_CERT_VALIDATION } from \"../cwe.js\";\n\nconst RE_RB_RSA = /\\bOpenSSL::PKey::RSA\\.(?:new|generate)\\s*\\(/g;\nconst RE_RB_EC = /\\bOpenSSL::PKey::EC\\.(?:new|generate)\\s*\\(/g;\nconst RE_RB_DSA = /\\bOpenSSL::PKey::DSA\\.(?:new|generate)\\s*\\(/g;\nconst RE_RB_DH = /\\bOpenSSL::PKey::DH\\.new\\s*\\(/g;\n// RSA public-key encryption on an already-loaded key (audit F4-ruby / F9).\nconst RE_RB_RSA_CRYPT = /\\.public_encrypt\\b|\\.private_decrypt\\b/g;\n// Finite-field DH shared-secret agreement.\nconst RE_RB_DH_AGREE = /\\bdh_compute_key\\s*\\(/g;\n// Type-agnostic key loader — could be RSA/EC/DSA/DH (conservative).\nconst RE_RB_PKEY_READ = /\\bOpenSSL::PKey\\.read\\s*\\(/g;\n// Ed25519 signing key via the generic generate_key factory.\nconst RE_RB_ED25519 = /\\bOpenSSL::PKey\\.generate_key\\s*\\(\\s*[\"']ED25519[\"']/g;\n// `ed25519` gem — Ed25519::SigningKey / VerifyKey (signature keys).\nconst RE_RB_ED25519_GEM = /\\bEd25519::(?:SigningKey|VerifyKey)\\b/g;\n// `rbnacl` (libsodium) — Curve25519/X25519 key agreement: PrivateKey, Box, GroupElement.\nconst RE_RB_RBNACL = /\\bRbNaCl::(?:PrivateKey|Box|GroupElement)\\b/g;\n// TLS peer verification disabled (mirrors the JS tlsDetector rejectUnauthorized rule).\nconst RE_RB_TLS_VERIFY_NONE = /\\bOpenSSL::SSL::VERIFY_NONE\\b/g;\n\nconst RULE_RB_RSA: RuleMeta = {\n id: \"ruby-rsa\",\n title: \"Ruby RSA key/usage\",\n description: \"OpenSSL::PKey::RSA.new / .generate\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Classical RSA (Ruby/OpenSSL) is not quantum-safe and RSA encryption is HNDL-exposed.\",\n};\nconst RULE_RB_EC: RuleMeta = {\n id: \"ruby-ec\",\n title: \"Ruby EC key generation\",\n description: \"OpenSSL::PKey::EC.new / .generate\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Generates a classical EC key pair (Ruby/OpenSSL). EC keys feed 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};\nconst RULE_RB_DSA: RuleMeta = {\n id: \"ruby-dsa\",\n title: \"Ruby DSA key/signature\",\n description: \"OpenSSL::PKey::DSA.new / .generate\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"DSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Classical DSA (Ruby/OpenSSL) is deprecated and forgeable by a quantum attacker.\",\n remediation: \"Rotate off DSA and migrate to ML-DSA-65 (FIPS 204).\",\n};\nconst RULE_RB_DH: RuleMeta = {\n id: \"ruby-dh\",\n title: \"Ruby Diffie-Hellman key exchange\",\n description: \"OpenSSL::PKey::DH.new\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"DH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Finite-field Diffie-Hellman (Ruby/OpenSSL) is broken by Shor's algorithm (harvest-now-decrypt-later).\",\n};\nconst RULE_RB_RSA_CRYPT: RuleMeta = {\n id: \"ruby-rsa-crypt\",\n title: \"Ruby RSA public-key encryption\",\n description: \"OpenSSL::PKey::RSA#public_encrypt / #private_decrypt\",\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/decryption (Ruby/OpenSSL) is harvest-now-decrypt-later exposed.\",\n};\nconst RULE_RB_DH_AGREE: RuleMeta = {\n id: \"ruby-dh-agree\",\n title: \"Ruby Diffie-Hellman key agreement\",\n description: \"OpenSSL DH compute_key shared-secret agreement\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"DH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Finite-field Diffie-Hellman key agreement (Ruby/OpenSSL) is broken by Shor's algorithm (harvest-now-decrypt-later).\",\n};\nconst RULE_RB_PKEY_READ: RuleMeta = {\n id: \"ruby-pkey-read\",\n title: \"Ruby PKey loaded from serialized key\",\n description: \"OpenSSL::PKey.read (type-agnostic key loader)\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Loads a classical asymmetric key of unknown type (RSA/EC/DSA/DH) via OpenSSL::PKey.read. Treated conservatively as key-exchange-capable (harvest-now-decrypt-later).\",\n remediation:\n \"For key agreement: hybrid X25519MLKEM768 (ML-KEM-768). For signatures: ML-DSA-65 (FIPS 204).\",\n};\nconst RULE_RB_ED25519: RuleMeta = {\n id: \"ruby-ed25519\",\n title: \"Ruby Ed25519 key generation\",\n description: 'OpenSSL::PKey.generate_key(\"ED25519\")',\n category: \"signature\",\n severity: \"low\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Generates an Ed25519 signing key (Ruby/OpenSSL) — modern but classical, and forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n};\nconst RULE_RB_ED25519_GEM: RuleMeta = {\n id: \"ruby-ed25519-gem\",\n title: \"Ruby Ed25519 signature (ed25519 gem)\",\n description: \"ed25519 gem Ed25519::SigningKey / Ed25519::VerifyKey\",\n category: \"signature\",\n severity: \"low\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Ed25519 signing/verification via the `ed25519` gem — modern but classical, and forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n};\nconst RULE_RB_RBNACL: RuleMeta = {\n id: \"ruby-rbnacl\",\n title: \"Ruby X25519 key agreement (rbnacl)\",\n description: \"rbnacl (libsodium) RbNaCl::PrivateKey / Box / GroupElement\",\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"X25519\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Curve25519/X25519 key agreement via the `rbnacl` gem (libsodium) — modern but classical key agreement, harvest-now-decrypt-later exposed.\",\n};\nconst RULE_RB_TLS_VERIFY_NONE: RuleMeta = {\n id: \"ruby-tls-verify-none\",\n title: \"Ruby TLS certificate verification disabled\",\n description: \"OpenSSL::SSL::VERIFY_NONE\",\n category: \"tls\",\n severity: \"high\",\n confidence: \"high\",\n hndl: false,\n cwe: CWE_CERT_VALIDATION,\n message: \"OpenSSL::SSL::VERIFY_NONE disables TLS peer certificate verification (MITM risk).\",\n remediation: \"Use OpenSSL::SSL::VERIFY_PEER and verify the certificate chain.\",\n};\n\n/** Detects classical asymmetric crypto in Ruby (OpenSSL::PKey). */\nexport const rubyDetector: Detector = {\n id: \"ruby-crypto\",\n description: \"Classical asymmetric crypto in Ruby (OpenSSL::PKey::{RSA,EC,DSA,DH})\",\n scope: \"source\",\n language: \"ruby\",\n rules: [\n RULE_RB_RSA,\n RULE_RB_EC,\n RULE_RB_DSA,\n RULE_RB_DH,\n RULE_RB_RSA_CRYPT,\n RULE_RB_DH_AGREE,\n RULE_RB_PKEY_READ,\n RULE_RB_ED25519,\n RULE_RB_ED25519_GEM,\n RULE_RB_RBNACL,\n RULE_RB_TLS_VERIFY_NONE,\n ],\n appliesTo: (f) => hasExtension(f, RUBY_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 add(RE_RB_RSA, RULE_RB_RSA);\n add(RE_RB_EC, RULE_RB_EC);\n add(RE_RB_DSA, RULE_RB_DSA);\n add(RE_RB_DH, RULE_RB_DH);\n add(RE_RB_RSA_CRYPT, RULE_RB_RSA_CRYPT);\n add(RE_RB_DH_AGREE, RULE_RB_DH_AGREE);\n add(RE_RB_PKEY_READ, RULE_RB_PKEY_READ);\n add(RE_RB_ED25519, RULE_RB_ED25519);\n add(RE_RB_ED25519_GEM, RULE_RB_ED25519_GEM);\n add(RE_RB_RBNACL, RULE_RB_RBNACL);\n add(RE_RB_TLS_VERIFY_NONE, RULE_RB_TLS_VERIFY_NONE);\n return findings;\n },\n};\n"]}
@@ -1,11 +1,16 @@
1
1
  /**
2
2
  * Source-code detector for classical asymmetric cryptography in Rust. Covers the
3
3
  * common crypto crates: `rsa`, `ring`, the `*-dalek` family (ed25519/x25519),
4
- * and the RustCrypto elliptic-curve crates (`p256`/`p384`/`k256`). Lexical, same
5
- * strategy as the other packs; the `::` path syntax makes the signals precise.
4
+ * the RustCrypto elliptic-curve crates (`p256`/`p384`/`k256`), and the `openssl`
5
+ * crate bindings. Lexical, same strategy as the other packs; the `::` path
6
+ * syntax makes the signals precise.
6
7
  *
7
8
  * HNDL: RSA encryption and (EC/X)DH key agreement are harvest-now-decrypt-later
8
- * exposed (hndl:true); ECDSA / Ed25519 signatures are hndl:false but forgeable.
9
+ * exposed (hndl:true); ECDSA / DSA / Ed25519 signatures are hndl:false but
10
+ * forgeable. `openssl::EcKey` keygen is ambiguous (feeds ECDSA + ECDH),
11
+ * classified conservatively as key-exchange-capable (hndl:true). Also flags
12
+ * Rust TLS certificate-validation bypasses (reqwest / rustls) — not quantum but
13
+ * mirrors the JS tlsDetector's cert-validation category.
9
14
  */
10
15
  import type { Detector } from "../types.js";
11
16
  /** Detects classical asymmetric crypto in Rust (rsa, ring, dalek, p256/k256). */
@@ -1 +1 @@
1
- {"version":3,"file":"rust.d.ts","sourceRoot":"","sources":["../../src/detectors/rust.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AA+E/D,iFAAiF;AACjF,eAAO,MAAM,YAAY,EAAE,QAsB1B,CAAC"}
1
+ {"version":3,"file":"rust.d.ts","sourceRoot":"","sources":["../../src/detectors/rust.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAmB,QAAQ,EAAqB,MAAM,aAAa,CAAC;AA+OhF,iFAAiF;AACjF,eAAO,MAAM,YAAY,EAAE,QA6D1B,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { RUST_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from "../detect-utils.js";
2
- import { CWE_BROKEN_CRYPTO } from "../cwe.js";
2
+ import { CWE_BROKEN_CRYPTO, CWE_CERT_VALIDATION } from "../cwe.js";
3
3
  // `rsa` crate + ring RsaKeyPair. `::` after the type marks an associated-fn call.
4
4
  const RE_RUST_RSA = /\b(?:RsaPrivateKey|RsaPublicKey|RsaKeyPair)::/g;
5
5
  // ECDSA: RustCrypto `p256::ecdsa::SigningKey` (contains `ecdsa::SigningKey`),
@@ -11,6 +11,31 @@ const RE_RUST_ECDH = /\becdh::EphemeralSecret\b|\bagreement::ECDH_P(?:256|384)\b
11
11
  const RE_RUST_ED25519 = /\bed25519_dalek::(?:SigningKey|Keypair|SecretKey)\b|\bEd25519KeyPair::/g;
12
12
  // X25519 key agreement (dalek).
13
13
  const RE_RUST_X25519 = /\bx25519_dalek::(?:EphemeralSecret|StaticSecret)\b/g;
14
+ // openssl crate bindings — the `Type::generate(` / `Dh::` call forms, distinct
15
+ // from the ring / RustCrypto path syntax above (audit F5/F9 false-negatives).
16
+ const RE_RUST_OPENSSL_RSA = /\bRsa::generate\s*\(/g;
17
+ const RE_RUST_OPENSSL_EC = /\bEcKey::generate\s*\(/g;
18
+ const RE_RUST_OPENSSL_DSA = /\bDsa::generate\s*\(/g;
19
+ const RE_RUST_OPENSSL_DH = /\bDh::/g;
20
+ // ring X25519 agreement (the ECDH_P* forms are handled by RE_RUST_ECDH above).
21
+ const RE_RUST_RING_X25519 = /\bagreement::X25519\b/g;
22
+ // Bare (unqualified) constructors: a braced `use x25519_dalek::{EphemeralSecret}`
23
+ // / `use ed25519_dalek::{SigningKey}` strips the `::` path prefix, defeating the
24
+ // path-qualified rules above. The `(?<![:\w])` lookbehind keeps these from
25
+ // double-matching the qualified forms (e.g. `p256::ecdsa::SigningKey::random`).
26
+ const RE_RUST_BARE_X25519 = /(?<![:\w])EphemeralSecret::new\s*\(/g;
27
+ const RE_RUST_BARE_SIGNINGKEY = /(?<![:\w])SigningKey::(?:generate|random)\s*\(/g;
28
+ // jsonwebtoken crate `Algorithm` enum variants selecting a classical JWT signer:
29
+ // RSASSA-PKCS1 (RS*), RSASSA-PSS (PS*), ECDSA (ES*), and Ed25519 (EdDSA). The
30
+ // `\s*` between `Algorithm` and `::` catches the variant split across lines /
31
+ // routed through a helper (audit token_policy false-negative); the required
32
+ // suffix keeps it off unrelated `Algorithm::` uses (e.g. `HS256` HMAC, which is
33
+ // symmetric and not quantum-vulnerable, or `Algorithm::new`).
34
+ const RE_RUST_JWT_ALG = /\bAlgorithm\s*::(RS|PS|ES)(?:256|384|512)\b|\bAlgorithm\s*::EdDSA\b/g;
35
+ // Rust TLS certificate-validation bypass: reqwest `danger_accept_invalid_certs`
36
+ // and the rustls `.dangerous()` escape hatch. Mirrors the JS tlsDetector.
37
+ const RE_RUST_TLS_ACCEPT_INVALID = /\bdanger_accept_invalid_certs\s*\(\s*true/g;
38
+ const RE_RUST_TLS_DANGEROUS = /\.dangerous\s*\(\s*\)/g;
14
39
  const RULE_RUST_RSA = {
15
40
  id: "rust-rsa",
16
41
  title: "Rust RSA key/usage",
@@ -65,20 +90,161 @@ const RULE_RUST_X25519 = {
65
90
  title: "Rust X25519 key agreement",
66
91
  description: "x25519-dalek EphemeralSecret/StaticSecret",
67
92
  category: "key-exchange",
68
- severity: "low",
93
+ severity: "medium",
69
94
  confidence: "high",
70
95
  algorithm: "X25519",
71
96
  hndl: true,
72
97
  cwe: CWE_BROKEN_CRYPTO,
73
98
  message: "X25519 (Rust) is modern but still classical key agreement — harvest-now-decrypt-later.",
74
99
  };
100
+ const RULE_RUST_OPENSSL_RSA = {
101
+ id: "rust-openssl-rsa",
102
+ title: "Rust openssl RSA key generation",
103
+ description: "openssl crate Rsa::generate",
104
+ category: "kem",
105
+ severity: "high",
106
+ confidence: "high",
107
+ algorithm: "RSA",
108
+ hndl: true,
109
+ cwe: CWE_BROKEN_CRYPTO,
110
+ message: "Generates a classical RSA key pair via the Rust `openssl` crate — not quantum-safe and RSA encryption is HNDL-exposed.",
111
+ };
112
+ const RULE_RUST_OPENSSL_EC = {
113
+ id: "rust-openssl-ec",
114
+ title: "Rust openssl EC key generation",
115
+ description: "openssl crate EcKey::generate",
116
+ category: "key-exchange",
117
+ severity: "high",
118
+ confidence: "high",
119
+ algorithm: "ECDH",
120
+ hndl: true,
121
+ cwe: CWE_BROKEN_CRYPTO,
122
+ message: "Generates a classical EC key pair via the Rust `openssl` crate. EC keys feed BOTH ECDSA signatures and ECDH key agreement; the ECDH path is harvest-now-decrypt-later exposed.",
123
+ remediation: "For key agreement: hybrid X25519MLKEM768 (ML-KEM-768). For signatures: ML-DSA-65 (FIPS 204).",
124
+ };
125
+ const RULE_RUST_OPENSSL_DSA = {
126
+ id: "rust-openssl-dsa",
127
+ title: "Rust openssl DSA key/usage",
128
+ description: "openssl crate Dsa::generate",
129
+ category: "signature",
130
+ severity: "high",
131
+ confidence: "high",
132
+ algorithm: "DSA",
133
+ hndl: false,
134
+ cwe: CWE_BROKEN_CRYPTO,
135
+ message: "Classical DSA via the Rust `openssl` crate is deprecated and forgeable by a quantum attacker.",
136
+ remediation: "Rotate off DSA and migrate to ML-DSA-65 (FIPS 204).",
137
+ };
138
+ const RULE_RUST_OPENSSL_DH = {
139
+ id: "rust-openssl-dh",
140
+ title: "Rust openssl Diffie-Hellman key exchange",
141
+ description: "openssl crate Dh params / key generation",
142
+ category: "key-exchange",
143
+ severity: "high",
144
+ confidence: "high",
145
+ algorithm: "DH",
146
+ hndl: true,
147
+ cwe: CWE_BROKEN_CRYPTO,
148
+ message: "Finite-field Diffie-Hellman via the Rust `openssl` crate is broken by Shor's algorithm (harvest-now-decrypt-later).",
149
+ };
150
+ const RULE_RUST_RING_X25519 = {
151
+ id: "rust-ring-x25519",
152
+ title: "Rust ring X25519 key agreement",
153
+ description: "ring agreement::X25519",
154
+ category: "key-exchange",
155
+ severity: "medium",
156
+ confidence: "high",
157
+ algorithm: "X25519",
158
+ hndl: true,
159
+ cwe: CWE_BROKEN_CRYPTO,
160
+ message: "X25519 key agreement via ring (Rust) is modern but still classical — harvest-now-decrypt-later.",
161
+ };
162
+ const RULE_RUST_BARE_X25519 = {
163
+ id: "rust-x25519-bare",
164
+ title: "Rust X25519 key agreement (unqualified)",
165
+ description: "bare EphemeralSecret::new (x25519-dalek imported via `use`)",
166
+ category: "key-exchange",
167
+ severity: "medium",
168
+ confidence: "medium",
169
+ algorithm: "X25519",
170
+ hndl: true,
171
+ cwe: CWE_BROKEN_CRYPTO,
172
+ message: "X25519 key agreement (x25519-dalek, imported unqualified) is modern but still classical — harvest-now-decrypt-later.",
173
+ };
174
+ const RULE_RUST_BARE_SIGNINGKEY = {
175
+ id: "rust-signingkey-bare",
176
+ title: "Rust signature key (unqualified)",
177
+ description: "bare SigningKey::generate/random (ed25519-dalek / k256 via `use`)",
178
+ category: "signature",
179
+ severity: "medium",
180
+ confidence: "medium",
181
+ algorithm: "unknown",
182
+ hndl: false,
183
+ cwe: CWE_BROKEN_CRYPTO,
184
+ message: "Classical signature key from an unqualified `SigningKey` (ed25519-dalek Ed25519 / k256 ECDSA) — forgeable by a quantum attacker.",
185
+ remediation: "ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)",
186
+ };
187
+ const RULE_RUST_JWT_ALGORITHM = {
188
+ id: "rust-jwt-algorithm",
189
+ title: "Rust jsonwebtoken classical signature algorithm",
190
+ description: "jsonwebtoken Algorithm::{RS,PS,ES}* / Algorithm::EdDSA enum variant",
191
+ category: "signature",
192
+ severity: "high",
193
+ confidence: "high",
194
+ // Representative family; refined per-finding (RS*/PS* → RSA, ES* → ECDSA, EdDSA).
195
+ algorithm: "RSA",
196
+ hndl: false,
197
+ cwe: CWE_BROKEN_CRYPTO,
198
+ message: "Selects a classical JWT signature algorithm (jsonwebtoken RS*/PS*/ES*/EdDSA), forgeable by a quantum attacker.",
199
+ remediation: "ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)",
200
+ };
201
+ const RULE_RUST_TLS_ACCEPT_INVALID = {
202
+ id: "rust-tls-accept-invalid-certs",
203
+ title: "Rust TLS certificate verification disabled",
204
+ description: "reqwest danger_accept_invalid_certs(true)",
205
+ category: "tls",
206
+ severity: "high",
207
+ confidence: "high",
208
+ hndl: false,
209
+ cwe: CWE_CERT_VALIDATION,
210
+ message: "danger_accept_invalid_certs(true) disables TLS certificate verification in reqwest (MITM risk).",
211
+ remediation: "Remove danger_accept_invalid_certs(true); verify certificates properly.",
212
+ };
213
+ const RULE_RUST_TLS_DANGEROUS = {
214
+ id: "rust-tls-rustls-dangerous",
215
+ title: "Rust rustls dangerous certificate config",
216
+ description: "rustls ClientConfig .dangerous() escape hatch",
217
+ category: "tls",
218
+ severity: "high",
219
+ confidence: "medium",
220
+ hndl: false,
221
+ cwe: CWE_CERT_VALIDATION,
222
+ message: "rustls `.dangerous()` opts into disabling certificate verification (MITM risk).",
223
+ remediation: "Avoid the dangerous() escape hatch; keep the default certificate verifier.",
224
+ };
75
225
  /** Detects classical asymmetric crypto in Rust (rsa, ring, dalek, p256/k256). */
76
226
  export const rustDetector = {
77
227
  id: "rust-crypto",
78
228
  description: "Classical asymmetric crypto in Rust (rsa, ring, *-dalek, p256/k256)",
79
229
  scope: "source",
80
230
  language: "rust",
81
- rules: [RULE_RUST_RSA, RULE_RUST_ECDSA, RULE_RUST_ECDH, RULE_RUST_ED25519, RULE_RUST_X25519],
231
+ rules: [
232
+ RULE_RUST_RSA,
233
+ RULE_RUST_ECDSA,
234
+ RULE_RUST_ECDH,
235
+ RULE_RUST_ED25519,
236
+ RULE_RUST_X25519,
237
+ RULE_RUST_OPENSSL_RSA,
238
+ RULE_RUST_OPENSSL_EC,
239
+ RULE_RUST_OPENSSL_DSA,
240
+ RULE_RUST_OPENSSL_DH,
241
+ RULE_RUST_RING_X25519,
242
+ RULE_RUST_BARE_X25519,
243
+ RULE_RUST_BARE_SIGNINGKEY,
244
+ RULE_RUST_JWT_ALGORITHM,
245
+ RULE_RUST_TLS_ACCEPT_INVALID,
246
+ RULE_RUST_TLS_DANGEROUS,
247
+ ],
82
248
  appliesTo: (f) => hasExtension(f, RUST_EXTENSIONS),
83
249
  detect({ file, content }) {
84
250
  const findings = [];
@@ -88,6 +254,22 @@ export const rustDetector = {
88
254
  add(RE_RUST_ECDH, RULE_RUST_ECDH);
89
255
  add(RE_RUST_ED25519, RULE_RUST_ED25519);
90
256
  add(RE_RUST_X25519, RULE_RUST_X25519);
257
+ add(RE_RUST_OPENSSL_RSA, RULE_RUST_OPENSSL_RSA);
258
+ add(RE_RUST_OPENSSL_EC, RULE_RUST_OPENSSL_EC);
259
+ add(RE_RUST_OPENSSL_DSA, RULE_RUST_OPENSSL_DSA);
260
+ add(RE_RUST_OPENSSL_DH, RULE_RUST_OPENSSL_DH);
261
+ add(RE_RUST_RING_X25519, RULE_RUST_RING_X25519);
262
+ add(RE_RUST_BARE_X25519, RULE_RUST_BARE_X25519);
263
+ add(RE_RUST_BARE_SIGNINGKEY, RULE_RUST_BARE_SIGNINGKEY);
264
+ // jsonwebtoken Algorithm enum variants — resolve the family per match: the
265
+ // RS*/PS* variants are RSASSA (RSA), ES* is ECDSA, EdDSA is Ed25519.
266
+ eachMatch(RE_RUST_JWT_ALG, content, (m) => {
267
+ const prefix = m[1];
268
+ const algorithm = prefix === undefined ? "EdDSA" : prefix === "ES" ? "ECDSA" : "RSA";
269
+ findings.push(findingFromRule(RULE_RUST_JWT_ALGORITHM, { file, content, index: m.index, matchLength: m[0].length }, { algorithm }));
270
+ });
271
+ add(RE_RUST_TLS_ACCEPT_INVALID, RULE_RUST_TLS_ACCEPT_INVALID);
272
+ add(RE_RUST_TLS_DANGEROUS, RULE_RUST_TLS_DANGEROUS);
91
273
  return findings;
92
274
  },
93
275
  };
@@ -1 +1 @@
1
- {"version":3,"file":"rust.js","sourceRoot":"","sources":["../../src/detectors/rust.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rust.js","sourceRoot":"","sources":["../../src/detectors/rust.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Source-code detector for classical asymmetric cryptography in Rust. Covers the\n * common crypto crates: `rsa`, `ring`, the `*-dalek` family (ed25519/x25519),\n * the RustCrypto elliptic-curve crates (`p256`/`p384`/`k256`), and the `openssl`\n * crate bindings. Lexical, same strategy as the other packs; the `::` path\n * syntax makes the signals precise.\n *\n * HNDL: RSA encryption and (EC/X)DH key agreement are harvest-now-decrypt-later\n * exposed (hndl:true); ECDSA / DSA / Ed25519 signatures are hndl:false but\n * forgeable. `openssl::EcKey` keygen is ambiguous (feeds ECDSA + ECDH),\n * classified conservatively as key-exchange-capable (hndl:true). Also flags\n * Rust TLS certificate-validation bypasses (reqwest / rustls) — not quantum but\n * mirrors the JS tlsDetector's cert-validation category.\n */\nimport type { AlgorithmFamily, Detector, Finding, RuleMeta } from \"../types.js\";\nimport { RUST_EXTENSIONS, eachMatch, findingFromRule, hasExtension } from \"../detect-utils.js\";\nimport { CWE_BROKEN_CRYPTO, CWE_CERT_VALIDATION } from \"../cwe.js\";\n\n// `rsa` crate + ring RsaKeyPair. `::` after the type marks an associated-fn call.\nconst RE_RUST_RSA = /\\b(?:RsaPrivateKey|RsaPublicKey|RsaKeyPair)::/g;\n// ECDSA: RustCrypto `p256::ecdsa::SigningKey` (contains `ecdsa::SigningKey`),\n// ring `EcdsaKeyPair::`, or a bare `ecdsa::SigningKey`.\nconst RE_RUST_ECDSA = /\\becdsa::SigningKey\\b|\\bEcdsaKeyPair::/g;\n// ECDH: RustCrypto `p256::ecdh::EphemeralSecret`, ring agreement / ECDH_P*.\nconst RE_RUST_ECDH = /\\becdh::EphemeralSecret\\b|\\bagreement::ECDH_P(?:256|384)\\b/g;\n// Ed25519 signatures (dalek + ring).\nconst RE_RUST_ED25519 = /\\bed25519_dalek::(?:SigningKey|Keypair|SecretKey)\\b|\\bEd25519KeyPair::/g;\n// X25519 key agreement (dalek).\nconst RE_RUST_X25519 = /\\bx25519_dalek::(?:EphemeralSecret|StaticSecret)\\b/g;\n// openssl crate bindings — the `Type::generate(` / `Dh::` call forms, distinct\n// from the ring / RustCrypto path syntax above (audit F5/F9 false-negatives).\nconst RE_RUST_OPENSSL_RSA = /\\bRsa::generate\\s*\\(/g;\nconst RE_RUST_OPENSSL_EC = /\\bEcKey::generate\\s*\\(/g;\nconst RE_RUST_OPENSSL_DSA = /\\bDsa::generate\\s*\\(/g;\nconst RE_RUST_OPENSSL_DH = /\\bDh::/g;\n// ring X25519 agreement (the ECDH_P* forms are handled by RE_RUST_ECDH above).\nconst RE_RUST_RING_X25519 = /\\bagreement::X25519\\b/g;\n// Bare (unqualified) constructors: a braced `use x25519_dalek::{EphemeralSecret}`\n// / `use ed25519_dalek::{SigningKey}` strips the `::` path prefix, defeating the\n// path-qualified rules above. The `(?<![:\\w])` lookbehind keeps these from\n// double-matching the qualified forms (e.g. `p256::ecdsa::SigningKey::random`).\nconst RE_RUST_BARE_X25519 = /(?<![:\\w])EphemeralSecret::new\\s*\\(/g;\nconst RE_RUST_BARE_SIGNINGKEY = /(?<![:\\w])SigningKey::(?:generate|random)\\s*\\(/g;\n// jsonwebtoken crate `Algorithm` enum variants selecting a classical JWT signer:\n// RSASSA-PKCS1 (RS*), RSASSA-PSS (PS*), ECDSA (ES*), and Ed25519 (EdDSA). The\n// `\\s*` between `Algorithm` and `::` catches the variant split across lines /\n// routed through a helper (audit token_policy false-negative); the required\n// suffix keeps it off unrelated `Algorithm::` uses (e.g. `HS256` HMAC, which is\n// symmetric and not quantum-vulnerable, or `Algorithm::new`).\nconst RE_RUST_JWT_ALG = /\\bAlgorithm\\s*::(RS|PS|ES)(?:256|384|512)\\b|\\bAlgorithm\\s*::EdDSA\\b/g;\n// Rust TLS certificate-validation bypass: reqwest `danger_accept_invalid_certs`\n// and the rustls `.dangerous()` escape hatch. Mirrors the JS tlsDetector.\nconst RE_RUST_TLS_ACCEPT_INVALID = /\\bdanger_accept_invalid_certs\\s*\\(\\s*true/g;\nconst RE_RUST_TLS_DANGEROUS = /\\.dangerous\\s*\\(\\s*\\)/g;\n\nconst RULE_RUST_RSA: RuleMeta = {\n id: \"rust-rsa\",\n title: \"Rust RSA key/usage\",\n description: \"the `rsa` crate / ring RsaKeyPair\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Classical RSA (Rust) is not quantum-safe and RSA encryption is HNDL-exposed.\",\n};\nconst RULE_RUST_ECDSA: RuleMeta = {\n id: \"rust-ecdsa\",\n title: \"Rust ECDSA signature\",\n description: \"p256/p384/k256 ecdsa::SigningKey / ring EcdsaKeyPair\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Classical ECDSA signing (Rust) is forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n};\nconst RULE_RUST_ECDH: RuleMeta = {\n id: \"rust-ecdh\",\n title: \"Rust ECDH key agreement\",\n description: \"p256/p384 ecdh::EphemeralSecret / ring agreement\",\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 (Rust) is broken by Shor's algorithm (harvest-now-decrypt-later).\",\n};\nconst RULE_RUST_ED25519: RuleMeta = {\n id: \"rust-ed25519\",\n title: \"Rust Ed25519 signature\",\n description: \"ed25519-dalek SigningKey/Keypair / ring Ed25519KeyPair\",\n category: \"signature\",\n severity: \"low\",\n confidence: \"high\",\n algorithm: \"EdDSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"Ed25519 (Rust) is a modern but still classical signature scheme.\",\n};\nconst RULE_RUST_X25519: RuleMeta = {\n id: \"rust-x25519\",\n title: \"Rust X25519 key agreement\",\n description: \"x25519-dalek EphemeralSecret/StaticSecret\",\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"high\",\n algorithm: \"X25519\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message: \"X25519 (Rust) is modern but still classical key agreement — harvest-now-decrypt-later.\",\n};\nconst RULE_RUST_OPENSSL_RSA: RuleMeta = {\n id: \"rust-openssl-rsa\",\n title: \"Rust openssl RSA key generation\",\n description: \"openssl crate Rsa::generate\",\n category: \"kem\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"RSA\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Generates a classical RSA key pair via the Rust `openssl` crate — not quantum-safe and RSA encryption is HNDL-exposed.\",\n};\nconst RULE_RUST_OPENSSL_EC: RuleMeta = {\n id: \"rust-openssl-ec\",\n title: \"Rust openssl EC key generation\",\n description: \"openssl crate EcKey::generate\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"ECDH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Generates a classical EC key pair via the Rust `openssl` crate. EC keys feed 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};\nconst RULE_RUST_OPENSSL_DSA: RuleMeta = {\n id: \"rust-openssl-dsa\",\n title: \"Rust openssl DSA key/usage\",\n description: \"openssl crate Dsa::generate\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"DSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Classical DSA via the Rust `openssl` crate is deprecated and forgeable by a quantum attacker.\",\n remediation: \"Rotate off DSA and migrate to ML-DSA-65 (FIPS 204).\",\n};\nconst RULE_RUST_OPENSSL_DH: RuleMeta = {\n id: \"rust-openssl-dh\",\n title: \"Rust openssl Diffie-Hellman key exchange\",\n description: \"openssl crate Dh params / key generation\",\n category: \"key-exchange\",\n severity: \"high\",\n confidence: \"high\",\n algorithm: \"DH\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Finite-field Diffie-Hellman via the Rust `openssl` crate is broken by Shor's algorithm (harvest-now-decrypt-later).\",\n};\nconst RULE_RUST_RING_X25519: RuleMeta = {\n id: \"rust-ring-x25519\",\n title: \"Rust ring X25519 key agreement\",\n description: \"ring agreement::X25519\",\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 key agreement via ring (Rust) is modern but still classical — harvest-now-decrypt-later.\",\n};\nconst RULE_RUST_BARE_X25519: RuleMeta = {\n id: \"rust-x25519-bare\",\n title: \"Rust X25519 key agreement (unqualified)\",\n description: \"bare EphemeralSecret::new (x25519-dalek imported via `use`)\",\n category: \"key-exchange\",\n severity: \"medium\",\n confidence: \"medium\",\n algorithm: \"X25519\",\n hndl: true,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"X25519 key agreement (x25519-dalek, imported unqualified) is modern but still classical — harvest-now-decrypt-later.\",\n};\nconst RULE_RUST_BARE_SIGNINGKEY: RuleMeta = {\n id: \"rust-signingkey-bare\",\n title: \"Rust signature key (unqualified)\",\n description: \"bare SigningKey::generate/random (ed25519-dalek / k256 via `use`)\",\n category: \"signature\",\n severity: \"medium\",\n confidence: \"medium\",\n algorithm: \"unknown\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Classical signature key from an unqualified `SigningKey` (ed25519-dalek Ed25519 / k256 ECDSA) — forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n};\nconst RULE_RUST_JWT_ALGORITHM: RuleMeta = {\n id: \"rust-jwt-algorithm\",\n title: \"Rust jsonwebtoken classical signature algorithm\",\n description: \"jsonwebtoken Algorithm::{RS,PS,ES}* / Algorithm::EdDSA enum variant\",\n category: \"signature\",\n severity: \"high\",\n confidence: \"high\",\n // Representative family; refined per-finding (RS*/PS* → RSA, ES* → ECDSA, EdDSA).\n algorithm: \"RSA\",\n hndl: false,\n cwe: CWE_BROKEN_CRYPTO,\n message:\n \"Selects a classical JWT signature algorithm (jsonwebtoken RS*/PS*/ES*/EdDSA), forgeable by a quantum attacker.\",\n remediation: \"ML-DSA-65 (FIPS 204) or SLH-DSA (FIPS 205)\",\n};\nconst RULE_RUST_TLS_ACCEPT_INVALID: RuleMeta = {\n id: \"rust-tls-accept-invalid-certs\",\n title: \"Rust TLS certificate verification disabled\",\n description: \"reqwest danger_accept_invalid_certs(true)\",\n category: \"tls\",\n severity: \"high\",\n confidence: \"high\",\n hndl: false,\n cwe: CWE_CERT_VALIDATION,\n message:\n \"danger_accept_invalid_certs(true) disables TLS certificate verification in reqwest (MITM risk).\",\n remediation: \"Remove danger_accept_invalid_certs(true); verify certificates properly.\",\n};\nconst RULE_RUST_TLS_DANGEROUS: RuleMeta = {\n id: \"rust-tls-rustls-dangerous\",\n title: \"Rust rustls dangerous certificate config\",\n description: \"rustls ClientConfig .dangerous() escape hatch\",\n category: \"tls\",\n severity: \"high\",\n confidence: \"medium\",\n hndl: false,\n cwe: CWE_CERT_VALIDATION,\n message: \"rustls `.dangerous()` opts into disabling certificate verification (MITM risk).\",\n remediation: \"Avoid the dangerous() escape hatch; keep the default certificate verifier.\",\n};\n\n/** Detects classical asymmetric crypto in Rust (rsa, ring, dalek, p256/k256). */\nexport const rustDetector: Detector = {\n id: \"rust-crypto\",\n description: \"Classical asymmetric crypto in Rust (rsa, ring, *-dalek, p256/k256)\",\n scope: \"source\",\n language: \"rust\",\n rules: [\n RULE_RUST_RSA,\n RULE_RUST_ECDSA,\n RULE_RUST_ECDH,\n RULE_RUST_ED25519,\n RULE_RUST_X25519,\n RULE_RUST_OPENSSL_RSA,\n RULE_RUST_OPENSSL_EC,\n RULE_RUST_OPENSSL_DSA,\n RULE_RUST_OPENSSL_DH,\n RULE_RUST_RING_X25519,\n RULE_RUST_BARE_X25519,\n RULE_RUST_BARE_SIGNINGKEY,\n RULE_RUST_JWT_ALGORITHM,\n RULE_RUST_TLS_ACCEPT_INVALID,\n RULE_RUST_TLS_DANGEROUS,\n ],\n appliesTo: (f) => hasExtension(f, RUST_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 add(RE_RUST_RSA, RULE_RUST_RSA);\n add(RE_RUST_ECDSA, RULE_RUST_ECDSA);\n add(RE_RUST_ECDH, RULE_RUST_ECDH);\n add(RE_RUST_ED25519, RULE_RUST_ED25519);\n add(RE_RUST_X25519, RULE_RUST_X25519);\n add(RE_RUST_OPENSSL_RSA, RULE_RUST_OPENSSL_RSA);\n add(RE_RUST_OPENSSL_EC, RULE_RUST_OPENSSL_EC);\n add(RE_RUST_OPENSSL_DSA, RULE_RUST_OPENSSL_DSA);\n add(RE_RUST_OPENSSL_DH, RULE_RUST_OPENSSL_DH);\n add(RE_RUST_RING_X25519, RULE_RUST_RING_X25519);\n add(RE_RUST_BARE_X25519, RULE_RUST_BARE_X25519);\n add(RE_RUST_BARE_SIGNINGKEY, RULE_RUST_BARE_SIGNINGKEY);\n // jsonwebtoken Algorithm enum variants — resolve the family per match: the\n // RS*/PS* variants are RSASSA (RSA), ES* is ECDSA, EdDSA is Ed25519.\n eachMatch(RE_RUST_JWT_ALG, content, (m) => {\n const prefix = m[1];\n const algorithm: AlgorithmFamily =\n prefix === undefined ? \"EdDSA\" : prefix === \"ES\" ? \"ECDSA\" : \"RSA\";\n findings.push(\n findingFromRule(\n RULE_RUST_JWT_ALGORITHM,\n { file, content, index: m.index, matchLength: m[0].length },\n { algorithm },\n ),\n );\n });\n add(RE_RUST_TLS_ACCEPT_INVALID, RULE_RUST_TLS_ACCEPT_INVALID);\n add(RE_RUST_TLS_DANGEROUS, RULE_RUST_TLS_DANGEROUS);\n return findings;\n },\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/detectors/source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAs2B/D,0DAA0D;AAC1D,eAAO,MAAM,eAAe,EAAE,QAAQ,EAOrC,CAAC"}
1
+ {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/detectors/source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AA4/B/D,0DAA0D;AAC1D,eAAO,MAAM,eAAe,EAAE,QAAQ,EAQrC,CAAC"}