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
|
@@ -1,30 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pass: insecure-cookie (CWE-614, category: security)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Pattern pass — flags cookie set operations that are missing the `Secure`
|
|
5
|
+
* or `HttpOnly` flags. This is a configuration/absence vulnerability (the
|
|
6
|
+
* cookie value itself does not need to be tainted), so it is detected by
|
|
7
|
+
* inspecting call-site option literals rather than via taint flow.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* 4. Flag if:
|
|
24
|
-
* - arg 2 is absent, OR
|
|
25
|
-
* - arg 2 does not contain `secure: true` (regex), OR
|
|
26
|
-
* - arg 2 does not contain `httpOnly: true` (regex).
|
|
27
|
-
* 5. Emit a single finding per call site listing the missing flags.
|
|
9
|
+
* Detection per language:
|
|
10
|
+
* JavaScript / TypeScript:
|
|
11
|
+
* - Express `res.cookie(name, value, options)` — flag if options object
|
|
12
|
+
* (arg 2) is absent OR does not literally contain `secure: true` and
|
|
13
|
+
* `httpOnly: true`.
|
|
14
|
+
* Python:
|
|
15
|
+
* - Flask / Django / Starlette `response.set_cookie(name, value, **kw)`
|
|
16
|
+
* — flag if `secure=True` and `httponly=True` keyword args are not
|
|
17
|
+
* present in the call expression text.
|
|
18
|
+
* Java:
|
|
19
|
+
* - `new javax.servlet.http.Cookie("name", "value")` — flag the
|
|
20
|
+
* construction site if no `.setSecure(true)` AND `.setHttpOnly(true)`
|
|
21
|
+
* calls appear in the same source file (text-based heuristic; a
|
|
22
|
+
* full DFG-based version would require tracking the assigned
|
|
23
|
+
* variable through CFG).
|
|
28
24
|
*
|
|
29
25
|
* Excluded (intentionally not flagged):
|
|
30
26
|
* - `res.clearCookie(...)` — clears, not sets.
|
|
@@ -49,5 +45,9 @@ export declare class InsecureCookiePass implements AnalysisPass<InsecureCookieRe
|
|
|
49
45
|
readonly name = "insecure-cookie";
|
|
50
46
|
readonly category: "security";
|
|
51
47
|
run(ctx: PassContext): InsecureCookieResult;
|
|
48
|
+
private detectJs;
|
|
49
|
+
private detectPython;
|
|
50
|
+
private detectJavaCookieCtor;
|
|
51
|
+
private emit;
|
|
52
52
|
}
|
|
53
53
|
//# sourceMappingURL=insecure-cookie-pass.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insecure-cookie-pass.d.ts","sourceRoot":"","sources":["../../../src/analysis/passes/insecure-cookie-pass.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"insecure-cookie-pass.d.ts","sourceRoot":"","sources":["../../../src/analysis/passes/insecure-cookie-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAqB9E,MAAM,WAAW,oBAAoB;IACnC,eAAe,EAAE,KAAK,CAAC;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,OAAO,CAAC;QACvB,eAAe,EAAE,OAAO,CAAC;QACzB,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC,CAAC;CACJ;AAED,qBAAa,kBAAmB,YAAW,YAAY,CAAC,oBAAoB,CAAC;IAC3E,QAAQ,CAAC,IAAI,qBAAqB;IAClC,QAAQ,CAAC,QAAQ,EAAG,UAAU,CAAU;IAExC,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,oBAAoB;IAqC3C,OAAO,CAAC,QAAQ;IA2BhB,OAAO,CAAC,YAAY;IAuBpB,OAAO,CAAC,oBAAoB;IA8B5B,OAAO,CAAC,IAAI;CAwCb"}
|
|
@@ -1,30 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pass: insecure-cookie (CWE-614, category: security)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Pattern pass — flags cookie set operations that are missing the `Secure`
|
|
5
|
+
* or `HttpOnly` flags. This is a configuration/absence vulnerability (the
|
|
6
|
+
* cookie value itself does not need to be tainted), so it is detected by
|
|
7
|
+
* inspecting call-site option literals rather than via taint flow.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* 4. Flag if:
|
|
24
|
-
* - arg 2 is absent, OR
|
|
25
|
-
* - arg 2 does not contain `secure: true` (regex), OR
|
|
26
|
-
* - arg 2 does not contain `httpOnly: true` (regex).
|
|
27
|
-
* 5. Emit a single finding per call site listing the missing flags.
|
|
9
|
+
* Detection per language:
|
|
10
|
+
* JavaScript / TypeScript:
|
|
11
|
+
* - Express `res.cookie(name, value, options)` — flag if options object
|
|
12
|
+
* (arg 2) is absent OR does not literally contain `secure: true` and
|
|
13
|
+
* `httpOnly: true`.
|
|
14
|
+
* Python:
|
|
15
|
+
* - Flask / Django / Starlette `response.set_cookie(name, value, **kw)`
|
|
16
|
+
* — flag if `secure=True` and `httponly=True` keyword args are not
|
|
17
|
+
* present in the call expression text.
|
|
18
|
+
* Java:
|
|
19
|
+
* - `new javax.servlet.http.Cookie("name", "value")` — flag the
|
|
20
|
+
* construction site if no `.setSecure(true)` AND `.setHttpOnly(true)`
|
|
21
|
+
* calls appear in the same source file (text-based heuristic; a
|
|
22
|
+
* full DFG-based version would require tracking the assigned
|
|
23
|
+
* variable through CFG).
|
|
28
24
|
*
|
|
29
25
|
* Excluded (intentionally not flagged):
|
|
30
26
|
* - `res.clearCookie(...)` — clears, not sets.
|
|
@@ -35,75 +31,169 @@
|
|
|
35
31
|
* We flag the call (RHS is opaque) unless `secure: true` and
|
|
36
32
|
* `httpOnly: true` appear literally. Users can suppress via config.
|
|
37
33
|
*/
|
|
34
|
+
// ---------- JS / TS ----------
|
|
38
35
|
const COOKIE_RESPONSE_RECEIVERS = new Set([
|
|
39
36
|
'res', 'response', 'reply',
|
|
40
37
|
]);
|
|
41
38
|
const SECURE_TRUE_RE = /\bsecure\s*:\s*true\b/;
|
|
42
39
|
const HTTPONLY_TRUE_RE = /\bhttpOnly\s*:\s*true\b/i;
|
|
40
|
+
// ---------- Python ----------
|
|
41
|
+
const PY_SET_COOKIE_RECEIVERS = new Set([
|
|
42
|
+
'response', 'resp', 'res',
|
|
43
|
+
]);
|
|
44
|
+
const PY_SECURE_TRUE_RE = /\bsecure\s*=\s*True\b/;
|
|
45
|
+
const PY_HTTPONLY_TRUE_RE = /\bhttponly\s*=\s*True\b/i;
|
|
46
|
+
// ---------- Java ----------
|
|
47
|
+
const JAVA_SET_SECURE_TRUE_RE = /\.setSecure\s*\(\s*true\s*\)/;
|
|
48
|
+
const JAVA_SET_HTTPONLY_TRUE_RE = /\.setHttpOnly\s*\(\s*true\s*\)/;
|
|
43
49
|
export class InsecureCookiePass {
|
|
44
50
|
name = 'insecure-cookie';
|
|
45
51
|
category = 'security';
|
|
46
52
|
run(ctx) {
|
|
47
|
-
const { graph, language } = ctx;
|
|
48
|
-
if (language !== 'javascript' && language !== 'typescript') {
|
|
49
|
-
return { insecureCookies: [] };
|
|
50
|
-
}
|
|
53
|
+
const { graph, language, code } = ctx;
|
|
51
54
|
const file = graph.ir.meta.file;
|
|
52
55
|
const insecureCookies = [];
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
id: `${this.name}-${file}-${line}`,
|
|
85
|
-
pass: this.name,
|
|
86
|
-
category: this.category,
|
|
87
|
-
rule_id: this.name,
|
|
88
|
-
cwe: 'CWE-614',
|
|
89
|
-
severity: 'medium',
|
|
90
|
-
level: 'warning',
|
|
91
|
-
message: `Cookie set without ${missing.join(' and ')} — vulnerable to ` +
|
|
92
|
-
`cleartext transmission (CWE-614) and client-side JS access ` +
|
|
93
|
-
`(CWE-1004).`,
|
|
94
|
-
file,
|
|
95
|
-
line,
|
|
96
|
-
fix: 'Pass `{ secure: true, httpOnly: true, sameSite: "lax" }` as the ' +
|
|
97
|
-
'third argument to `res.cookie()`.',
|
|
98
|
-
evidence: {
|
|
99
|
-
receiver,
|
|
100
|
-
options_present: optionsPresent,
|
|
101
|
-
missing_secure: missingSecure,
|
|
102
|
-
missing_http_only: missingHttpOnly,
|
|
103
|
-
},
|
|
104
|
-
});
|
|
56
|
+
if (language === 'javascript' || language === 'typescript') {
|
|
57
|
+
for (const call of graph.ir.calls) {
|
|
58
|
+
const det = this.detectJs(call);
|
|
59
|
+
if (!det)
|
|
60
|
+
continue;
|
|
61
|
+
insecureCookies.push(det);
|
|
62
|
+
this.emit(ctx, file, det, 'js');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else if (language === 'python') {
|
|
66
|
+
for (const call of graph.ir.calls) {
|
|
67
|
+
const det = this.detectPython(call);
|
|
68
|
+
if (!det)
|
|
69
|
+
continue;
|
|
70
|
+
insecureCookies.push(det);
|
|
71
|
+
this.emit(ctx, file, det, 'python');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else if (language === 'java') {
|
|
75
|
+
// Java text-based heuristic: detect `new Cookie(...)` constructor calls,
|
|
76
|
+
// then look in the file source for `.setSecure(true)` and `.setHttpOnly(true)`
|
|
77
|
+
// anywhere. Misses only when those setters exist in another file.
|
|
78
|
+
const hasSetSecureTrue = JAVA_SET_SECURE_TRUE_RE.test(code);
|
|
79
|
+
const hasSetHttpOnlyTrue = JAVA_SET_HTTPONLY_TRUE_RE.test(code);
|
|
80
|
+
for (const call of graph.ir.calls) {
|
|
81
|
+
const det = this.detectJavaCookieCtor(call, hasSetSecureTrue, hasSetHttpOnlyTrue);
|
|
82
|
+
if (!det)
|
|
83
|
+
continue;
|
|
84
|
+
insecureCookies.push(det);
|
|
85
|
+
this.emit(ctx, file, det, 'java');
|
|
86
|
+
}
|
|
105
87
|
}
|
|
106
88
|
return { insecureCookies };
|
|
107
89
|
}
|
|
90
|
+
// ---------------- JS / TS ----------------
|
|
91
|
+
detectJs(call) {
|
|
92
|
+
if (call.method_name !== 'cookie')
|
|
93
|
+
return null;
|
|
94
|
+
const receiver = call.receiver ?? '';
|
|
95
|
+
if (!COOKIE_RESPONSE_RECEIVERS.has(receiver))
|
|
96
|
+
return null;
|
|
97
|
+
// Must look like a setter call: at least (name, value) args.
|
|
98
|
+
// `res.cookie('name')` (Express getter form) takes one arg — skip.
|
|
99
|
+
if (call.arguments.length < 2)
|
|
100
|
+
return null;
|
|
101
|
+
const opts = call.arguments.find((a) => a.position === 2);
|
|
102
|
+
const optsExpr = (opts?.expression ?? '').trim();
|
|
103
|
+
const optionsPresent = optsExpr.length > 0;
|
|
104
|
+
const missingSecure = !SECURE_TRUE_RE.test(optsExpr);
|
|
105
|
+
const missingHttpOnly = !HTTPONLY_TRUE_RE.test(optsExpr);
|
|
106
|
+
if (!missingSecure && !missingHttpOnly)
|
|
107
|
+
return null;
|
|
108
|
+
return {
|
|
109
|
+
line: call.location.line,
|
|
110
|
+
receiver,
|
|
111
|
+
missingSecure,
|
|
112
|
+
missingHttpOnly,
|
|
113
|
+
optionsPresent,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
// ---------------- Python ----------------
|
|
117
|
+
detectPython(call) {
|
|
118
|
+
if (call.method_name !== 'set_cookie')
|
|
119
|
+
return null;
|
|
120
|
+
const receiver = call.receiver ?? '';
|
|
121
|
+
if (!PY_SET_COOKIE_RECEIVERS.has(receiver))
|
|
122
|
+
return null;
|
|
123
|
+
// Concatenate all argument expression text — keyword args may appear in
|
|
124
|
+
// any position past the leading positional args.
|
|
125
|
+
const argsBlob = call.arguments.map((a) => a.expression ?? '').join(', ');
|
|
126
|
+
const missingSecure = !PY_SECURE_TRUE_RE.test(argsBlob);
|
|
127
|
+
const missingHttpOnly = !PY_HTTPONLY_TRUE_RE.test(argsBlob);
|
|
128
|
+
if (!missingSecure && !missingHttpOnly)
|
|
129
|
+
return null;
|
|
130
|
+
return {
|
|
131
|
+
line: call.location.line,
|
|
132
|
+
receiver,
|
|
133
|
+
missingSecure,
|
|
134
|
+
missingHttpOnly,
|
|
135
|
+
optionsPresent: call.arguments.length >= 2,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
// ---------------- Java ----------------
|
|
139
|
+
detectJavaCookieCtor(call, hasSetSecureTrue, hasSetHttpOnlyTrue) {
|
|
140
|
+
// Java constructor: method_name === 'Cookie', receiver is null,
|
|
141
|
+
// receiver_type === 'Cookie' (set by the Java plugin). Some plugins
|
|
142
|
+
// also set call.is_constructor — accept any of the indicators.
|
|
143
|
+
if (call.method_name !== 'Cookie')
|
|
144
|
+
return null;
|
|
145
|
+
const looksLikeCtor = call.is_constructor ||
|
|
146
|
+
(!call.receiver && call.receiver_type === 'Cookie') ||
|
|
147
|
+
(call.resolution?.target ?? '').endsWith('.<init>');
|
|
148
|
+
if (!looksLikeCtor)
|
|
149
|
+
return null;
|
|
150
|
+
// Need at least (name, value).
|
|
151
|
+
if (call.arguments.length < 2)
|
|
152
|
+
return null;
|
|
153
|
+
const missingSecure = !hasSetSecureTrue;
|
|
154
|
+
const missingHttpOnly = !hasSetHttpOnlyTrue;
|
|
155
|
+
if (!missingSecure && !missingHttpOnly)
|
|
156
|
+
return null;
|
|
157
|
+
return {
|
|
158
|
+
line: call.location.line,
|
|
159
|
+
receiver: 'new Cookie',
|
|
160
|
+
missingSecure,
|
|
161
|
+
missingHttpOnly,
|
|
162
|
+
optionsPresent: false,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
emit(ctx, file, det, flavor) {
|
|
166
|
+
const missing = [];
|
|
167
|
+
if (det.missingSecure)
|
|
168
|
+
missing.push(flavor === 'js' ? '`secure: true`' : flavor === 'python' ? '`secure=True`' : '`setSecure(true)`');
|
|
169
|
+
if (det.missingHttpOnly)
|
|
170
|
+
missing.push(flavor === 'js' ? '`httpOnly: true`' : flavor === 'python' ? '`httponly=True`' : '`setHttpOnly(true)`');
|
|
171
|
+
const fix = flavor === 'js'
|
|
172
|
+
? 'Pass `{ secure: true, httpOnly: true, sameSite: "lax" }` as the third argument to `res.cookie()`.'
|
|
173
|
+
: flavor === 'python'
|
|
174
|
+
? 'Pass `secure=True, httponly=True, samesite="Lax"` to `response.set_cookie(...)`.'
|
|
175
|
+
: 'After constructing the cookie, call `cookie.setSecure(true)` and `cookie.setHttpOnly(true)` before adding it to the response.';
|
|
176
|
+
ctx.addFinding({
|
|
177
|
+
id: `${this.name}-${file}-${det.line}`,
|
|
178
|
+
pass: this.name,
|
|
179
|
+
category: this.category,
|
|
180
|
+
rule_id: this.name,
|
|
181
|
+
cwe: 'CWE-614',
|
|
182
|
+
severity: 'medium',
|
|
183
|
+
level: 'warning',
|
|
184
|
+
message: `Cookie set without ${missing.join(' and ')} — vulnerable to ` +
|
|
185
|
+
`cleartext transmission (CWE-614) and client-side JS access ` +
|
|
186
|
+
`(CWE-1004).`,
|
|
187
|
+
file,
|
|
188
|
+
line: det.line,
|
|
189
|
+
fix,
|
|
190
|
+
evidence: {
|
|
191
|
+
receiver: det.receiver,
|
|
192
|
+
options_present: det.optionsPresent,
|
|
193
|
+
missing_secure: det.missingSecure,
|
|
194
|
+
missing_http_only: det.missingHttpOnly,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
}
|
|
108
198
|
}
|
|
109
199
|
//# sourceMappingURL=insecure-cookie-pass.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insecure-cookie-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/insecure-cookie-pass.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"insecure-cookie-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/insecure-cookie-pass.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
import type { AnalysisPass, PassContext } from '../../graph/analysis-pass.js';
|
|
36
|
+
export interface TlsVerifyDisabledResult {
|
|
37
|
+
findings: Array<{
|
|
38
|
+
line: number;
|
|
39
|
+
language: string;
|
|
40
|
+
pattern: string;
|
|
41
|
+
api: string;
|
|
42
|
+
}>;
|
|
43
|
+
}
|
|
44
|
+
export declare class TlsVerifyDisabledPass implements AnalysisPass<TlsVerifyDisabledResult> {
|
|
45
|
+
readonly name = "tls-verify-disabled";
|
|
46
|
+
readonly category: "security";
|
|
47
|
+
run(ctx: PassContext): TlsVerifyDisabledResult;
|
|
48
|
+
private detectCall;
|
|
49
|
+
private detectSourceText;
|
|
50
|
+
private fixFor;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=tls-verify-disabled-pass.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tls-verify-disabled-pass.d.ts","sourceRoot":"","sources":["../../../src/analysis/passes/tls-verify-disabled-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAsB9E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;KACb,CAAC,CAAC;CACJ;AAED,qBAAa,qBAAsB,YAAW,YAAY,CAAC,uBAAuB,CAAC;IACjF,QAAQ,CAAC,IAAI,yBAAyB;IACtC,QAAQ,CAAC,QAAQ,EAAG,UAAU,CAAU;IAExC,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,uBAAuB;IA6D9C,OAAO,CAAC,UAAU;IA4ElB,OAAO,CAAC,gBAAgB;IAiDxB,OAAO,CAAC,MAAM;CA2Bf"}
|