circle-ir 3.6.0 → 3.8.2
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/configs/sinks/nodejs.json +58 -0
- package/configs/sinks/python.json +9 -0
- package/configs/sources/python.json +57 -17
- package/dist/analysis/config-loader.js +8 -6
- package/dist/analysis/config-loader.js.map +1 -1
- package/dist/analysis/interprocedural.js +14 -0
- package/dist/analysis/interprocedural.js.map +1 -1
- package/dist/analysis/taint-matcher.js +43 -0
- package/dist/analysis/taint-matcher.js.map +1 -1
- package/dist/analyzer.js +484 -0
- package/dist/analyzer.js.map +1 -1
- package/dist/browser/circle-ir.js +438 -8
- package/dist/core/circle-ir-core.cjs +45 -6
- package/dist/core/circle-ir-core.js +45 -6
- package/package.json +1 -1
|
@@ -9,6 +9,14 @@
|
|
|
9
9
|
"arg_positions": [0],
|
|
10
10
|
"note": "Command execution - extremely dangerous with user input"
|
|
11
11
|
},
|
|
12
|
+
{
|
|
13
|
+
"method": "exec",
|
|
14
|
+
"type": "command_injection",
|
|
15
|
+
"cwe": "CWE-78",
|
|
16
|
+
"severity": "critical",
|
|
17
|
+
"arg_positions": [0],
|
|
18
|
+
"note": "Destructured child_process.exec import - no receiver"
|
|
19
|
+
},
|
|
12
20
|
{
|
|
13
21
|
"method": "execSync",
|
|
14
22
|
"class": "child_process",
|
|
@@ -18,6 +26,14 @@
|
|
|
18
26
|
"arg_positions": [0],
|
|
19
27
|
"note": "Synchronous command execution"
|
|
20
28
|
},
|
|
29
|
+
{
|
|
30
|
+
"method": "execSync",
|
|
31
|
+
"type": "command_injection",
|
|
32
|
+
"cwe": "CWE-78",
|
|
33
|
+
"severity": "critical",
|
|
34
|
+
"arg_positions": [0],
|
|
35
|
+
"note": "Destructured child_process.execSync import - no receiver"
|
|
36
|
+
},
|
|
21
37
|
{
|
|
22
38
|
"method": "spawn",
|
|
23
39
|
"class": "child_process",
|
|
@@ -27,6 +43,14 @@
|
|
|
27
43
|
"arg_positions": [0, 1],
|
|
28
44
|
"note": "Process spawn - arg[0] is command, arg[1] is args array"
|
|
29
45
|
},
|
|
46
|
+
{
|
|
47
|
+
"method": "spawn",
|
|
48
|
+
"type": "command_injection",
|
|
49
|
+
"cwe": "CWE-78",
|
|
50
|
+
"severity": "critical",
|
|
51
|
+
"arg_positions": [0, 1],
|
|
52
|
+
"note": "Destructured child_process.spawn import - no receiver"
|
|
53
|
+
},
|
|
30
54
|
{
|
|
31
55
|
"method": "spawnSync",
|
|
32
56
|
"class": "child_process",
|
|
@@ -36,6 +60,14 @@
|
|
|
36
60
|
"arg_positions": [0, 1],
|
|
37
61
|
"note": "Synchronous process spawn"
|
|
38
62
|
},
|
|
63
|
+
{
|
|
64
|
+
"method": "spawnSync",
|
|
65
|
+
"type": "command_injection",
|
|
66
|
+
"cwe": "CWE-78",
|
|
67
|
+
"severity": "critical",
|
|
68
|
+
"arg_positions": [0, 1],
|
|
69
|
+
"note": "Destructured child_process.spawnSync import - no receiver"
|
|
70
|
+
},
|
|
39
71
|
{
|
|
40
72
|
"method": "execFile",
|
|
41
73
|
"class": "child_process",
|
|
@@ -45,6 +77,14 @@
|
|
|
45
77
|
"arg_positions": [0, 1],
|
|
46
78
|
"note": "Execute file with arguments"
|
|
47
79
|
},
|
|
80
|
+
{
|
|
81
|
+
"method": "execFile",
|
|
82
|
+
"type": "command_injection",
|
|
83
|
+
"cwe": "CWE-78",
|
|
84
|
+
"severity": "critical",
|
|
85
|
+
"arg_positions": [0, 1],
|
|
86
|
+
"note": "Destructured child_process.execFile import - no receiver"
|
|
87
|
+
},
|
|
48
88
|
{
|
|
49
89
|
"method": "fork",
|
|
50
90
|
"class": "child_process",
|
|
@@ -293,6 +333,15 @@
|
|
|
293
333
|
"arg_positions": [0],
|
|
294
334
|
"note": "Node.js HTTP request"
|
|
295
335
|
},
|
|
336
|
+
{
|
|
337
|
+
"method": "get",
|
|
338
|
+
"class": "http",
|
|
339
|
+
"type": "ssrf",
|
|
340
|
+
"cwe": "CWE-918",
|
|
341
|
+
"severity": "high",
|
|
342
|
+
"arg_positions": [0],
|
|
343
|
+
"note": "Node.js HTTP GET request - validate URL to prevent SSRF"
|
|
344
|
+
},
|
|
296
345
|
{
|
|
297
346
|
"method": "request",
|
|
298
347
|
"class": "https",
|
|
@@ -302,6 +351,15 @@
|
|
|
302
351
|
"arg_positions": [0],
|
|
303
352
|
"note": "Node.js HTTPS request"
|
|
304
353
|
},
|
|
354
|
+
{
|
|
355
|
+
"method": "get",
|
|
356
|
+
"class": "https",
|
|
357
|
+
"type": "ssrf",
|
|
358
|
+
"cwe": "CWE-918",
|
|
359
|
+
"severity": "high",
|
|
360
|
+
"arg_positions": [0],
|
|
361
|
+
"note": "Node.js HTTPS GET request"
|
|
362
|
+
},
|
|
305
363
|
{
|
|
306
364
|
"method": "redirect",
|
|
307
365
|
"class": "Response",
|
|
@@ -378,6 +378,15 @@
|
|
|
378
378
|
"arg_positions": [0],
|
|
379
379
|
"note": "etree.iterfind() with XPath expression"
|
|
380
380
|
},
|
|
381
|
+
{
|
|
382
|
+
"method": "select",
|
|
383
|
+
"class": "elementpath",
|
|
384
|
+
"type": "xpath_injection",
|
|
385
|
+
"cwe": "CWE-643",
|
|
386
|
+
"severity": "high",
|
|
387
|
+
"arg_positions": [1],
|
|
388
|
+
"note": "elementpath.select(root, query) - XPath injection via query param"
|
|
389
|
+
},
|
|
381
390
|
{
|
|
382
391
|
"method": "parse",
|
|
383
392
|
"class": "etree",
|
|
@@ -1,21 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"sources": [
|
|
3
3
|
{
|
|
4
|
-
"method": "
|
|
5
|
-
"class": "
|
|
4
|
+
"method": "get",
|
|
5
|
+
"class": "args",
|
|
6
6
|
"type": "http_param",
|
|
7
7
|
"severity": "high",
|
|
8
8
|
"return_tainted": true,
|
|
9
9
|
"note": "Flask request.args.get() - query string parameter"
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
|
-
"method": "
|
|
13
|
-
"class": "
|
|
12
|
+
"method": "getlist",
|
|
13
|
+
"class": "args",
|
|
14
14
|
"type": "http_param",
|
|
15
15
|
"severity": "high",
|
|
16
16
|
"return_tainted": true,
|
|
17
|
+
"note": "Flask request.args.getlist() - multi-value query string parameter"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"method": "get",
|
|
21
|
+
"class": "form",
|
|
22
|
+
"type": "http_body",
|
|
23
|
+
"severity": "high",
|
|
24
|
+
"return_tainted": true,
|
|
17
25
|
"note": "Flask request.form.get() - POST form parameter"
|
|
18
26
|
},
|
|
27
|
+
{
|
|
28
|
+
"method": "getlist",
|
|
29
|
+
"class": "form",
|
|
30
|
+
"type": "http_body",
|
|
31
|
+
"severity": "high",
|
|
32
|
+
"return_tainted": true,
|
|
33
|
+
"note": "Flask request.form.getlist() - multi-value POST form parameter"
|
|
34
|
+
},
|
|
19
35
|
{
|
|
20
36
|
"field": "json",
|
|
21
37
|
"class": "request",
|
|
@@ -24,6 +40,14 @@
|
|
|
24
40
|
"return_tainted": true,
|
|
25
41
|
"note": "Flask request.json - parsed JSON body"
|
|
26
42
|
},
|
|
43
|
+
{
|
|
44
|
+
"method": "get_json",
|
|
45
|
+
"class": "request",
|
|
46
|
+
"type": "http_body",
|
|
47
|
+
"severity": "high",
|
|
48
|
+
"return_tainted": true,
|
|
49
|
+
"note": "Flask request.get_json() - parsed JSON body"
|
|
50
|
+
},
|
|
27
51
|
{
|
|
28
52
|
"field": "data",
|
|
29
53
|
"class": "request",
|
|
@@ -33,16 +57,16 @@
|
|
|
33
57
|
"note": "Flask request.data - raw request body"
|
|
34
58
|
},
|
|
35
59
|
{
|
|
36
|
-
"method": "
|
|
37
|
-
"class": "
|
|
60
|
+
"method": "get",
|
|
61
|
+
"class": "headers",
|
|
38
62
|
"type": "http_header",
|
|
39
63
|
"severity": "high",
|
|
40
64
|
"return_tainted": true,
|
|
41
65
|
"note": "Flask request.headers.get() - HTTP header value"
|
|
42
66
|
},
|
|
43
67
|
{
|
|
44
|
-
"method": "
|
|
45
|
-
"class": "
|
|
68
|
+
"method": "get",
|
|
69
|
+
"class": "cookies",
|
|
46
70
|
"type": "http_cookie",
|
|
47
71
|
"severity": "high",
|
|
48
72
|
"return_tainted": true,
|
|
@@ -65,17 +89,17 @@
|
|
|
65
89
|
"note": "Flask request.query_string - raw query string"
|
|
66
90
|
},
|
|
67
91
|
{
|
|
68
|
-
"method": "
|
|
69
|
-
"class": "
|
|
92
|
+
"method": "get",
|
|
93
|
+
"class": "GET",
|
|
70
94
|
"type": "http_param",
|
|
71
95
|
"severity": "high",
|
|
72
96
|
"return_tainted": true,
|
|
73
97
|
"note": "Django request.GET.get() - query string parameter"
|
|
74
98
|
},
|
|
75
99
|
{
|
|
76
|
-
"method": "
|
|
77
|
-
"class": "
|
|
78
|
-
"type": "
|
|
100
|
+
"method": "get",
|
|
101
|
+
"class": "POST",
|
|
102
|
+
"type": "http_body",
|
|
79
103
|
"severity": "high",
|
|
80
104
|
"return_tainted": true,
|
|
81
105
|
"note": "Django request.POST.get() - POST form parameter"
|
|
@@ -89,21 +113,29 @@
|
|
|
89
113
|
"note": "Django request.body - raw request body"
|
|
90
114
|
},
|
|
91
115
|
{
|
|
92
|
-
"method": "
|
|
93
|
-
"class": "
|
|
116
|
+
"method": "get",
|
|
117
|
+
"class": "META",
|
|
94
118
|
"type": "http_header",
|
|
95
119
|
"severity": "high",
|
|
96
120
|
"return_tainted": true,
|
|
97
121
|
"note": "Django request.META.get() - HTTP headers and server info"
|
|
98
122
|
},
|
|
99
123
|
{
|
|
100
|
-
"method": "
|
|
101
|
-
"class": "
|
|
124
|
+
"method": "get",
|
|
125
|
+
"class": "COOKIES",
|
|
102
126
|
"type": "http_cookie",
|
|
103
127
|
"severity": "high",
|
|
104
128
|
"return_tainted": true,
|
|
105
129
|
"note": "Django request.COOKIES.get() - cookie value"
|
|
106
130
|
},
|
|
131
|
+
{
|
|
132
|
+
"field": "FILES",
|
|
133
|
+
"class": "request",
|
|
134
|
+
"type": "file_input",
|
|
135
|
+
"severity": "high",
|
|
136
|
+
"return_tainted": true,
|
|
137
|
+
"note": "Django request.FILES - uploaded files"
|
|
138
|
+
},
|
|
107
139
|
{
|
|
108
140
|
"field": "path_info",
|
|
109
141
|
"class": "request",
|
|
@@ -112,6 +144,14 @@
|
|
|
112
144
|
"return_tainted": true,
|
|
113
145
|
"note": "Django request.path_info - URL path"
|
|
114
146
|
},
|
|
147
|
+
{
|
|
148
|
+
"method": "get",
|
|
149
|
+
"class": "query_params",
|
|
150
|
+
"type": "http_param",
|
|
151
|
+
"severity": "high",
|
|
152
|
+
"return_tainted": true,
|
|
153
|
+
"note": "FastAPI/Starlette request.query_params.get() - query string parameter"
|
|
154
|
+
},
|
|
115
155
|
{
|
|
116
156
|
"method": "get",
|
|
117
157
|
"class": "environ",
|
|
@@ -539,9 +539,7 @@ export const DEFAULT_SINKS = [
|
|
|
539
539
|
{ method: 'resolveURI', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0] },
|
|
540
540
|
{ method: 'resolve', class: 'SourceResolver', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0] },
|
|
541
541
|
{ method: 'getSource', class: 'SourceResolver', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0] },
|
|
542
|
-
// URL-
|
|
543
|
-
{ method: 'URL', class: 'constructor', type: 'path_traversal', cwe: 'CWE-22', severity: 'medium', arg_positions: [0] },
|
|
544
|
-
{ method: 'openStream', class: 'URL', type: 'path_traversal', cwe: 'CWE-22', severity: 'medium', arg_positions: [] },
|
|
542
|
+
// NOTE: new URL(userInput) is SSRF (CWE-918), not path traversal — see ssrf section below
|
|
545
543
|
// Servlet context resource loading
|
|
546
544
|
{ method: 'getResource', class: 'ServletContext', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0] },
|
|
547
545
|
{ method: 'getResourceAsStream', class: 'ServletContext', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0] },
|
|
@@ -578,8 +576,7 @@ export const DEFAULT_SINKS = [
|
|
|
578
576
|
{ method: 'extract', type: 'path_traversal', cwe: 'CWE-22', severity: 'critical', arg_positions: [0, 1] },
|
|
579
577
|
{ method: 'extractAll', type: 'path_traversal', cwe: 'CWE-22', severity: 'critical', arg_positions: [0, 1] },
|
|
580
578
|
{ method: 'unjar', type: 'path_traversal', cwe: 'CWE-22', severity: 'critical', arg_positions: [0, 1] },
|
|
581
|
-
// Additional file constructors
|
|
582
|
-
{ method: 'BufferedReader', class: 'constructor', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0] },
|
|
579
|
+
// Additional file constructors — BufferedReader(Reader) is NOT a path traversal sink; it wraps a Reader, not a file path
|
|
583
580
|
{ method: 'PrintWriter', class: 'constructor', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0] },
|
|
584
581
|
{ method: 'Scanner', class: 'constructor', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0] },
|
|
585
582
|
// Topic/queue names (for message queue systems - can be exploited for path traversal)
|
|
@@ -1102,9 +1099,12 @@ export const DEFAULT_SINKS = [
|
|
|
1102
1099
|
{ method: 'execSync', class: 'child_process', type: 'command_injection', cwe: 'CWE-78', severity: 'critical', arg_positions: [0] },
|
|
1103
1100
|
{ method: 'spawn', class: 'child_process', type: 'command_injection', cwe: 'CWE-78', severity: 'critical', arg_positions: [0] },
|
|
1104
1101
|
{ method: 'spawnSync', class: 'child_process', type: 'command_injection', cwe: 'CWE-78', severity: 'critical', arg_positions: [0] },
|
|
1105
|
-
// Also match without receiver (destructured imports)
|
|
1102
|
+
// Also match without receiver (destructured imports: const { exec } = require('child_process'))
|
|
1106
1103
|
{ method: 'exec', type: 'command_injection', cwe: 'CWE-78', severity: 'high', arg_positions: [0] },
|
|
1107
1104
|
{ method: 'execSync', type: 'command_injection', cwe: 'CWE-78', severity: 'high', arg_positions: [0] },
|
|
1105
|
+
{ method: 'spawn', type: 'command_injection', cwe: 'CWE-78', severity: 'high', arg_positions: [0] },
|
|
1106
|
+
{ method: 'spawnSync', type: 'command_injection', cwe: 'CWE-78', severity: 'high', arg_positions: [0] },
|
|
1107
|
+
{ method: 'execFile', type: 'command_injection', cwe: 'CWE-78', severity: 'high', arg_positions: [0] },
|
|
1108
1108
|
// Node.js File System (path traversal)
|
|
1109
1109
|
{ method: 'readFile', class: 'fs', type: 'path_traversal', cwe: 'CWE-22', severity: 'critical', arg_positions: [0] },
|
|
1110
1110
|
{ method: 'readFileSync', class: 'fs', type: 'path_traversal', cwe: 'CWE-22', severity: 'critical', arg_positions: [0] },
|
|
@@ -1147,7 +1147,9 @@ export const DEFAULT_SINKS = [
|
|
|
1147
1147
|
{ method: 'request', class: 'axios', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0] },
|
|
1148
1148
|
{ method: 'fetch', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0] },
|
|
1149
1149
|
{ method: 'request', class: 'http', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0] },
|
|
1150
|
+
{ method: 'get', class: 'http', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0] },
|
|
1150
1151
|
{ method: 'request', class: 'https', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0] },
|
|
1152
|
+
{ method: 'get', class: 'https', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0] },
|
|
1151
1153
|
// needle library (used in NodeGoat)
|
|
1152
1154
|
{ method: 'get', class: 'needle', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0] },
|
|
1153
1155
|
{ method: 'post', class: 'needle', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0] },
|