circle-ir 3.51.0 → 3.53.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 (35) hide show
  1. package/configs/sinks/path.yaml +0 -16
  2. package/configs/sources/file_sources.yaml +32 -0
  3. package/dist/analysis/config-loader.d.ts.map +1 -1
  4. package/dist/analysis/config-loader.js +17 -20
  5. package/dist/analysis/config-loader.js.map +1 -1
  6. package/dist/analysis/passes/insecure-cookie-pass.d.ts +23 -23
  7. package/dist/analysis/passes/insecure-cookie-pass.d.ts.map +1 -1
  8. package/dist/analysis/passes/insecure-cookie-pass.js +169 -79
  9. package/dist/analysis/passes/insecure-cookie-pass.js.map +1 -1
  10. package/dist/analysis/passes/tls-verify-disabled-pass.d.ts +52 -0
  11. package/dist/analysis/passes/tls-verify-disabled-pass.d.ts.map +1 -0
  12. package/dist/analysis/passes/tls-verify-disabled-pass.js +247 -0
  13. package/dist/analysis/passes/tls-verify-disabled-pass.js.map +1 -0
  14. package/dist/analysis/passes/weak-crypto-pass.d.ts +59 -0
  15. package/dist/analysis/passes/weak-crypto-pass.d.ts.map +1 -0
  16. package/dist/analysis/passes/weak-crypto-pass.js +392 -0
  17. package/dist/analysis/passes/weak-crypto-pass.js.map +1 -0
  18. package/dist/analysis/passes/weak-hash-pass.d.ts +45 -0
  19. package/dist/analysis/passes/weak-hash-pass.d.ts.map +1 -0
  20. package/dist/analysis/passes/weak-hash-pass.js +150 -0
  21. package/dist/analysis/passes/weak-hash-pass.js.map +1 -0
  22. package/dist/analysis/passes/weak-random-pass.d.ts +53 -0
  23. package/dist/analysis/passes/weak-random-pass.d.ts.map +1 -0
  24. package/dist/analysis/passes/weak-random-pass.js +181 -0
  25. package/dist/analysis/passes/weak-random-pass.js.map +1 -0
  26. package/dist/analysis/taint-matcher.d.ts.map +1 -1
  27. package/dist/analysis/taint-matcher.js +28 -13
  28. package/dist/analysis/taint-matcher.js.map +1 -1
  29. package/dist/analyzer.d.ts.map +1 -1
  30. package/dist/analyzer.js +12 -0
  31. package/dist/analyzer.js.map +1 -1
  32. package/dist/browser/circle-ir.js +852 -57
  33. package/dist/core/circle-ir-core.cjs +25 -26
  34. package/dist/core/circle-ir-core.js +25 -26
  35. package/package.json +1 -1
