acidtest 0.7.0 → 1.0.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/.github/workflows/acidtest-pr-comment.yml +219 -0
- package/README.md +155 -30
- package/dist/analysis/dataflow-graph.d.ts +19 -0
- package/dist/analysis/dataflow-graph.d.ts.map +1 -0
- package/dist/analysis/dataflow-graph.js +365 -0
- package/dist/analysis/dataflow-graph.js.map +1 -0
- package/dist/analysis/dataflow-types.d.ts +86 -0
- package/dist/analysis/dataflow-types.d.ts.map +1 -0
- package/dist/analysis/dataflow-types.js +8 -0
- package/dist/analysis/dataflow-types.js.map +1 -0
- package/dist/analysis/dataflow.test.d.ts +7 -0
- package/dist/analysis/dataflow.test.d.ts.map +1 -0
- package/dist/analysis/dataflow.test.js +257 -0
- package/dist/analysis/dataflow.test.js.map +1 -0
- package/dist/analysis/taint-propagation.d.ts +30 -0
- package/dist/analysis/taint-propagation.d.ts.map +1 -0
- package/dist/analysis/taint-propagation.js +207 -0
- package/dist/analysis/taint-propagation.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/layers/code.d.ts +1 -1
- package/dist/layers/code.d.ts.map +1 -1
- package/dist/layers/code.js +282 -3
- package/dist/layers/code.js.map +1 -1
- package/dist/layers/code.test.js +196 -0
- package/dist/layers/code.test.js.map +1 -1
- package/dist/layers/crossref.d.ts.map +1 -1
- package/dist/layers/crossref.js +6 -3
- package/dist/layers/crossref.js.map +1 -1
- package/dist/layers/dataflow.d.ts +29 -0
- package/dist/layers/dataflow.d.ts.map +1 -0
- package/dist/layers/dataflow.js +217 -0
- package/dist/layers/dataflow.js.map +1 -0
- package/dist/layers/permissions.d.ts.map +1 -1
- package/dist/layers/permissions.js +2 -1
- package/dist/layers/permissions.js.map +1 -1
- package/dist/mcp-server.js +1 -1
- package/dist/parsers/parser-interface.d.ts +31 -0
- package/dist/parsers/parser-interface.d.ts.map +1 -0
- package/dist/parsers/parser-interface.js +6 -0
- package/dist/parsers/parser-interface.js.map +1 -0
- package/dist/parsers/parsers.test.d.ts +5 -0
- package/dist/parsers/parsers.test.d.ts.map +1 -0
- package/dist/parsers/parsers.test.js +111 -0
- package/dist/parsers/parsers.test.js.map +1 -0
- package/dist/parsers/python-parser.d.ts +18 -0
- package/dist/parsers/python-parser.d.ts.map +1 -0
- package/dist/parsers/python-parser.js +120 -0
- package/dist/parsers/python-parser.js.map +1 -0
- package/dist/parsers/typescript-parser.d.ts +16 -0
- package/dist/parsers/typescript-parser.d.ts.map +1 -0
- package/dist/parsers/typescript-parser.js +112 -0
- package/dist/parsers/typescript-parser.js.map +1 -0
- package/dist/patterns/dangerous-calls-python.json +220 -0
- package/dist/patterns/dangerous-imports-python.json +256 -0
- package/dist/patterns/insecure-crypto.json +163 -0
- package/dist/patterns/prototype-pollution.json +72 -0
- package/dist/patterns/python-deserialization.json +94 -0
- package/dist/patterns/regex-dos.json +50 -0
- package/dist/patterns/sql-injection.json +91 -0
- package/dist/patterns/xss-injection.json +115 -0
- package/dist/scanner.d.ts +1 -1
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +51 -4
- package/dist/scanner.js.map +1 -1
- package/dist/schemas/pattern.schema.json +139 -0
- package/dist/test-corpus/validate-corpus.d.ts +7 -0
- package/dist/test-corpus/validate-corpus.d.ts.map +1 -0
- package/dist/test-corpus/validate-corpus.js +341 -0
- package/dist/test-corpus/validate-corpus.js.map +1 -0
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/validation/pattern-validator.d.ts +34 -0
- package/dist/validation/pattern-validator.d.ts.map +1 -0
- package/dist/validation/pattern-validator.js +168 -0
- package/dist/validation/pattern-validator.js.map +1 -0
- package/dist/validation/pattern-validator.test.d.ts +5 -0
- package/dist/validation/pattern-validator.test.d.ts.map +1 -0
- package/dist/validation/pattern-validator.test.js +222 -0
- package/dist/validation/pattern-validator.test.js.map +1 -0
- package/dist/validation/validate-patterns.d.ts +6 -0
- package/dist/validation/validate-patterns.d.ts.map +1 -0
- package/dist/validation/validate-patterns.js +55 -0
- package/dist/validation/validate-patterns.js.map +1 -0
- package/package.json +11 -4
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
{
|
|
2
|
+
"category": "dangerous-imports",
|
|
3
|
+
"patterns": [
|
|
4
|
+
{
|
|
5
|
+
"id": "pyimp-001",
|
|
6
|
+
"name": "subprocess-module",
|
|
7
|
+
"description": "Imports subprocess module for command execution",
|
|
8
|
+
"severity": "HIGH",
|
|
9
|
+
"match": {
|
|
10
|
+
"type": "regex",
|
|
11
|
+
"value": "(import\\s+subprocess|from\\s+subprocess\\s+import)",
|
|
12
|
+
"flags": "g"
|
|
13
|
+
},
|
|
14
|
+
"layer": "code",
|
|
15
|
+
"remediation": {
|
|
16
|
+
"title": "Avoid subprocess when possible",
|
|
17
|
+
"suggestions": [
|
|
18
|
+
"Use built-in Python APIs instead of shell commands",
|
|
19
|
+
"If subprocess is necessary, never use shell=True",
|
|
20
|
+
"Never pass user input directly to subprocess functions",
|
|
21
|
+
"Use explicit argument lists with subprocess.run([cmd, arg1, arg2])",
|
|
22
|
+
"Validate and sanitize all command arguments"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "pyimp-002",
|
|
28
|
+
"name": "os-system-import",
|
|
29
|
+
"description": "Imports os module which provides os.system() for command execution",
|
|
30
|
+
"severity": "MEDIUM",
|
|
31
|
+
"match": {
|
|
32
|
+
"type": "regex",
|
|
33
|
+
"value": "(import\\s+os|from\\s+os\\s+import)",
|
|
34
|
+
"flags": "g"
|
|
35
|
+
},
|
|
36
|
+
"layer": "code"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "pyimp-003",
|
|
40
|
+
"name": "eval-builtin",
|
|
41
|
+
"description": "Uses eval() builtin for arbitrary code execution",
|
|
42
|
+
"severity": "CRITICAL",
|
|
43
|
+
"match": {
|
|
44
|
+
"type": "regex",
|
|
45
|
+
"value": "\\beval\\s*\\(",
|
|
46
|
+
"flags": "g"
|
|
47
|
+
},
|
|
48
|
+
"layer": "code",
|
|
49
|
+
"remediation": {
|
|
50
|
+
"title": "Replace eval() with safer alternatives",
|
|
51
|
+
"suggestions": [
|
|
52
|
+
"Use json.loads() for parsing JSON strings",
|
|
53
|
+
"Use ast.literal_eval() for safely evaluating Python literals",
|
|
54
|
+
"Consider removing dynamic code execution entirely",
|
|
55
|
+
"If absolutely necessary, validate and sanitize all inputs"
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": "pyimp-004",
|
|
61
|
+
"name": "exec-builtin",
|
|
62
|
+
"description": "Uses exec() builtin for arbitrary code execution",
|
|
63
|
+
"severity": "CRITICAL",
|
|
64
|
+
"match": {
|
|
65
|
+
"type": "regex",
|
|
66
|
+
"value": "\\bexec\\s*\\(",
|
|
67
|
+
"flags": "g"
|
|
68
|
+
},
|
|
69
|
+
"layer": "code",
|
|
70
|
+
"remediation": {
|
|
71
|
+
"title": "Avoid exec() for dynamic code execution",
|
|
72
|
+
"suggestions": [
|
|
73
|
+
"Refactor to use static function definitions",
|
|
74
|
+
"Use importlib for dynamic module loading instead",
|
|
75
|
+
"If truly necessary, ensure all code is from trusted sources only",
|
|
76
|
+
"Consider using a restricted globals/locals dictionary"
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "pyimp-005",
|
|
82
|
+
"name": "compile-builtin",
|
|
83
|
+
"description": "Uses compile() builtin for code object creation",
|
|
84
|
+
"severity": "HIGH",
|
|
85
|
+
"match": {
|
|
86
|
+
"type": "regex",
|
|
87
|
+
"value": "\\bcompile\\s*\\(",
|
|
88
|
+
"flags": "g"
|
|
89
|
+
},
|
|
90
|
+
"layer": "code"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"id": "pyimp-006",
|
|
94
|
+
"name": "pickle-module",
|
|
95
|
+
"description": "Imports pickle module for unsafe deserialization",
|
|
96
|
+
"severity": "CRITICAL",
|
|
97
|
+
"match": {
|
|
98
|
+
"type": "regex",
|
|
99
|
+
"value": "(import\\s+pickle|from\\s+pickle\\s+import)",
|
|
100
|
+
"flags": "g"
|
|
101
|
+
},
|
|
102
|
+
"layer": "code",
|
|
103
|
+
"remediation": {
|
|
104
|
+
"title": "Replace pickle with safer serialization",
|
|
105
|
+
"suggestions": [
|
|
106
|
+
"Use json for data serialization when possible",
|
|
107
|
+
"For complex objects, consider msgpack or protobuf",
|
|
108
|
+
"Never unpickle data from untrusted sources",
|
|
109
|
+
"If pickle is required, use hmac to verify data integrity",
|
|
110
|
+
"Consider using restricted unpicklers with custom find_class()"
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"id": "pyimp-007",
|
|
116
|
+
"name": "shelve-module",
|
|
117
|
+
"description": "Imports shelve module which uses pickle internally",
|
|
118
|
+
"severity": "HIGH",
|
|
119
|
+
"match": {
|
|
120
|
+
"type": "regex",
|
|
121
|
+
"value": "(import\\s+shelve|from\\s+shelve\\s+import)",
|
|
122
|
+
"flags": "g"
|
|
123
|
+
},
|
|
124
|
+
"layer": "code"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"id": "pyimp-008",
|
|
128
|
+
"name": "marshal-module",
|
|
129
|
+
"description": "Imports marshal module for unsafe deserialization",
|
|
130
|
+
"severity": "HIGH",
|
|
131
|
+
"match": {
|
|
132
|
+
"type": "regex",
|
|
133
|
+
"value": "(import\\s+marshal|from\\s+marshal\\s+import)",
|
|
134
|
+
"flags": "g"
|
|
135
|
+
},
|
|
136
|
+
"layer": "code"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"id": "pyimp-009",
|
|
140
|
+
"name": "import-builtin",
|
|
141
|
+
"description": "Uses __import__ builtin for dynamic imports",
|
|
142
|
+
"severity": "HIGH",
|
|
143
|
+
"match": {
|
|
144
|
+
"type": "regex",
|
|
145
|
+
"value": "\\b__import__\\s*\\(",
|
|
146
|
+
"flags": "g"
|
|
147
|
+
},
|
|
148
|
+
"layer": "code",
|
|
149
|
+
"remediation": {
|
|
150
|
+
"title": "Replace dynamic imports with static imports",
|
|
151
|
+
"suggestions": [
|
|
152
|
+
"Use static import statements when possible",
|
|
153
|
+
"Use importlib.import_module() with whitelisted module names",
|
|
154
|
+
"Validate module names against a known set before importing",
|
|
155
|
+
"Consider using entry points or plugin systems instead"
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"id": "pyimp-010",
|
|
161
|
+
"name": "importlib-import",
|
|
162
|
+
"description": "Uses importlib for dynamic module imports",
|
|
163
|
+
"severity": "MEDIUM",
|
|
164
|
+
"match": {
|
|
165
|
+
"type": "regex",
|
|
166
|
+
"value": "(import\\s+importlib|from\\s+importlib\\s+import|importlib\\.import_module)",
|
|
167
|
+
"flags": "g"
|
|
168
|
+
},
|
|
169
|
+
"layer": "code"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"id": "pyimp-011",
|
|
173
|
+
"name": "ctypes-module",
|
|
174
|
+
"description": "Imports ctypes for native code execution",
|
|
175
|
+
"severity": "HIGH",
|
|
176
|
+
"match": {
|
|
177
|
+
"type": "regex",
|
|
178
|
+
"value": "(import\\s+ctypes|from\\s+ctypes\\s+import)",
|
|
179
|
+
"flags": "g"
|
|
180
|
+
},
|
|
181
|
+
"layer": "code"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"id": "pyimp-012",
|
|
185
|
+
"name": "cffi-module",
|
|
186
|
+
"description": "Imports cffi for native code execution",
|
|
187
|
+
"severity": "HIGH",
|
|
188
|
+
"match": {
|
|
189
|
+
"type": "regex",
|
|
190
|
+
"value": "(import\\s+cffi|from\\s+cffi\\s+import)",
|
|
191
|
+
"flags": "g"
|
|
192
|
+
},
|
|
193
|
+
"layer": "code"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"id": "pyimp-013",
|
|
197
|
+
"name": "socket-module",
|
|
198
|
+
"description": "Imports socket module for network access",
|
|
199
|
+
"severity": "LOW",
|
|
200
|
+
"match": {
|
|
201
|
+
"type": "regex",
|
|
202
|
+
"value": "(import\\s+socket|from\\s+socket\\s+import)",
|
|
203
|
+
"flags": "g"
|
|
204
|
+
},
|
|
205
|
+
"layer": "code"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"id": "pyimp-014",
|
|
209
|
+
"name": "requests-module",
|
|
210
|
+
"description": "Imports requests module for HTTP requests",
|
|
211
|
+
"severity": "LOW",
|
|
212
|
+
"match": {
|
|
213
|
+
"type": "regex",
|
|
214
|
+
"value": "(import\\s+requests|from\\s+requests\\s+import)",
|
|
215
|
+
"flags": "g"
|
|
216
|
+
},
|
|
217
|
+
"layer": "code"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"id": "pyimp-015",
|
|
221
|
+
"name": "urllib-module",
|
|
222
|
+
"description": "Imports urllib for URL/HTTP operations",
|
|
223
|
+
"severity": "LOW",
|
|
224
|
+
"match": {
|
|
225
|
+
"type": "regex",
|
|
226
|
+
"value": "(import\\s+urllib|from\\s+urllib)",
|
|
227
|
+
"flags": "g"
|
|
228
|
+
},
|
|
229
|
+
"layer": "code"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"id": "pyimp-016",
|
|
233
|
+
"name": "httpx-module",
|
|
234
|
+
"description": "Imports httpx module for HTTP requests",
|
|
235
|
+
"severity": "LOW",
|
|
236
|
+
"match": {
|
|
237
|
+
"type": "regex",
|
|
238
|
+
"value": "(import\\s+httpx|from\\s+httpx\\s+import)",
|
|
239
|
+
"flags": "g"
|
|
240
|
+
},
|
|
241
|
+
"layer": "code"
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"id": "pyimp-017",
|
|
245
|
+
"name": "input-builtin",
|
|
246
|
+
"description": "Uses input() for user input which could be dangerous",
|
|
247
|
+
"severity": "LOW",
|
|
248
|
+
"match": {
|
|
249
|
+
"type": "regex",
|
|
250
|
+
"value": "\\binput\\s*\\(",
|
|
251
|
+
"flags": "g"
|
|
252
|
+
},
|
|
253
|
+
"layer": "code"
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
{
|
|
2
|
+
"category": "insecure-crypto",
|
|
3
|
+
"patterns": [
|
|
4
|
+
{
|
|
5
|
+
"id": "crypto-001",
|
|
6
|
+
"name": "MD5 hash algorithm usage",
|
|
7
|
+
"description": "MD5 is cryptographically broken and should not be used for security purposes",
|
|
8
|
+
"severity": "HIGH",
|
|
9
|
+
"match": {
|
|
10
|
+
"type": "regex",
|
|
11
|
+
"value": "(createHash|hashlib\\.(md5|new)).*['\"]md5['\"]",
|
|
12
|
+
"flags": "i"
|
|
13
|
+
},
|
|
14
|
+
"layer": "code",
|
|
15
|
+
"category": "insecure-crypto",
|
|
16
|
+
"remediation": {
|
|
17
|
+
"title": "Use secure hash algorithms",
|
|
18
|
+
"suggestions": [
|
|
19
|
+
"Use SHA-256 or SHA-3 for hashing",
|
|
20
|
+
"For passwords, use bcrypt, scrypt, or Argon2",
|
|
21
|
+
"MD5 is vulnerable to collision attacks",
|
|
22
|
+
"For TypeScript: crypto.createHash('sha256')",
|
|
23
|
+
"For Python: hashlib.sha256()"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "crypto-002",
|
|
29
|
+
"name": "SHA-1 hash algorithm usage",
|
|
30
|
+
"description": "SHA-1 is deprecated and vulnerable to collision attacks",
|
|
31
|
+
"severity": "MEDIUM",
|
|
32
|
+
"match": {
|
|
33
|
+
"type": "regex",
|
|
34
|
+
"value": "(createHash|hashlib\\.(sha1|new)).*['\"]sha1['\"]",
|
|
35
|
+
"flags": "i"
|
|
36
|
+
},
|
|
37
|
+
"layer": "code",
|
|
38
|
+
"category": "insecure-crypto",
|
|
39
|
+
"remediation": {
|
|
40
|
+
"title": "Use SHA-256 or better",
|
|
41
|
+
"suggestions": [
|
|
42
|
+
"Migrate to SHA-256, SHA-384, or SHA-512",
|
|
43
|
+
"SHA-1 is deprecated by NIST since 2011",
|
|
44
|
+
"Vulnerable to collision attacks (SHAttered attack)",
|
|
45
|
+
"Use SHA-256 minimum for new applications"
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "crypto-003",
|
|
51
|
+
"name": "Weak random number generation",
|
|
52
|
+
"description": "Math.random() is not cryptographically secure",
|
|
53
|
+
"severity": "MEDIUM",
|
|
54
|
+
"match": {
|
|
55
|
+
"type": "regex",
|
|
56
|
+
"value": "Math\\.random\\(\\)",
|
|
57
|
+
"flags": ""
|
|
58
|
+
},
|
|
59
|
+
"layer": "code",
|
|
60
|
+
"category": "insecure-crypto",
|
|
61
|
+
"remediation": {
|
|
62
|
+
"title": "Use cryptographically secure random",
|
|
63
|
+
"suggestions": [
|
|
64
|
+
"For TypeScript: Use crypto.randomBytes() or crypto.getRandomValues()",
|
|
65
|
+
"For Python: Use secrets module instead of random",
|
|
66
|
+
"Math.random() is predictable and not suitable for security",
|
|
67
|
+
"Never use Math.random() for tokens, keys, or security-sensitive operations"
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "crypto-004",
|
|
73
|
+
"name": "Python random module for security (Python)",
|
|
74
|
+
"description": "Python's random module is not cryptographically secure",
|
|
75
|
+
"severity": "MEDIUM",
|
|
76
|
+
"match": {
|
|
77
|
+
"type": "regex",
|
|
78
|
+
"value": "import random|from random import",
|
|
79
|
+
"flags": ""
|
|
80
|
+
},
|
|
81
|
+
"layer": "code",
|
|
82
|
+
"category": "insecure-crypto",
|
|
83
|
+
"remediation": {
|
|
84
|
+
"title": "Use secrets module",
|
|
85
|
+
"suggestions": [
|
|
86
|
+
"Use 'import secrets' instead of 'import random' for security",
|
|
87
|
+
"secrets.token_bytes(), secrets.token_hex(), secrets.token_urlsafe()",
|
|
88
|
+
"random module uses Mersenne Twister which is predictable",
|
|
89
|
+
"Only use random module for non-security purposes (games, simulations)"
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"id": "crypto-005",
|
|
95
|
+
"name": "Hardcoded secret or API key",
|
|
96
|
+
"description": "Hardcoded secrets in source code are a security risk",
|
|
97
|
+
"severity": "CRITICAL",
|
|
98
|
+
"match": {
|
|
99
|
+
"type": "regex",
|
|
100
|
+
"value": "(api[_-]?key|secret|password|token|auth)\\s*=\\s*['\"][a-zA-Z0-9_-]{20,}['\"]",
|
|
101
|
+
"flags": "i"
|
|
102
|
+
},
|
|
103
|
+
"layer": "code",
|
|
104
|
+
"category": "insecure-crypto",
|
|
105
|
+
"remediation": {
|
|
106
|
+
"title": "Use environment variables",
|
|
107
|
+
"suggestions": [
|
|
108
|
+
"Store secrets in environment variables (process.env.API_KEY)",
|
|
109
|
+
"Use a secrets management service (AWS Secrets Manager, HashiCorp Vault)",
|
|
110
|
+
"Never commit secrets to version control",
|
|
111
|
+
"Use .env files (but add .env to .gitignore)",
|
|
112
|
+
"Rotate any secrets that were accidentally committed"
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"id": "crypto-006",
|
|
118
|
+
"name": "DES/3DES cipher usage",
|
|
119
|
+
"description": "DES and 3DES are obsolete and insecure encryption algorithms",
|
|
120
|
+
"severity": "HIGH",
|
|
121
|
+
"match": {
|
|
122
|
+
"type": "regex",
|
|
123
|
+
"value": "(createCipher|Cipher\\.getInstance).*['\"]?(DES|3DES|TripleDES)['\"]?",
|
|
124
|
+
"flags": "i"
|
|
125
|
+
},
|
|
126
|
+
"layer": "code",
|
|
127
|
+
"category": "insecure-crypto",
|
|
128
|
+
"remediation": {
|
|
129
|
+
"title": "Use AES encryption",
|
|
130
|
+
"suggestions": [
|
|
131
|
+
"Use AES-256-GCM or AES-256-CBC for encryption",
|
|
132
|
+
"DES has a 56-bit key which is too weak",
|
|
133
|
+
"3DES is deprecated and slow",
|
|
134
|
+
"For TypeScript: crypto.createCipheriv('aes-256-gcm', key, iv)",
|
|
135
|
+
"For Python: Use cryptography library with AES"
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"id": "crypto-007",
|
|
141
|
+
"name": "ECB cipher mode usage",
|
|
142
|
+
"description": "ECB mode does not provide message confidentiality",
|
|
143
|
+
"severity": "HIGH",
|
|
144
|
+
"match": {
|
|
145
|
+
"type": "regex",
|
|
146
|
+
"value": "(createCipher|Cipher\\.getInstance).*ECB",
|
|
147
|
+
"flags": "i"
|
|
148
|
+
},
|
|
149
|
+
"layer": "code",
|
|
150
|
+
"category": "insecure-crypto",
|
|
151
|
+
"remediation": {
|
|
152
|
+
"title": "Use GCM or CBC mode",
|
|
153
|
+
"suggestions": [
|
|
154
|
+
"Use AES-GCM mode (provides authentication)",
|
|
155
|
+
"Use AES-CBC mode with HMAC for authentication",
|
|
156
|
+
"ECB mode reveals patterns in plaintext",
|
|
157
|
+
"ECB is deterministic - same plaintext produces same ciphertext",
|
|
158
|
+
"Never use ECB mode for encrypting more than one block"
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
]
|
|
163
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"category": "prototype-pollution",
|
|
3
|
+
"patterns": [
|
|
4
|
+
{
|
|
5
|
+
"id": "proto-001",
|
|
6
|
+
"name": "Direct __proto__ access",
|
|
7
|
+
"description": "Direct access or modification of __proto__ can lead to prototype pollution",
|
|
8
|
+
"severity": "HIGH",
|
|
9
|
+
"match": {
|
|
10
|
+
"type": "regex",
|
|
11
|
+
"value": "__proto__|\\[\\s*['\"]__proto__['\"]\\s*\\]",
|
|
12
|
+
"flags": ""
|
|
13
|
+
},
|
|
14
|
+
"layer": "code",
|
|
15
|
+
"category": "prototype-pollution",
|
|
16
|
+
"remediation": {
|
|
17
|
+
"title": "Avoid __proto__ access",
|
|
18
|
+
"suggestions": [
|
|
19
|
+
"Use Object.create(null) to create objects without prototype",
|
|
20
|
+
"Use Object.setPrototypeOf() if prototype modification is necessary",
|
|
21
|
+
"Validate and sanitize object keys before assignment",
|
|
22
|
+
"Use Object.freeze() to prevent prototype modification",
|
|
23
|
+
"Never allow user input to set object properties dynamically"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "proto-002",
|
|
29
|
+
"name": "constructor.prototype manipulation",
|
|
30
|
+
"description": "Modifying constructor.prototype can affect all instances",
|
|
31
|
+
"severity": "HIGH",
|
|
32
|
+
"match": {
|
|
33
|
+
"type": "regex",
|
|
34
|
+
"value": "constructor\\[\\s*['\"]prototype['\"]\\s*\\]|constructor\\.prototype\\[",
|
|
35
|
+
"flags": ""
|
|
36
|
+
},
|
|
37
|
+
"layer": "code",
|
|
38
|
+
"category": "prototype-pollution",
|
|
39
|
+
"remediation": {
|
|
40
|
+
"title": "Avoid prototype manipulation",
|
|
41
|
+
"suggestions": [
|
|
42
|
+
"Validate object keys before dynamic property access",
|
|
43
|
+
"Use Object.create(null) for user-controlled objects",
|
|
44
|
+
"Implement key whitelisting for dynamic properties",
|
|
45
|
+
"Consider using Map instead of plain objects for key-value storage"
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "proto-003",
|
|
51
|
+
"name": "Object merge without key validation",
|
|
52
|
+
"description": "Merging objects without validating keys can lead to prototype pollution",
|
|
53
|
+
"severity": "MEDIUM",
|
|
54
|
+
"match": {
|
|
55
|
+
"type": "regex",
|
|
56
|
+
"value": "(Object\\.assign|\\.\\.\\.|merge|extend)\\([^)]*\\)",
|
|
57
|
+
"flags": ""
|
|
58
|
+
},
|
|
59
|
+
"layer": "code",
|
|
60
|
+
"category": "prototype-pollution",
|
|
61
|
+
"remediation": {
|
|
62
|
+
"title": "Validate keys during merge",
|
|
63
|
+
"suggestions": [
|
|
64
|
+
"Validate that source objects don't contain __proto__, constructor, or prototype",
|
|
65
|
+
"Use a safe merge function that filters dangerous keys",
|
|
66
|
+
"Consider using libraries like 'lodash.merge' with proper configuration",
|
|
67
|
+
"Implement a key whitelist for allowed properties"
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"category": "deserialization",
|
|
3
|
+
"patterns": [
|
|
4
|
+
{
|
|
5
|
+
"id": "deser-001",
|
|
6
|
+
"name": "YAML unsafe load (Python)",
|
|
7
|
+
"description": "yaml.load() without Loader parameter can execute arbitrary code",
|
|
8
|
+
"severity": "CRITICAL",
|
|
9
|
+
"match": {
|
|
10
|
+
"type": "regex",
|
|
11
|
+
"value": "yaml\\.load\\([^,)]+\\)|yaml\\.load\\([^)]*,\\s*Loader\\s*=\\s*yaml\\.Loader\\s*\\)",
|
|
12
|
+
"flags": ""
|
|
13
|
+
},
|
|
14
|
+
"layer": "code",
|
|
15
|
+
"category": "deserialization",
|
|
16
|
+
"remediation": {
|
|
17
|
+
"title": "Use yaml.safe_load()",
|
|
18
|
+
"suggestions": [
|
|
19
|
+
"Use yaml.safe_load() instead of yaml.load()",
|
|
20
|
+
"If Loader is needed, use yaml.SafeLoader",
|
|
21
|
+
"yaml.load() can execute arbitrary Python code in YAML",
|
|
22
|
+
"Example: yaml.safe_load(data) or yaml.load(data, Loader=yaml.SafeLoader)"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "deser-002",
|
|
28
|
+
"name": "XML parsing without entity protection (Python)",
|
|
29
|
+
"description": "XML parsing without defusedxml can be vulnerable to XXE and billion laughs attacks",
|
|
30
|
+
"severity": "HIGH",
|
|
31
|
+
"match": {
|
|
32
|
+
"type": "regex",
|
|
33
|
+
"value": "from xml\\.etree|import xml\\.etree|ElementTree\\.parse|lxml\\.etree",
|
|
34
|
+
"flags": ""
|
|
35
|
+
},
|
|
36
|
+
"layer": "code",
|
|
37
|
+
"category": "deserialization",
|
|
38
|
+
"remediation": {
|
|
39
|
+
"title": "Use defusedxml library",
|
|
40
|
+
"suggestions": [
|
|
41
|
+
"Use defusedxml library instead of xml.etree or lxml",
|
|
42
|
+
"Install: pip install defusedxml",
|
|
43
|
+
"from defusedxml.ElementTree import parse",
|
|
44
|
+
"Protects against XXE, billion laughs, and other XML attacks",
|
|
45
|
+
"Configure parsers to disable external entities"
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "deser-003",
|
|
51
|
+
"name": "marshal.loads() usage (Python)",
|
|
52
|
+
"description": "marshal module is not safe for untrusted data",
|
|
53
|
+
"severity": "HIGH",
|
|
54
|
+
"match": {
|
|
55
|
+
"type": "regex",
|
|
56
|
+
"value": "marshal\\.loads?\\(",
|
|
57
|
+
"flags": ""
|
|
58
|
+
},
|
|
59
|
+
"layer": "code",
|
|
60
|
+
"category": "deserialization",
|
|
61
|
+
"remediation": {
|
|
62
|
+
"title": "Use json or safer serialization",
|
|
63
|
+
"suggestions": [
|
|
64
|
+
"Use json module for data serialization",
|
|
65
|
+
"marshal is only safe for trusted data",
|
|
66
|
+
"Never deserialize marshal data from untrusted sources",
|
|
67
|
+
"Consider using json, msgpack, or protobuf for untrusted data"
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "deser-004",
|
|
73
|
+
"name": "jsonpickle decode (Python)",
|
|
74
|
+
"description": "jsonpickle can deserialize arbitrary Python objects",
|
|
75
|
+
"severity": "HIGH",
|
|
76
|
+
"match": {
|
|
77
|
+
"type": "regex",
|
|
78
|
+
"value": "jsonpickle\\.(decode|loads)",
|
|
79
|
+
"flags": ""
|
|
80
|
+
},
|
|
81
|
+
"layer": "code",
|
|
82
|
+
"category": "deserialization",
|
|
83
|
+
"remediation": {
|
|
84
|
+
"title": "Use standard json module",
|
|
85
|
+
"suggestions": [
|
|
86
|
+
"Use json.loads() for untrusted data",
|
|
87
|
+
"jsonpickle can instantiate arbitrary classes",
|
|
88
|
+
"Only use jsonpickle with data you control",
|
|
89
|
+
"Implement class whitelisting if jsonpickle is required"
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"category": "regex-dos",
|
|
3
|
+
"patterns": [
|
|
4
|
+
{
|
|
5
|
+
"id": "redos-001",
|
|
6
|
+
"name": "Regex with nested quantifiers (ReDoS)",
|
|
7
|
+
"description": "Regex with nested quantifiers can cause exponential backtracking (ReDoS)",
|
|
8
|
+
"severity": "MEDIUM",
|
|
9
|
+
"match": {
|
|
10
|
+
"type": "regex",
|
|
11
|
+
"value": "new RegExp\\([^)]*\\([^)]*[*+]\\)[*+]|/[^/]*\\([^)]*[*+]\\)[*+][^/]*/",
|
|
12
|
+
"flags": ""
|
|
13
|
+
},
|
|
14
|
+
"layer": "code",
|
|
15
|
+
"category": "regex-dos",
|
|
16
|
+
"remediation": {
|
|
17
|
+
"title": "Avoid nested quantifiers",
|
|
18
|
+
"suggestions": [
|
|
19
|
+
"Simplify regex to avoid nested quantifiers like (a+)+",
|
|
20
|
+
"Use atomic groups or possessive quantifiers if supported",
|
|
21
|
+
"Set timeout for regex execution in production",
|
|
22
|
+
"Test regex with long inputs to detect exponential behavior",
|
|
23
|
+
"Consider using dedicated parsing libraries for complex formats"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "redos-002",
|
|
29
|
+
"name": "Regex with overlapping alternatives",
|
|
30
|
+
"description": "Regex with overlapping alternatives can cause catastrophic backtracking",
|
|
31
|
+
"severity": "LOW",
|
|
32
|
+
"match": {
|
|
33
|
+
"type": "regex",
|
|
34
|
+
"value": "new RegExp\\([^)]*\\|.*\\|.*\\|",
|
|
35
|
+
"flags": ""
|
|
36
|
+
},
|
|
37
|
+
"layer": "code",
|
|
38
|
+
"category": "regex-dos",
|
|
39
|
+
"remediation": {
|
|
40
|
+
"title": "Optimize regex alternatives",
|
|
41
|
+
"suggestions": [
|
|
42
|
+
"Combine overlapping alternatives",
|
|
43
|
+
"Order alternatives from most specific to least specific",
|
|
44
|
+
"Test regex performance with long inputs",
|
|
45
|
+
"Consider using string operations instead of regex for simple cases"
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|