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.
- package/dist/analysis/config-loader.d.ts.map +1 -1
- package/dist/analysis/config-loader.js +9 -19
- package/dist/analysis/config-loader.js.map +1 -1
- package/dist/analysis/passes/insecure-cookie-pass.d.ts +23 -23
- package/dist/analysis/passes/insecure-cookie-pass.d.ts.map +1 -1
- package/dist/analysis/passes/insecure-cookie-pass.js +169 -79
- package/dist/analysis/passes/insecure-cookie-pass.js.map +1 -1
- package/dist/analysis/passes/tls-verify-disabled-pass.d.ts +52 -0
- package/dist/analysis/passes/tls-verify-disabled-pass.d.ts.map +1 -0
- package/dist/analysis/passes/tls-verify-disabled-pass.js +247 -0
- package/dist/analysis/passes/tls-verify-disabled-pass.js.map +1 -0
- package/dist/analysis/passes/weak-crypto-pass.d.ts +49 -0
- package/dist/analysis/passes/weak-crypto-pass.d.ts.map +1 -0
- package/dist/analysis/passes/weak-crypto-pass.js +223 -0
- package/dist/analysis/passes/weak-crypto-pass.js.map +1 -0
- package/dist/analysis/passes/weak-hash-pass.d.ts +45 -0
- package/dist/analysis/passes/weak-hash-pass.d.ts.map +1 -0
- package/dist/analysis/passes/weak-hash-pass.js +150 -0
- package/dist/analysis/passes/weak-hash-pass.js.map +1 -0
- package/dist/analysis/passes/weak-random-pass.d.ts +53 -0
- package/dist/analysis/passes/weak-random-pass.d.ts.map +1 -0
- package/dist/analysis/passes/weak-random-pass.js +181 -0
- package/dist/analysis/passes/weak-random-pass.js.map +1 -0
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +12 -0
- package/dist/analyzer.js.map +1 -1
- package/dist/browser/circle-ir.js +747 -50
- package/dist/core/circle-ir-core.cjs +9 -19
- package/dist/core/circle-ir-core.js +9 -19
- 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"}
|