@@ -0,0 +1,392 @@
1
+ /**
2
+ * Pass: weak-crypto (CWE-327 / CWE-329 / CWE-321 / CWE-326, category: security)
3
+ *
4
+ * Pattern pass — flags use of cryptographically weak symmetric ciphers
5
+ * (DES, 3DES, RC2, RC4, Blowfish), ECB mode, weak RSA key sizes (< 2048),
6
+ * static/zero IVs (CWE-329), hardcoded symmetric keys (CWE-321), and weak
7
+ * AES modes. Like weak-hash, the vulnerability is the *constant algorithm
8
+ * string*, *constant IV bytes*, *literal key material*, or *key-size
9
+ * argument*, not data flow.
10
+ *
11
+ * Detection per language:
12
+ * Java:
13
+ * - `Cipher.getInstance("DES"|"DES/...")` / `"RC4"` / `"RC2"` / `"Blowfish"`
14
+ * - `Cipher.getInstance(".../ECB/...")` — ECB mode
15
+ * - `KeyGenerator.getInstance("DES"|"RC4"|"Blowfish")`
16
+ * - `new IvParameterSpec(new byte[N])` / `new IvParameterSpec(literalBytes)`
17
+ * — static/zero IV (CWE-329, issue #87)
18
+ * - `new SecretKeySpec("literal".getBytes(), ...)` — hardcoded symmetric
19
+ * key (CWE-321, issue #87)
20
+ * - `KeyPairGenerator.initialize(<2048)` — weak RSA key size (CWE-326,
21
+ * issue #87). Detected by literal `< 2048` argument on `initialize`
22
+ * calls whose receiver is a `KeyPairGenerator` (best-effort: matches
23
+ * any `*.initialize(int)` where the literal is below 2048, since
24
+ * 2048+ is also the minimum for DSA / DH and 256+ is correct for EC).
25
+ * Python:
26
+ * - `Crypto.Cipher.DES.new(...)` / `Crypto.Cipher.ARC4.new(...)` /
27
+ * `Crypto.Cipher.Blowfish.new(...)` (pycryptodome / pycrypto)
28
+ * - `cryptography.hazmat.primitives.ciphers.algorithms.{TripleDES,Blowfish,ARC4,IDEA,SEED,CAST5}`
29
+ * - `AES.new(key, AES.MODE_ECB)` — ECB mode argument
30
+ * JavaScript / TypeScript:
31
+ * - `crypto.createCipher(...)` (deprecated; always weak)
32
+ * - `crypto.createCipheriv("des-..."|"rc4"|"bf-..."|"des-ede"|".*-ecb")`
33
+ * Go:
34
+ * - `des.NewCipher(...)` / `des.NewTripleDESCipher(...)` / `rc4.NewCipher(...)`
35
+ * (from `crypto/des` and `crypto/rc4`)
36
+ * - `cipher.NewECBEncrypter(...)` (custom ECB wrappers — best-effort)
37
+ *
38
+ * Aligned with: gosec G401/G405, Bandit B304/B305/B306, OWASP Benchmark `crypto` category.
39
+ */
40
+ // Weak symmetric ciphers (algorithm name set, lowercased).
41
+ const WEAK_CIPHER_BASES = new Set([
42
+ 'des', '3des', 'desede', 'tripledes',
43
+ 'rc2', 'rc4', 'arc4',
44
+ 'blowfish', 'bf',
45
+ 'idea', 'seed', 'cast5',
46
+ ]);
47
+ // Java cipher transformation regex: "ALG/MODE/PADDING"; we look at base and mode.
48
+ function classifyJavaCipherSpec(spec) {
49
+ const parts = spec.split('/').map((p) => p.trim().toLowerCase());
50
+ const base = parts[0] ?? '';
51
+ const mode = parts[1] ?? '';
52
+ const result = {};
53
+ if (WEAK_CIPHER_BASES.has(base))
54
+ result.weakBase = base;
55
+ if (mode === 'ecb')
56
+ result.ecb = true;
57
+ // Java default when only base is given is ECB (Cipher.getInstance("AES") == AES/ECB/PKCS5).
58
+ if (parts.length === 1 && base === 'aes')
59
+ result.ecb = true;
60
+ return result;
61
+ }
62
+ function stripQuotes(s) {
63
+ const t = s.trim();
64
+ if ((t.startsWith('"') && t.endsWith('"')) ||
65
+ (t.startsWith("'") && t.endsWith("'")) ||
66
+ (t.startsWith('`') && t.endsWith('`'))) {
67
+ return t.slice(1, -1);
68
+ }
69
+ return t;
70
+ }
71
+ function literalAlgo(call, position) {
72
+ const arg = call.arguments.find((a) => a.position === position);
73
+ if (!arg)
74
+ return null;
75
+ const raw = arg.literal ?? arg.expression ?? '';
76
+ const cleaned = stripQuotes(raw);
77
+ return cleaned || null;
78
+ }
79
+ /**
80
+ * Detect a static or zero IV passed to `new IvParameterSpec(...)`.
81
+ *
82
+ * Patterns flagged (returns a human-readable detail string):
83
+ * - `new byte[N]` → "zero-filled byte[N]"
84
+ * - `new byte[]{0x00, 0x01,…}` → "literal byte[] {…}"
85
+ * - `"literal".getBytes()` → "literal string getBytes()"
86
+ * - bare string literal → "literal string"
87
+ *
88
+ * Returns null when the IV argument is a variable / method call whose
89
+ * value cannot be determined as a constant.
90
+ */
91
+ function detectStaticIvJava(call) {
92
+ const arg = call.arguments.find((a) => a.position === 0);
93
+ if (!arg)
94
+ return null;
95
+ const expr = (arg.literal ?? arg.expression ?? '').trim();
96
+ if (!expr)
97
+ return null;
98
+ // `new byte[16]` / `new byte[BLOCK_SIZE]` — zero-initialised array literal.
99
+ // Java initialises primitive arrays to zero, so a fresh `new byte[N]`
100
+ // (without an immediate assignment of random bytes) is always a zero IV.
101
+ if (/^new\s+byte\s*\[[^\]]*\]\s*$/.test(expr)) {
102
+ return `zero-filled ${expr}`;
103
+ }
104
+ // `new byte[]{0x00, …}` — literal byte array initializer.
105
+ if (/^new\s+byte\s*\[\s*\]\s*\{[^}]*\}\s*$/.test(expr)) {
106
+ return `literal byte[] initializer`;
107
+ }
108
+ // `"…".getBytes()` / `"…".getBytes("UTF-8")` — constant string source.
109
+ if (/^"[^"]*"\.getBytes\s*\(/.test(expr)) {
110
+ return `literal string .getBytes()`;
111
+ }
112
+ // Bare string literal (rare for IvParameterSpec but possible via overload).
113
+ if (/^"[^"]*"$/.test(expr)) {
114
+ return `literal string`;
115
+ }
116
+ return null;
117
+ }
118
+ /**
119
+ * Detect a hardcoded symmetric key passed to `new SecretKeySpec(...)`.
120
+ *
121
+ * Patterns flagged:
122
+ * - `"literalKey".getBytes()` → "literal string .getBytes()"
123
+ * - `"literalKey".getBytes("…")`
124
+ * - `new byte[]{0x00, …}` → "literal byte[] initializer"
125
+ * - bare string literal → "literal string"
126
+ *
127
+ * Returns null when the key argument is a variable, method call, or any
128
+ * other non-literal expression.
129
+ */
130
+ /**
131
+ * Recognise a Java constructor call to `new ClassName(...)`.
132
+ *
133
+ * The Java language plugin emits constructor calls as `CallInfo` with:
134
+ * method_name === ClassName
135
+ * receiver === null
136
+ * receiver_type === ClassName (or FQN tail)
137
+ *
138
+ * Match on that shape, plus the explicit `is_constructor` flag when set.
139
+ */
140
+ function isJavaCtor(call, className) {
141
+ if (call.is_constructor === true)
142
+ return true;
143
+ if (call.receiver)
144
+ return false;
145
+ if (call.receiver_type === className)
146
+ return true;
147
+ if ((call.receiver_type_fqn ?? '').endsWith('.' + className))
148
+ return true;
149
+ return false;
150
+ }
151
+ function detectHardcodedKeyJava(call) {
152
+ const arg = call.arguments.find((a) => a.position === 0);
153
+ if (!arg)
154
+ return null;
155
+ const expr = (arg.literal ?? arg.expression ?? '').trim();
156
+ if (!expr)
157
+ return null;
158
+ if (/^"[^"]*"\.getBytes\s*\(/.test(expr))
159
+ return `literal string .getBytes()`;
160
+ if (/^new\s+byte\s*\[\s*\]\s*\{[^}]*\}\s*$/.test(expr))
161
+ return `literal byte[] initializer`;
162
+ if (/^"[^"]*"$/.test(expr))
163
+ return `literal string`;
164
+ return null;
165
+ }
166
+ /** Map issue kind → CWE identifier. */
167
+ const ISSUE_CWE = {
168
+ 'weak-cipher': 'CWE-327',
169
+ 'ecb-mode': 'CWE-327',
170
+ 'deprecated-api': 'CWE-327',
171
+ 'static-iv': 'CWE-329',
172
+ 'hardcoded-key': 'CWE-321',
173
+ 'weak-rsa-key': 'CWE-326',
174
+ };
175
+ export class WeakCryptoPass {
176
+ name = 'weak-crypto';
177
+ category = 'security';
178
+ run(ctx) {
179
+ const { graph, language } = ctx;
180
+ const file = graph.ir.meta.file;
181
+ const findings = [];
182
+ for (const call of graph.ir.calls) {
183
+ const detections = this.detect(call, language);
184
+ for (const det of detections) {
185
+ const line = call.location.line;
186
+ findings.push({ line, language, ...det });
187
+ const message = this.buildMessage(det);
188
+ ctx.addFinding({
189
+ id: `${this.name}-${file}-${line}-${det.issue}`,
190
+ pass: this.name,
191
+ category: this.category,
192
+ rule_id: this.name,
193
+ cwe: ISSUE_CWE[det.issue],
194
+ severity: 'high',
195
+ level: 'error',
196
+ message,
197
+ file,
198
+ line,
199
+ fix: this.buildFix(det.issue),
200
+ evidence: { ...det, language },
201
+ });
202
+ }
203
+ }
204
+ return { findings };
205
+ }
206
+ buildMessage(det) {
207
+ switch (det.issue) {
208
+ case 'weak-cipher':
209
+ return (`Weak symmetric cipher \`${det.detail.toUpperCase()}\` used via ` +
210
+ `\`${det.api}\`. DES, 3DES, RC2, RC4, Blowfish, and IDEA/SEED/CAST5 ` +
211
+ 'are deprecated and broken at modern key sizes.');
212
+ case 'ecb-mode':
213
+ return (`ECB block-cipher mode used via \`${det.api}\` (\`${det.detail}\`). ` +
214
+ 'ECB leaks plaintext structure (identical blocks → identical ciphertext) ' +
215
+ 'and is not semantically secure.');
216
+ case 'deprecated-api':
217
+ return (`Deprecated crypto API \`${det.api}\` used (no IV: \`${det.detail}\`). ` +
218
+ 'This API derives the key/IV from a password in an insecure way.');
219
+ case 'static-iv':
220
+ return (`Static or zero-valued IV passed to \`${det.api}\` (\`${det.detail}\`). ` +
221
+ 'Reusing a fixed IV with CBC/CTR/GCM breaks confidentiality and, for ' +
222
+ 'GCM, can leak the authentication key.');
223
+ case 'hardcoded-key':
224
+ return (`Hardcoded symmetric key material passed to \`${det.api}\` (\`${det.detail}\`). ` +
225
+ 'Keys embedded in source code are trivially recoverable from binaries ' +
226
+ 'and shared across deployments — they provide no confidentiality.');
227
+ case 'weak-rsa-key':
228
+ return (`Weak RSA key size \`${det.detail}\` requested via \`${det.api}\`. ` +
229
+ 'RSA keys below 2048 bits are factorable and not compliant with ' +
230
+ 'NIST SP 800-57 / FIPS 186-5.');
231
+ default:
232
+ return `Weak cryptography: ${det.detail} (${det.api})`;
233
+ }
234
+ }
235
+ buildFix(issue) {
236
+ switch (issue) {
237
+ case 'static-iv':
238
+ return ('Generate a fresh random IV per message using SecureRandom: ' +
239
+ '`byte[] iv = new byte[12]; SecureRandom.getInstanceStrong().nextBytes(iv); ' +
240
+ 'new IvParameterSpec(iv);` and prepend it to the ciphertext.');
241
+ case 'hardcoded-key':
242
+ return ('Load the key from a secure key management system (HSM, KMS, ' +
243
+ 'Vault) or platform keystore. Never embed key material in source code.');
244
+ case 'weak-rsa-key':
245
+ return ('Initialize KeyPairGenerator with at least 2048 bits (preferably ' +
246
+ '3072 or 4096) for RSA, or switch to EC keys (P-256+).');
247
+ default:
248
+ return ('Use AES-GCM (authenticated) or ChaCha20-Poly1305. Avoid DES, ' +
249
+ '3DES, RC2, RC4, Blowfish, and ECB mode. For asymmetric encryption ' +
250
+ 'use RSA-OAEP with ≥2048-bit keys or modern curve-based schemes.');
251
+ }
252
+ }
253
+ detect(call, language) {
254
+ const method = call.method_name;
255
+ const receiver = call.receiver ?? '';
256
+ const out = [];
257
+ if (language === 'java') {
258
+ // Cipher.getInstance(...) / KeyGenerator.getInstance(...)
259
+ const isCipherFactory = method === 'getInstance' &&
260
+ (receiver === 'Cipher' || receiver.endsWith('.Cipher') ||
261
+ receiver === 'KeyGenerator' || receiver.endsWith('.KeyGenerator'));
262
+ if (isCipherFactory) {
263
+ const spec = literalAlgo(call, 0);
264
+ if (spec) {
265
+ const { weakBase, ecb } = classifyJavaCipherSpec(spec);
266
+ const api = `${receiver}.getInstance`;
267
+ if (weakBase)
268
+ out.push({ issue: 'weak-cipher', detail: weakBase, api });
269
+ if (ecb)
270
+ out.push({ issue: 'ecb-mode', detail: spec, api });
271
+ }
272
+ }
273
+ // new IvParameterSpec(...) — issue #87 (CWE-329 static IV)
274
+ // Java constructor IR shape: method_name === 'IvParameterSpec',
275
+ // receiver === null, receiver_type === 'IvParameterSpec'. The
276
+ // is_constructor flag is not always populated by the Java plugin,
277
+ // so detect by class-name match.
278
+ if (method === 'IvParameterSpec' && isJavaCtor(call, 'IvParameterSpec')) {
279
+ const ivDetail = detectStaticIvJava(call);
280
+ if (ivDetail) {
281
+ out.push({ issue: 'static-iv', detail: ivDetail, api: 'new IvParameterSpec' });
282
+ }
283
+ }
284
+ // new SecretKeySpec(literal.getBytes(), "ALG") — issue #87 (CWE-321 hardcoded key)
285
+ if (method === 'SecretKeySpec' && isJavaCtor(call, 'SecretKeySpec')) {
286
+ const keyDetail = detectHardcodedKeyJava(call);
287
+ if (keyDetail) {
288
+ out.push({ issue: 'hardcoded-key', detail: keyDetail, api: 'new SecretKeySpec' });
289
+ }
290
+ }
291
+ // kpg.initialize(<2048) — issue #87 (CWE-326 weak RSA key size)
292
+ // KeyPairGenerator instance method. Receiver_type === 'KeyPairGenerator'
293
+ // when the language plugin resolves it (post receiver-type matcher fix #52).
294
+ if (method === 'initialize') {
295
+ const isKpg = call.receiver_type === 'KeyPairGenerator' ||
296
+ (call.receiver_type_fqn ?? '').endsWith('.KeyPairGenerator');
297
+ if (isKpg) {
298
+ const sizeArg = call.arguments.find((a) => a.position === 0);
299
+ const expr = (sizeArg?.literal ?? sizeArg?.expression ?? '').trim();
300
+ const n = parseInt(expr, 10);
301
+ if (Number.isFinite(n) && n > 0 && n < 2048) {
302
+ out.push({
303
+ issue: 'weak-rsa-key',
304
+ detail: String(n),
305
+ api: 'KeyPairGenerator.initialize',
306
+ });
307
+ }
308
+ }
309
+ }
310
+ return out;
311
+ }
312
+ if (language === 'python') {
313
+ // Crypto.Cipher.DES.new(...) / ARC4.new(...) / Blowfish.new(...)
314
+ // pycryptodome receiver shape: `Crypto.Cipher.DES` or just `DES` (after import).
315
+ if (method === 'new') {
316
+ const rcvLower = receiver.toLowerCase();
317
+ const lastSeg = rcvLower.split('.').pop() ?? rcvLower;
318
+ if (WEAK_CIPHER_BASES.has(lastSeg)) {
319
+ out.push({ issue: 'weak-cipher', detail: lastSeg, api: `${receiver}.new` });
320
+ }
321
+ // AES.new(key, AES.MODE_ECB) — ECB mode argument
322
+ if (lastSeg === 'aes' || lastSeg.endsWith('.aes')) {
323
+ const mode = call.arguments.find((a) => a.position === 1);
324
+ const modeExpr = (mode?.expression ?? '').trim();
325
+ if (/\bMODE_ECB\b/.test(modeExpr)) {
326
+ out.push({ issue: 'ecb-mode', detail: 'AES.MODE_ECB', api: `${receiver}.new` });
327
+ }
328
+ }
329
+ }
330
+ // cryptography.hazmat ciphers — algorithms.TripleDES(key) / Blowfish(key) / ARC4(key) / IDEA(key) / SEED(key) / CAST5(key)
331
+ // Receiver here is `algorithms` (or full path); method is the algo name.
332
+ const isHazmatAlgos = receiver === 'algorithms' || receiver.endsWith('.algorithms');
333
+ if (isHazmatAlgos) {
334
+ const m = method.toLowerCase();
335
+ const normalized = m === 'tripledes' ? '3des' : m;
336
+ if (WEAK_CIPHER_BASES.has(normalized)) {
337
+ out.push({ issue: 'weak-cipher', detail: normalized, api: `algorithms.${method}` });
338
+ }
339
+ }
340
+ return out;
341
+ }
342
+ if (language === 'javascript' || language === 'typescript') {
343
+ // crypto.createCipher(...) — deprecated, always weak (no IV).
344
+ if (method === 'createCipher' && receiver === 'crypto') {
345
+ const algo = literalAlgo(call, 0) ?? '<unknown>';
346
+ out.push({ issue: 'deprecated-api', detail: algo, api: 'crypto.createCipher' });
347
+ }
348
+ // crypto.createCipheriv("des-..."|"rc4"|"...-ecb"|...)
349
+ if (method === 'createCipheriv' && receiver === 'crypto') {
350
+ const algo = literalAlgo(call, 0);
351
+ if (algo) {
352
+ const lower = algo.toLowerCase();
353
+ // Split on dashes: "aes-128-ecb", "des-ede3-cbc", "rc4", "bf-cbc"
354
+ const parts = lower.split('-');
355
+ const base = parts[0];
356
+ const mode = parts[parts.length - 1];
357
+ let normalizedBase = base;
358
+ if (base === 'bf')
359
+ normalizedBase = 'blowfish';
360
+ if (base === 'desede' || base === 'des-ede3' || base === 'des3')
361
+ normalizedBase = '3des';
362
+ if (WEAK_CIPHER_BASES.has(normalizedBase)) {
363
+ out.push({ issue: 'weak-cipher', detail: normalizedBase, api: 'crypto.createCipheriv' });
364
+ }
365
+ if (mode === 'ecb') {
366
+ out.push({ issue: 'ecb-mode', detail: lower, api: 'crypto.createCipheriv' });
367
+ }
368
+ }
369
+ }
370
+ return out;
371
+ }
372
+ if (language === 'go') {
373
+ // crypto/des: des.NewCipher / des.NewTripleDESCipher
374
+ if (receiver === 'des' && (method === 'NewCipher' || method === 'NewTripleDESCipher')) {
375
+ const base = method === 'NewTripleDESCipher' ? '3des' : 'des';
376
+ out.push({ issue: 'weak-cipher', detail: base, api: `des.${method}` });
377
+ }
378
+ // crypto/rc4: rc4.NewCipher
379
+ if (receiver === 'rc4' && method === 'NewCipher') {
380
+ out.push({ issue: 'weak-cipher', detail: 'rc4', api: 'rc4.NewCipher' });
381
+ }
382
+ // ECB mode wrappers — cipher.NewECBEncrypter / NewECBDecrypter (custom helpers
383
+ // — Go stdlib intentionally omits ECB, so any such call is suspect).
384
+ if ((method === 'NewECBEncrypter' || method === 'NewECBDecrypter') && receiver === 'cipher') {
385
+ out.push({ issue: 'ecb-mode', detail: method, api: `cipher.${method}` });
386
+ }
387
+ return out;
388
+ }
389
+ return out;
390
+ }
391
+ }
392
+ //# sourceMappingURL=weak-crypto-pass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"weak-crypto-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/weak-crypto-pass.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Pass: weak-hash (CWE-328, category: security)
3
+ *
4
+ * Pattern pass — flags use of cryptographically broken hash algorithms
5
+ * (MD2, MD4, MD5, SHA-1) for security purposes. The vulnerability is
6
+ * the *constant algorithm string*, not data flow: `MessageDigest.getInstance("MD5")`
7
+ * is always vulnerable regardless of input. Therefore this is implemented
8
+ * as call-site literal inspection, not as a taint sink.
9
+ *
10
+ * Detection per language:
11
+ * Java:
12
+ * - `MessageDigest.getInstance("MD5"|"SHA-1"|"SHA1"|"MD2"|"MD4")`
13
+ * - `DigestUtils.md5(...)` / `md5Hex(...)` / `sha1(...)` / `sha1Hex(...)`
14
+ * (Apache Commons Codec — method name encodes the algorithm)
15
+ * Python:
16
+ * - `hashlib.md5(...)` / `hashlib.sha1(...)` / `hashlib.md4(...)` / `hashlib.new("md5", ...)`
17
+ * JavaScript / TypeScript:
18
+ * - `crypto.createHash('md5'|'sha1'|'md4'|'md2')`
19
+ * - `crypto.createHmac('md5'|'sha1', key)`
20
+ * Go:
21
+ * - `md5.New()` / `md5.Sum(...)` / `sha1.New()` / `sha1.Sum(...)`
22
+ * (from `crypto/md5` and `crypto/sha1` packages)
23
+ *
24
+ * Aligned with: gosec G401, Bandit B303/B304, OWASP Benchmark `hash` category.
25
+ *
26
+ * Replaces (and supersedes) the broken taint-sink registration
27
+ * `{method:'getInstance', class:'MessageDigest', type:'weak_hash'}` that
28
+ * could never fire on a literal algorithm name.
29
+ */
30
+ import type { AnalysisPass, PassContext } from '../../graph/analysis-pass.js';
31
+ export interface WeakHashResult {
32
+ findings: Array<{
33
+ line: number;
34
+ language: string;
35
+ algorithm: string;
36
+ api: string;
37
+ }>;
38
+ }
39
+ export declare class WeakHashPass implements AnalysisPass<WeakHashResult> {
40
+ readonly name = "weak-hash";
41
+ readonly category: "security";
42
+ run(ctx: PassContext): WeakHashResult;
43
+ private detect;
44
+ }
45
+ //# sourceMappingURL=weak-hash-pass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"weak-hash-pass.d.ts","sourceRoot":"","sources":["../../../src/analysis/passes/weak-hash-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAoB9E,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,GAAG,EAAE,MAAM,CAAC;KACb,CAAC,CAAC;CACJ;AAsBD,qBAAa,YAAa,YAAW,YAAY,CAAC,cAAc,CAAC;IAC/D,QAAQ,CAAC,IAAI,eAAe;IAC5B,QAAQ,CAAC,QAAQ,EAAG,UAAU,CAAU;IAExC,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,cAAc;IAsCrC,OAAO,CAAC,MAAM;CA6Df"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Pass: weak-hash (CWE-328, category: security)
3
+ *
4
+ * Pattern pass — flags use of cryptographically broken hash algorithms
5
+ * (MD2, MD4, MD5, SHA-1) for security purposes. The vulnerability is
6
+ * the *constant algorithm string*, not data flow: `MessageDigest.getInstance("MD5")`
7
+ * is always vulnerable regardless of input. Therefore this is implemented
8
+ * as call-site literal inspection, not as a taint sink.
9
+ *
10
+ * Detection per language:
11
+ * Java:
12
+ * - `MessageDigest.getInstance("MD5"|"SHA-1"|"SHA1"|"MD2"|"MD4")`
13
+ * - `DigestUtils.md5(...)` / `md5Hex(...)` / `sha1(...)` / `sha1Hex(...)`
14
+ * (Apache Commons Codec — method name encodes the algorithm)
15
+ * Python:
16
+ * - `hashlib.md5(...)` / `hashlib.sha1(...)` / `hashlib.md4(...)` / `hashlib.new("md5", ...)`
17
+ * JavaScript / TypeScript:
18
+ * - `crypto.createHash('md5'|'sha1'|'md4'|'md2')`
19
+ * - `crypto.createHmac('md5'|'sha1', key)`
20
+ * Go:
21
+ * - `md5.New()` / `md5.Sum(...)` / `sha1.New()` / `sha1.Sum(...)`
22
+ * (from `crypto/md5` and `crypto/sha1` packages)
23
+ *
24
+ * Aligned with: gosec G401, Bandit B303/B304, OWASP Benchmark `hash` category.
25
+ *
26
+ * Replaces (and supersedes) the broken taint-sink registration
27
+ * `{method:'getInstance', class:'MessageDigest', type:'weak_hash'}` that
28
+ * could never fire on a literal algorithm name.
29
+ */
30
+ const WEAK_HASH_NAMES = new Set([
31
+ 'md2', 'md4', 'md5',
32
+ 'sha-1', 'sha1',
33
+ ]);
34
+ // Apache Commons Codec DigestUtils — method name encodes algorithm.
35
+ const COMMONS_DIGEST_METHODS = new Set([
36
+ 'md2', 'md2Hex',
37
+ 'md5', 'md5Hex',
38
+ 'sha1', 'sha1Hex',
39
+ // Apache Commons also has the misnamed `sha(...)` which is SHA-1
40
+ 'sha', 'shaHex',
41
+ ]);
42
+ // Python hashlib direct constructors
43
+ const PY_HASHLIB_WEAK = new Set(['md5', 'sha1', 'md4', 'md2', 'new']);
44
+ function stripQuotes(s) {
45
+ const trimmed = s.trim();
46
+ if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
47
+ (trimmed.startsWith("'") && trimmed.endsWith("'")) ||
48
+ (trimmed.startsWith('`') && trimmed.endsWith('`'))) {
49
+ return trimmed.slice(1, -1);
50
+ }
51
+ return trimmed;
52
+ }
53
+ function literalAlgo(call, position) {
54
+ const arg = call.arguments.find((a) => a.position === position);
55
+ if (!arg)
56
+ return null;
57
+ const raw = arg.literal ?? arg.expression ?? '';
58
+ const cleaned = stripQuotes(raw).toLowerCase();
59
+ return cleaned || null;
60
+ }
61
+ export class WeakHashPass {
62
+ name = 'weak-hash';
63
+ category = 'security';
64
+ run(ctx) {
65
+ const { graph, language } = ctx;
66
+ const file = graph.ir.meta.file;
67
+ const findings = [];
68
+ for (const call of graph.ir.calls) {
69
+ const detection = this.detect(call, language);
70
+ if (!detection)
71
+ continue;
72
+ const { algorithm, api } = detection;
73
+ const line = call.location.line;
74
+ findings.push({ line, language, algorithm, api });
75
+ ctx.addFinding({
76
+ id: `${this.name}-${file}-${line}`,
77
+ pass: this.name,
78
+ category: this.category,
79
+ rule_id: this.name,
80
+ cwe: 'CWE-328',
81
+ severity: 'medium',
82
+ level: 'warning',
83
+ message: `Weak hash algorithm \`${algorithm.toUpperCase()}\` used via \`${api}\`. ` +
84
+ 'MD2/MD4/MD5/SHA-1 are cryptographically broken and must not be used ' +
85
+ 'for passwords, signatures, integrity checks, or anywhere collision ' +
86
+ 'resistance is required.',
87
+ file,
88
+ line,
89
+ fix: 'Use SHA-256 or stronger (SHA-384, SHA-512, SHA-3). For passwords, ' +
90
+ 'use a password-hashing function: bcrypt, scrypt, Argon2, or PBKDF2.',
91
+ evidence: { algorithm, api, language },
92
+ });
93
+ }
94
+ return { findings };
95
+ }
96
+ detect(call, language) {
97
+ const method = call.method_name;
98
+ const receiver = call.receiver ?? '';
99
+ if (language === 'java') {
100
+ // MessageDigest.getInstance("MD5")
101
+ if (method === 'getInstance' && (receiver === 'MessageDigest' || receiver.endsWith('.MessageDigest'))) {
102
+ const algo = literalAlgo(call, 0);
103
+ if (algo && WEAK_HASH_NAMES.has(algo)) {
104
+ return { algorithm: algo, api: 'MessageDigest.getInstance' };
105
+ }
106
+ }
107
+ // Apache Commons Codec — DigestUtils.md5Hex(...), .sha1(...), etc.
108
+ if (COMMONS_DIGEST_METHODS.has(method) && (receiver === 'DigestUtils' || receiver.endsWith('.DigestUtils'))) {
109
+ const algoFromMethod = method.toLowerCase().replace(/hex$/, '');
110
+ const normalized = algoFromMethod === 'sha' ? 'sha1' : algoFromMethod;
111
+ return { algorithm: normalized, api: `DigestUtils.${method}` };
112
+ }
113
+ return null;
114
+ }
115
+ if (language === 'python') {
116
+ // hashlib.md5(...), .sha1(...), .md4(...), .md2(...)
117
+ if ((receiver === 'hashlib' || receiver.endsWith('.hashlib')) && PY_HASHLIB_WEAK.has(method)) {
118
+ if (method === 'new') {
119
+ const algo = literalAlgo(call, 0);
120
+ if (algo && WEAK_HASH_NAMES.has(algo)) {
121
+ return { algorithm: algo, api: 'hashlib.new' };
122
+ }
123
+ return null;
124
+ }
125
+ return { algorithm: method, api: `hashlib.${method}` };
126
+ }
127
+ return null;
128
+ }
129
+ if (language === 'javascript' || language === 'typescript') {
130
+ // crypto.createHash('md5') / crypto.createHmac('sha1', key)
131
+ if ((method === 'createHash' || method === 'createHmac') && receiver === 'crypto') {
132
+ const algo = literalAlgo(call, 0);
133
+ if (algo && WEAK_HASH_NAMES.has(algo)) {
134
+ return { algorithm: algo, api: `crypto.${method}` };
135
+ }
136
+ }
137
+ return null;
138
+ }
139
+ if (language === 'go') {
140
+ // md5.New() / md5.Sum(...) / sha1.New() / sha1.Sum(...)
141
+ const isWeakPkg = receiver === 'md5' || receiver === 'sha1';
142
+ if (isWeakPkg && (method === 'New' || method === 'Sum')) {
143
+ return { algorithm: receiver, api: `${receiver}.${method}` };
144
+ }
145
+ return null;
146
+ }
147
+ return null;
148
+ }
149
+ }
150
+ //# sourceMappingURL=weak-hash-pass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"weak-hash-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/weak-hash-pass.ts"],"names":[],"mappings":"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"}