circle-ir 3.51.0 → 3.52.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 (30) hide show
  1. package/dist/analysis/config-loader.d.ts.map +1 -1
  2. package/dist/analysis/config-loader.js +9 -19
  3. package/dist/analysis/config-loader.js.map +1 -1
  4. package/dist/analysis/passes/insecure-cookie-pass.d.ts +23 -23
  5. package/dist/analysis/passes/insecure-cookie-pass.d.ts.map +1 -1
  6. package/dist/analysis/passes/insecure-cookie-pass.js +169 -79
  7. package/dist/analysis/passes/insecure-cookie-pass.js.map +1 -1
  8. package/dist/analysis/passes/tls-verify-disabled-pass.d.ts +52 -0
  9. package/dist/analysis/passes/tls-verify-disabled-pass.d.ts.map +1 -0
  10. package/dist/analysis/passes/tls-verify-disabled-pass.js +247 -0
  11. package/dist/analysis/passes/tls-verify-disabled-pass.js.map +1 -0
  12. package/dist/analysis/passes/weak-crypto-pass.d.ts +49 -0
  13. package/dist/analysis/passes/weak-crypto-pass.d.ts.map +1 -0
  14. package/dist/analysis/passes/weak-crypto-pass.js +223 -0
  15. package/dist/analysis/passes/weak-crypto-pass.js.map +1 -0
  16. package/dist/analysis/passes/weak-hash-pass.d.ts +45 -0
  17. package/dist/analysis/passes/weak-hash-pass.d.ts.map +1 -0
  18. package/dist/analysis/passes/weak-hash-pass.js +150 -0
  19. package/dist/analysis/passes/weak-hash-pass.js.map +1 -0
  20. package/dist/analysis/passes/weak-random-pass.d.ts +53 -0
  21. package/dist/analysis/passes/weak-random-pass.d.ts.map +1 -0
  22. package/dist/analysis/passes/weak-random-pass.js +181 -0
  23. package/dist/analysis/passes/weak-random-pass.js.map +1 -0
  24. package/dist/analyzer.d.ts.map +1 -1
  25. package/dist/analyzer.js +12 -0
  26. package/dist/analyzer.js.map +1 -1
  27. package/dist/browser/circle-ir.js +747 -50
  28. package/dist/core/circle-ir-core.cjs +9 -19
  29. package/dist/core/circle-ir-core.js +9 -19
  30. package/package.json +1 -1
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Pass: tls-verify-disabled (CWE-295, category: security)
3
+ *
4
+ * Pattern pass — flags places where TLS certificate / hostname verification
5
+ * is explicitly disabled. This is a *configuration* vulnerability (the bad
6
+ * value is hard-coded, no taint flow is involved).
7
+ *
8
+ * Detection per language:
9
+ * Go:
10
+ * - `&tls.Config{InsecureSkipVerify: true}` (composite literal)
11
+ * - Detected via call argument scan: when the receiver is `tls` and
12
+ * call/composite contains literal `InsecureSkipVerify: true`, OR via
13
+ * a syntactic text scan (composite literals are not always emitted
14
+ * as calls in IR).
15
+ * Python:
16
+ * - `requests.get|post|put|delete|patch|head|options|request(..., verify=False)`
17
+ * - `ssl._create_unverified_context()` / `ssl._create_default_https_context = ssl._create_unverified_context`
18
+ * - `urllib3.disable_warnings(InsecureRequestWarning)` — best-effort hint
19
+ * - `httpx.Client(verify=False)` / `httpx.get(..., verify=False)`
20
+ * JavaScript / TypeScript:
21
+ * - `{ rejectUnauthorized: false }` in https.request / fetch options /
22
+ * node-fetch / axios — text scan on arg expressions
23
+ * - `https.Agent({ rejectUnauthorized: false })`
24
+ * - `process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'` (assignment;
25
+ * detected via call to property assignment — best-effort)
26
+ * Java:
27
+ * - Custom `HostnameVerifier` that returns true unconditionally
28
+ * (lambdas `(h, s) -> true` / anonymous classes) — detected via
29
+ * textual scan on setHostnameVerifier arg expression.
30
+ * - `setHostnameVerifier(NoopHostnameVerifier.INSTANCE)` /
31
+ * `setHostnameVerifier(new AllowAllHostnameVerifier())`
32
+ *
33
+ * Aligned with: gosec G402 (Go), Bandit B501/B502/B504/B505 (Python).
34
+ */
35
+ // Python HTTP libraries whose calls accept a verify=False kwarg.
36
+ const PY_HTTP_METHODS = new Set([
37
+ 'get', 'post', 'put', 'delete', 'patch', 'head', 'options', 'request',
38
+ 'send',
39
+ ]);
40
+ const PY_HTTP_RECEIVERS = new Set([
41
+ 'requests', 'httpx',
42
+ ]);
43
+ const VERIFY_FALSE_RE = /\bverify\s*=\s*False\b/;
44
+ const REJECT_UNAUTHORIZED_FALSE_RE = /\brejectUnauthorized\s*:\s*false\b/;
45
+ const INSECURE_SKIP_VERIFY_TRUE_RE = /\bInsecureSkipVerify\s*:\s*true\b/;
46
+ const HOSTNAME_LAMBDA_TRUE_RE = /\(\s*\w+\s*,\s*\w+\s*\)\s*->\s*true\b/;
47
+ const ALLOW_ALL_HOSTNAME_VERIFIERS = new Set([
48
+ 'NoopHostnameVerifier.INSTANCE',
49
+ 'new AllowAllHostnameVerifier()',
50
+ 'new NoopHostnameVerifier()',
51
+ ]);
52
+ export class TlsVerifyDisabledPass {
53
+ name = 'tls-verify-disabled';
54
+ category = 'security';
55
+ run(ctx) {
56
+ const { graph, language, code } = ctx;
57
+ const file = graph.ir.meta.file;
58
+ const findings = [];
59
+ // Call-based detection (most precise — uses arg.expression text).
60
+ for (const call of graph.ir.calls) {
61
+ const det = this.detectCall(call, language);
62
+ if (!det)
63
+ continue;
64
+ const line = call.location.line;
65
+ findings.push({ line, language, ...det });
66
+ ctx.addFinding({
67
+ id: `${this.name}-${file}-${line}-${det.pattern}`,
68
+ pass: this.name,
69
+ category: this.category,
70
+ rule_id: this.name,
71
+ cwe: 'CWE-295',
72
+ severity: 'high',
73
+ level: 'error',
74
+ message: `TLS certificate verification disabled via \`${det.pattern}\` in ` +
75
+ `\`${det.api}\`. The connection becomes vulnerable to active ` +
76
+ 'man-in-the-middle attacks — any attacker on the network path can ' +
77
+ 'present a forged certificate.',
78
+ file,
79
+ line,
80
+ fix: this.fixFor(language, det.pattern),
81
+ evidence: { ...det, language },
82
+ });
83
+ }
84
+ // Source-text scan for composite-literal / module-level patterns that
85
+ // do not surface as IR calls (Go `tls.Config{}`, Python ssl globals,
86
+ // Node `NODE_TLS_REJECT_UNAUTHORIZED`).
87
+ for (const extra of this.detectSourceText(code, language)) {
88
+ const dupKey = `${extra.line}-${extra.pattern}`;
89
+ if (findings.some((f) => `${f.line}-${f.pattern}` === dupKey))
90
+ continue;
91
+ findings.push({ ...extra, language });
92
+ ctx.addFinding({
93
+ id: `${this.name}-${file}-${extra.line}-${extra.pattern}`,
94
+ pass: this.name,
95
+ category: this.category,
96
+ rule_id: this.name,
97
+ cwe: 'CWE-295',
98
+ severity: 'high',
99
+ level: 'error',
100
+ message: `TLS certificate verification disabled via \`${extra.pattern}\` ` +
101
+ `(${extra.api}). Vulnerable to active man-in-the-middle.`,
102
+ file,
103
+ line: extra.line,
104
+ fix: this.fixFor(language, extra.pattern),
105
+ evidence: { ...extra, language },
106
+ });
107
+ }
108
+ return { findings };
109
+ }
110
+ detectCall(call, language) {
111
+ const method = call.method_name;
112
+ const receiver = call.receiver ?? '';
113
+ if (language === 'python') {
114
+ // requests.get(..., verify=False) etc.
115
+ if (PY_HTTP_RECEIVERS.has(receiver) && PY_HTTP_METHODS.has(method)) {
116
+ for (const arg of call.arguments) {
117
+ const expr = (arg.expression ?? '').trim();
118
+ if (VERIFY_FALSE_RE.test(expr)) {
119
+ return { pattern: 'verify=False', api: `${receiver}.${method}` };
120
+ }
121
+ }
122
+ }
123
+ // ssl._create_unverified_context()
124
+ if (method === '_create_unverified_context' && receiver === 'ssl') {
125
+ return { pattern: 'ssl._create_unverified_context', api: 'ssl._create_unverified_context()' };
126
+ }
127
+ // httpx.Client(verify=False) — same shape via constructor; receiver is module.
128
+ if (receiver === 'httpx' && method === 'Client') {
129
+ for (const arg of call.arguments) {
130
+ if (VERIFY_FALSE_RE.test(arg.expression ?? '')) {
131
+ return { pattern: 'verify=False', api: 'httpx.Client' };
132
+ }
133
+ }
134
+ }
135
+ return null;
136
+ }
137
+ if (language === 'javascript' || language === 'typescript') {
138
+ // axios.create({httpsAgent: new https.Agent({rejectUnauthorized: false})}),
139
+ // https.request({rejectUnauthorized: false}, ...), fetch(url, {agent: ...})
140
+ // We do an arg-expression text scan because the option commonly appears
141
+ // inside an inline object literal.
142
+ //
143
+ // The JS plugin sometimes surfaces `new https.Agent(...)` with
144
+ // method_name='https.Agent' and receiver=null (rather than receiver='https',
145
+ // method='Agent'). Accept the trailing segment of the dotted name too.
146
+ const lastSeg = method.includes('.') ? method.split('.').pop() ?? '' : method;
147
+ const arglooks = method === 'request' || method === 'get' || method === 'post' ||
148
+ method === 'create' || method === 'Agent' || method === 'fetch' ||
149
+ lastSeg === 'Agent' || lastSeg === 'request' || lastSeg === 'create';
150
+ if (arglooks) {
151
+ for (const arg of call.arguments) {
152
+ if (REJECT_UNAUTHORIZED_FALSE_RE.test(arg.expression ?? '')) {
153
+ return { pattern: 'rejectUnauthorized: false', api: `${receiver || '(global)'}.${method}` };
154
+ }
155
+ }
156
+ }
157
+ return null;
158
+ }
159
+ if (language === 'java') {
160
+ // someConn.setHostnameVerifier((h, s) -> true)
161
+ if (method === 'setHostnameVerifier') {
162
+ const arg = call.arguments.find((a) => a.position === 0);
163
+ const expr = (arg?.expression ?? '').trim();
164
+ if (HOSTNAME_LAMBDA_TRUE_RE.test(expr)) {
165
+ return { pattern: '(h,s) -> true', api: 'setHostnameVerifier' };
166
+ }
167
+ for (const v of ALLOW_ALL_HOSTNAME_VERIFIERS) {
168
+ if (expr === v || expr.replace(/\s+/g, '') === v.replace(/\s+/g, '')) {
169
+ return { pattern: v, api: 'setHostnameVerifier' };
170
+ }
171
+ }
172
+ }
173
+ return null;
174
+ }
175
+ return null;
176
+ }
177
+ detectSourceText(code, language) {
178
+ const out = [];
179
+ const lines = code.split('\n');
180
+ if (language === 'go') {
181
+ // Look for `InsecureSkipVerify: true` literal anywhere — overwhelmingly
182
+ // appears in tls.Config{} composite literals.
183
+ for (let i = 0; i < lines.length; i++) {
184
+ if (INSECURE_SKIP_VERIFY_TRUE_RE.test(lines[i])) {
185
+ out.push({
186
+ line: i + 1,
187
+ pattern: 'InsecureSkipVerify: true',
188
+ api: 'tls.Config',
189
+ });
190
+ }
191
+ }
192
+ }
193
+ if (language === 'python') {
194
+ for (let i = 0; i < lines.length; i++) {
195
+ const l = lines[i];
196
+ if (/ssl\._create_default_https_context\s*=\s*ssl\._create_unverified_context/.test(l)) {
197
+ out.push({
198
+ line: i + 1,
199
+ pattern: 'ssl._create_default_https_context = _create_unverified_context',
200
+ api: 'ssl module override',
201
+ });
202
+ }
203
+ }
204
+ }
205
+ if (language === 'javascript' || language === 'typescript') {
206
+ for (let i = 0; i < lines.length; i++) {
207
+ const l = lines[i];
208
+ if (/process\.env\.NODE_TLS_REJECT_UNAUTHORIZED\s*=\s*['"]0['"]/.test(l)) {
209
+ out.push({
210
+ line: i + 1,
211
+ pattern: 'NODE_TLS_REJECT_UNAUTHORIZED=0',
212
+ api: 'process.env',
213
+ });
214
+ }
215
+ }
216
+ }
217
+ return out;
218
+ }
219
+ fixFor(language, pattern) {
220
+ if (pattern.includes('InsecureSkipVerify')) {
221
+ return 'Remove `InsecureSkipVerify: true` — let Go verify the cert. If ' +
222
+ 'you need to trust a private CA, set `RootCAs` to a `*x509.CertPool` ' +
223
+ 'containing that CA.';
224
+ }
225
+ if (pattern.includes('verify=False')) {
226
+ return 'Remove `verify=False`. To trust a private CA, pass `verify=\'/path/to/ca.pem\'`.';
227
+ }
228
+ if (pattern.includes('rejectUnauthorized')) {
229
+ return 'Remove `rejectUnauthorized: false`. To trust a private CA, set the ' +
230
+ '`ca` option to the CA cert(s). Never disable TLS verification globally.';
231
+ }
232
+ if (pattern.includes('NODE_TLS_REJECT_UNAUTHORIZED')) {
233
+ return 'Remove the `NODE_TLS_REJECT_UNAUTHORIZED=0` assignment — it globally ' +
234
+ 'disables TLS verification for every outbound HTTPS request.';
235
+ }
236
+ if (language === 'java') {
237
+ return 'Do not use an always-true HostnameVerifier or AllowAllHostnameVerifier. ' +
238
+ 'Use the JVM\'s default verifier; for self-signed certs add the cert to a ' +
239
+ 'custom TrustManager that validates the chain.';
240
+ }
241
+ if (pattern.includes('ssl._create_unverified_context')) {
242
+ return 'Do not use `_create_unverified_context()`. Use `ssl.create_default_context()`.';
243
+ }
244
+ return 'Restore TLS certificate and hostname verification.';
245
+ }
246
+ }
247
+ //# sourceMappingURL=tls-verify-disabled-pass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tls-verify-disabled-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/tls-verify-disabled-pass.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Pass: weak-crypto (CWE-327, 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
+ * and weak AES modes. Like weak-hash, the vulnerability is the *constant
7
+ * algorithm string* (or key-size argument), not data flow.
8
+ *
9
+ * Detection per language:
10
+ * Java:
11
+ * - `Cipher.getInstance("DES"|"DES/...")` / `"RC4"` / `"RC2"` / `"Blowfish"`
12
+ * - `Cipher.getInstance(".../ECB/...")` — ECB mode
13
+ * - `KeyGenerator.getInstance("DES"|"RC4"|"Blowfish")`
14
+ * - `KeyPairGenerator.getInstance("RSA")` followed by `initialize(<2048)`
15
+ * (the `.initialize(int)` literal under 2048 is detected directly when
16
+ * the receiver class is a generator)
17
+ * Python:
18
+ * - `Crypto.Cipher.DES.new(...)` / `Crypto.Cipher.ARC4.new(...)` /
19
+ * `Crypto.Cipher.Blowfish.new(...)` (pycryptodome / pycrypto)
20
+ * - `cryptography.hazmat.primitives.ciphers.algorithms.{TripleDES,Blowfish,ARC4,IDEA,SEED,CAST5}`
21
+ * - `AES.new(key, AES.MODE_ECB)` — ECB mode argument
22
+ * JavaScript / TypeScript:
23
+ * - `crypto.createCipher(...)` (deprecated; always weak)
24
+ * - `crypto.createCipheriv("des-..."|"rc4"|"bf-..."|"des-ede"|".*-ecb")`
25
+ * Go:
26
+ * - `des.NewCipher(...)` / `des.NewTripleDESCipher(...)` / `rc4.NewCipher(...)`
27
+ * (from `crypto/des` and `crypto/rc4`)
28
+ * - `cipher.NewECBEncrypter(...)` (custom ECB wrappers — best-effort)
29
+ *
30
+ * Aligned with: gosec G401/G405, Bandit B304/B305/B306, OWASP Benchmark `crypto` category.
31
+ */
32
+ import type { AnalysisPass, PassContext } from '../../graph/analysis-pass.js';
33
+ export interface WeakCryptoResult {
34
+ findings: Array<{
35
+ line: number;
36
+ language: string;
37
+ issue: 'weak-cipher' | 'ecb-mode' | 'deprecated-api';
38
+ detail: string;
39
+ api: string;
40
+ }>;
41
+ }
42
+ export declare class WeakCryptoPass implements AnalysisPass<WeakCryptoResult> {
43
+ readonly name = "weak-crypto";
44
+ readonly category: "security";
45
+ run(ctx: PassContext): WeakCryptoResult;
46
+ private buildMessage;
47
+ private detect;
48
+ }
49
+ //# sourceMappingURL=weak-crypto-pass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"weak-crypto-pass.d.ts","sourceRoot":"","sources":["../../../src/analysis/passes/weak-crypto-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AA4C9E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,aAAa,GAAG,UAAU,GAAG,gBAAgB,CAAC;QACrD,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC,CAAC;CACJ;AAED,qBAAa,cAAe,YAAW,YAAY,CAAC,gBAAgB,CAAC;IACnE,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,QAAQ,EAAG,UAAU,CAAU;IAExC,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,gBAAgB;IAmCvC,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,MAAM;CA2Gf"}
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Pass: weak-crypto (CWE-327, 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
+ * and weak AES modes. Like weak-hash, the vulnerability is the *constant
7
+ * algorithm string* (or key-size argument), not data flow.
8
+ *
9
+ * Detection per language:
10
+ * Java:
11
+ * - `Cipher.getInstance("DES"|"DES/...")` / `"RC4"` / `"RC2"` / `"Blowfish"`
12
+ * - `Cipher.getInstance(".../ECB/...")` — ECB mode
13
+ * - `KeyGenerator.getInstance("DES"|"RC4"|"Blowfish")`
14
+ * - `KeyPairGenerator.getInstance("RSA")` followed by `initialize(<2048)`
15
+ * (the `.initialize(int)` literal under 2048 is detected directly when
16
+ * the receiver class is a generator)
17
+ * Python:
18
+ * - `Crypto.Cipher.DES.new(...)` / `Crypto.Cipher.ARC4.new(...)` /
19
+ * `Crypto.Cipher.Blowfish.new(...)` (pycryptodome / pycrypto)
20
+ * - `cryptography.hazmat.primitives.ciphers.algorithms.{TripleDES,Blowfish,ARC4,IDEA,SEED,CAST5}`
21
+ * - `AES.new(key, AES.MODE_ECB)` — ECB mode argument
22
+ * JavaScript / TypeScript:
23
+ * - `crypto.createCipher(...)` (deprecated; always weak)
24
+ * - `crypto.createCipheriv("des-..."|"rc4"|"bf-..."|"des-ede"|".*-ecb")`
25
+ * Go:
26
+ * - `des.NewCipher(...)` / `des.NewTripleDESCipher(...)` / `rc4.NewCipher(...)`
27
+ * (from `crypto/des` and `crypto/rc4`)
28
+ * - `cipher.NewECBEncrypter(...)` (custom ECB wrappers — best-effort)
29
+ *
30
+ * Aligned with: gosec G401/G405, Bandit B304/B305/B306, OWASP Benchmark `crypto` category.
31
+ */
32
+ // Weak symmetric ciphers (algorithm name set, lowercased).
33
+ const WEAK_CIPHER_BASES = new Set([
34
+ 'des', '3des', 'desede', 'tripledes',
35
+ 'rc2', 'rc4', 'arc4',
36
+ 'blowfish', 'bf',
37
+ 'idea', 'seed', 'cast5',
38
+ ]);
39
+ // Java cipher transformation regex: "ALG/MODE/PADDING"; we look at base and mode.
40
+ function classifyJavaCipherSpec(spec) {
41
+ const parts = spec.split('/').map((p) => p.trim().toLowerCase());
42
+ const base = parts[0] ?? '';
43
+ const mode = parts[1] ?? '';
44
+ const result = {};
45
+ if (WEAK_CIPHER_BASES.has(base))
46
+ result.weakBase = base;
47
+ if (mode === 'ecb')
48
+ result.ecb = true;
49
+ // Java default when only base is given is ECB (Cipher.getInstance("AES") == AES/ECB/PKCS5).
50
+ if (parts.length === 1 && base === 'aes')
51
+ result.ecb = true;
52
+ return result;
53
+ }
54
+ function stripQuotes(s) {
55
+ const t = s.trim();
56
+ if ((t.startsWith('"') && t.endsWith('"')) ||
57
+ (t.startsWith("'") && t.endsWith("'")) ||
58
+ (t.startsWith('`') && t.endsWith('`'))) {
59
+ return t.slice(1, -1);
60
+ }
61
+ return t;
62
+ }
63
+ function literalAlgo(call, position) {
64
+ const arg = call.arguments.find((a) => a.position === position);
65
+ if (!arg)
66
+ return null;
67
+ const raw = arg.literal ?? arg.expression ?? '';
68
+ const cleaned = stripQuotes(raw);
69
+ return cleaned || null;
70
+ }
71
+ export class WeakCryptoPass {
72
+ name = 'weak-crypto';
73
+ category = 'security';
74
+ run(ctx) {
75
+ const { graph, language } = ctx;
76
+ const file = graph.ir.meta.file;
77
+ const findings = [];
78
+ for (const call of graph.ir.calls) {
79
+ const detections = this.detect(call, language);
80
+ for (const det of detections) {
81
+ const line = call.location.line;
82
+ findings.push({ line, language, ...det });
83
+ const message = this.buildMessage(det);
84
+ ctx.addFinding({
85
+ id: `${this.name}-${file}-${line}-${det.issue}`,
86
+ pass: this.name,
87
+ category: this.category,
88
+ rule_id: this.name,
89
+ cwe: 'CWE-327',
90
+ severity: 'high',
91
+ level: 'error',
92
+ message,
93
+ file,
94
+ line,
95
+ fix: 'Use AES-GCM (authenticated) or ChaCha20-Poly1305. Avoid DES, ' +
96
+ '3DES, RC2, RC4, Blowfish, and ECB mode. For asymmetric encryption ' +
97
+ 'use RSA-OAEP with ≥2048-bit keys or modern curve-based schemes.',
98
+ evidence: { ...det, language },
99
+ });
100
+ }
101
+ }
102
+ return { findings };
103
+ }
104
+ buildMessage(det) {
105
+ switch (det.issue) {
106
+ case 'weak-cipher':
107
+ return (`Weak symmetric cipher \`${det.detail.toUpperCase()}\` used via ` +
108
+ `\`${det.api}\`. DES, 3DES, RC2, RC4, Blowfish, and IDEA/SEED/CAST5 ` +
109
+ 'are deprecated and broken at modern key sizes.');
110
+ case 'ecb-mode':
111
+ return (`ECB block-cipher mode used via \`${det.api}\` (\`${det.detail}\`). ` +
112
+ 'ECB leaks plaintext structure (identical blocks → identical ciphertext) ' +
113
+ 'and is not semantically secure.');
114
+ case 'deprecated-api':
115
+ return (`Deprecated crypto API \`${det.api}\` used (no IV: \`${det.detail}\`). ` +
116
+ 'This API derives the key/IV from a password in an insecure way.');
117
+ default:
118
+ return `Weak cryptography: ${det.detail} (${det.api})`;
119
+ }
120
+ }
121
+ detect(call, language) {
122
+ const method = call.method_name;
123
+ const receiver = call.receiver ?? '';
124
+ const out = [];
125
+ if (language === 'java') {
126
+ // Cipher.getInstance(...) / KeyGenerator.getInstance(...)
127
+ const isCipherFactory = method === 'getInstance' &&
128
+ (receiver === 'Cipher' || receiver.endsWith('.Cipher') ||
129
+ receiver === 'KeyGenerator' || receiver.endsWith('.KeyGenerator'));
130
+ if (isCipherFactory) {
131
+ const spec = literalAlgo(call, 0);
132
+ if (spec) {
133
+ const { weakBase, ecb } = classifyJavaCipherSpec(spec);
134
+ const api = `${receiver}.getInstance`;
135
+ if (weakBase)
136
+ out.push({ issue: 'weak-cipher', detail: weakBase, api });
137
+ if (ecb)
138
+ out.push({ issue: 'ecb-mode', detail: spec, api });
139
+ }
140
+ }
141
+ return out;
142
+ }
143
+ if (language === 'python') {
144
+ // Crypto.Cipher.DES.new(...) / ARC4.new(...) / Blowfish.new(...)
145
+ // pycryptodome receiver shape: `Crypto.Cipher.DES` or just `DES` (after import).
146
+ if (method === 'new') {
147
+ const rcvLower = receiver.toLowerCase();
148
+ const lastSeg = rcvLower.split('.').pop() ?? rcvLower;
149
+ if (WEAK_CIPHER_BASES.has(lastSeg)) {
150
+ out.push({ issue: 'weak-cipher', detail: lastSeg, api: `${receiver}.new` });
151
+ }
152
+ // AES.new(key, AES.MODE_ECB) — ECB mode argument
153
+ if (lastSeg === 'aes' || lastSeg.endsWith('.aes')) {
154
+ const mode = call.arguments.find((a) => a.position === 1);
155
+ const modeExpr = (mode?.expression ?? '').trim();
156
+ if (/\bMODE_ECB\b/.test(modeExpr)) {
157
+ out.push({ issue: 'ecb-mode', detail: 'AES.MODE_ECB', api: `${receiver}.new` });
158
+ }
159
+ }
160
+ }
161
+ // cryptography.hazmat ciphers — algorithms.TripleDES(key) / Blowfish(key) / ARC4(key) / IDEA(key) / SEED(key) / CAST5(key)
162
+ // Receiver here is `algorithms` (or full path); method is the algo name.
163
+ const isHazmatAlgos = receiver === 'algorithms' || receiver.endsWith('.algorithms');
164
+ if (isHazmatAlgos) {
165
+ const m = method.toLowerCase();
166
+ const normalized = m === 'tripledes' ? '3des' : m;
167
+ if (WEAK_CIPHER_BASES.has(normalized)) {
168
+ out.push({ issue: 'weak-cipher', detail: normalized, api: `algorithms.${method}` });
169
+ }
170
+ }
171
+ return out;
172
+ }
173
+ if (language === 'javascript' || language === 'typescript') {
174
+ // crypto.createCipher(...) — deprecated, always weak (no IV).
175
+ if (method === 'createCipher' && receiver === 'crypto') {
176
+ const algo = literalAlgo(call, 0) ?? '<unknown>';
177
+ out.push({ issue: 'deprecated-api', detail: algo, api: 'crypto.createCipher' });
178
+ }
179
+ // crypto.createCipheriv("des-..."|"rc4"|"...-ecb"|...)
180
+ if (method === 'createCipheriv' && receiver === 'crypto') {
181
+ const algo = literalAlgo(call, 0);
182
+ if (algo) {
183
+ const lower = algo.toLowerCase();
184
+ // Split on dashes: "aes-128-ecb", "des-ede3-cbc", "rc4", "bf-cbc"
185
+ const parts = lower.split('-');
186
+ const base = parts[0];
187
+ const mode = parts[parts.length - 1];
188
+ let normalizedBase = base;
189
+ if (base === 'bf')
190
+ normalizedBase = 'blowfish';
191
+ if (base === 'desede' || base === 'des-ede3' || base === 'des3')
192
+ normalizedBase = '3des';
193
+ if (WEAK_CIPHER_BASES.has(normalizedBase)) {
194
+ out.push({ issue: 'weak-cipher', detail: normalizedBase, api: 'crypto.createCipheriv' });
195
+ }
196
+ if (mode === 'ecb') {
197
+ out.push({ issue: 'ecb-mode', detail: lower, api: 'crypto.createCipheriv' });
198
+ }
199
+ }
200
+ }
201
+ return out;
202
+ }
203
+ if (language === 'go') {
204
+ // crypto/des: des.NewCipher / des.NewTripleDESCipher
205
+ if (receiver === 'des' && (method === 'NewCipher' || method === 'NewTripleDESCipher')) {
206
+ const base = method === 'NewTripleDESCipher' ? '3des' : 'des';
207
+ out.push({ issue: 'weak-cipher', detail: base, api: `des.${method}` });
208
+ }
209
+ // crypto/rc4: rc4.NewCipher
210
+ if (receiver === 'rc4' && method === 'NewCipher') {
211
+ out.push({ issue: 'weak-cipher', detail: 'rc4', api: 'rc4.NewCipher' });
212
+ }
213
+ // ECB mode wrappers — cipher.NewECBEncrypter / NewECBDecrypter (custom helpers
214
+ // — Go stdlib intentionally omits ECB, so any such call is suspect).
215
+ if ((method === 'NewECBEncrypter' || method === 'NewECBDecrypter') && receiver === 'cipher') {
216
+ out.push({ issue: 'ecb-mode', detail: method, api: `cipher.${method}` });
217
+ }
218
+ return out;
219
+ }
220
+ return out;
221
+ }
222
+ }
223
+ //# 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"}