omen-sec-cli 1.0.16 → 1.0.18
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/README.md +56 -63
- package/bin/index.js +67 -25
- package/core/discover/stack-detector.js +67 -0
- package/core/engine-v2.js +170 -0
- package/core/generator.js +43 -11
- package/core/local-scanner.js +154 -41
- package/core/remote-scanner.js +220 -98
- package/core/reporters/fix-plan-reporter.js +46 -0
- package/core/reporters/markdown-reporter.js +25 -0
- package/core/runners/local-app-runner.js +39 -0
- package/core/scanner.js +34 -24
- package/core/state/state-manager.js +43 -0
- package/core/ui-server.js +101 -37
- package/package.json +6 -1
- package/ui/banner.js +1 -1
package/core/local-scanner.js
CHANGED
|
@@ -45,10 +45,15 @@ export async function scanLocalProject() {
|
|
|
45
45
|
osvRes.data.vulns.forEach(vuln => {
|
|
46
46
|
vulnerabilities.push({
|
|
47
47
|
id: vuln.id,
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
kind: 'tech',
|
|
49
|
+
category: 'confirmed',
|
|
50
|
+
confidence: 'high',
|
|
51
|
+
severity: 'high',
|
|
52
|
+
title: `Vulnerable Dependency: ${name}`,
|
|
50
53
|
description: `Real CVE found for ${name}@${cleanVersion}: ${vuln.summary || vuln.details}`,
|
|
51
|
-
cwe: vuln.database_specific?.cwe_ids?.[0] || 'N/A'
|
|
54
|
+
cwe: vuln.database_specific?.cwe_ids?.[0] || 'N/A',
|
|
55
|
+
evidence: { package: name, version: cleanVersion, vuln_id: vuln.id },
|
|
56
|
+
remediation: `Update ${name} to a secure version as recommended by OSV/NVD.`
|
|
52
57
|
});
|
|
53
58
|
});
|
|
54
59
|
}
|
|
@@ -57,27 +62,33 @@ export async function scanLocalProject() {
|
|
|
57
62
|
}
|
|
58
63
|
}
|
|
59
64
|
|
|
60
|
-
//
|
|
65
|
+
// Fallback mocks
|
|
61
66
|
if (deps['lodash'] && deps['lodash'].match(/[~^]?4\.17\.[0-20]/)) {
|
|
62
67
|
vulnerabilities.push({
|
|
63
68
|
id: `LOC-VULN-${Date.now()}-1`,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
kind: 'tech',
|
|
70
|
+
category: 'confirmed',
|
|
71
|
+
confidence: 'high',
|
|
72
|
+
severity: 'high',
|
|
73
|
+
title: 'Vulnerable Lodash Version',
|
|
67
74
|
description: `Outdated dependency detected in package.json: lodash (${deps['lodash']}). Known Prototype Pollution risk.`,
|
|
68
75
|
cwe: 'CWE-1321',
|
|
69
|
-
evidence: { file: 'package.json', finding: `lodash: ${deps['lodash']}` }
|
|
76
|
+
evidence: { file: 'package.json', finding: `lodash: ${deps['lodash']}` },
|
|
77
|
+
remediation: 'Update lodash to version 4.17.21 or higher.'
|
|
70
78
|
});
|
|
71
79
|
}
|
|
72
80
|
if (deps['express'] && deps['express'].match(/[~^]?3\./)) {
|
|
73
81
|
vulnerabilities.push({
|
|
74
82
|
id: `LOC-VULN-${Date.now()}-2`,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
83
|
+
kind: 'tech',
|
|
84
|
+
category: 'confirmed',
|
|
85
|
+
confidence: 'high',
|
|
86
|
+
severity: 'high',
|
|
87
|
+
title: 'Critical Outdated Express',
|
|
78
88
|
description: `Severely outdated Express.js version (${deps['express']}) detected. Multiple CVEs exist.`,
|
|
79
89
|
cwe: 'CWE-1104',
|
|
80
|
-
evidence: { file: 'package.json', finding: `express: ${deps['express']}` }
|
|
90
|
+
evidence: { file: 'package.json', finding: `express: ${deps['express']}` },
|
|
91
|
+
remediation: 'Upgrade Express.js to the latest stable version (4.x or 5.x).'
|
|
81
92
|
});
|
|
82
93
|
}
|
|
83
94
|
} catch (err) {
|
|
@@ -98,55 +109,154 @@ export async function scanLocalProject() {
|
|
|
98
109
|
filesScanned.push(path.basename(file));
|
|
99
110
|
|
|
100
111
|
lines.forEach((line, index) => {
|
|
101
|
-
// Regra 1: Hardcoded Secrets (
|
|
102
|
-
|
|
112
|
+
// Regra 1: Hardcoded Secrets (Improved)
|
|
113
|
+
const secretRegex = /(api_key|apikey|secret|password|token|jwt_secret|connection_string|private_key|aws_key|aws_secret|db_pass)\s*[:=]\s*['"][a-zA-Z0-9_\-\.\/\+\=]{12,}['"]/i;
|
|
114
|
+
if (secretRegex.test(line)) {
|
|
103
115
|
vulnerabilities.push({
|
|
104
|
-
id: `LOC-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
116
|
+
id: `LOC-SEC-${Date.now()}-${index}`,
|
|
117
|
+
kind: 'content',
|
|
118
|
+
category: 'confirmed',
|
|
119
|
+
confidence: 'high',
|
|
120
|
+
severity: 'critical',
|
|
121
|
+
title: 'Exposed Hardcoded Secret',
|
|
122
|
+
description: `A potential sensitive credential or token was found hardcoded in ${path.basename(file)} at line ${index + 1}.`,
|
|
109
123
|
cwe: 'CWE-798',
|
|
110
|
-
evidence: { file: path.basename(file), line: index + 1, code: line.trim() }
|
|
124
|
+
evidence: { file: path.basename(file), line: index + 1, code: line.trim() },
|
|
125
|
+
remediation: 'Immediately rotate this secret and move it to an environment variable or a secret manager vault.'
|
|
111
126
|
});
|
|
112
127
|
}
|
|
113
128
|
|
|
114
|
-
// Regra
|
|
129
|
+
// Regra 10: Insecure CORS configuration
|
|
130
|
+
if (/Access-Control-Allow-Origin.*\*['"]/i.test(line)) {
|
|
131
|
+
vulnerabilities.push({
|
|
132
|
+
id: `LOC-CORS-${Date.now()}-${index}`,
|
|
133
|
+
kind: 'content',
|
|
134
|
+
category: 'hardening',
|
|
135
|
+
confidence: 'high',
|
|
136
|
+
severity: 'medium',
|
|
137
|
+
title: 'Overly Permissive CORS Policy',
|
|
138
|
+
description: `CORS policy allows all origins (*) in ${path.basename(file)} at line ${index + 1}. This can lead to CSRF or data leakage.`,
|
|
139
|
+
cwe: 'CWE-942',
|
|
140
|
+
evidence: { file: path.basename(file), line: index + 1, code: line.trim() },
|
|
141
|
+
remediation: 'Restrict Access-Control-Allow-Origin to specific, trusted domains instead of using "*".'
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Regra 11: Insecure Cookie Attributes
|
|
146
|
+
if (/res\.cookie\(.*\{/i.test(line) && !/httpOnly:\s*true/i.test(line)) {
|
|
147
|
+
vulnerabilities.push({
|
|
148
|
+
id: `LOC-COOKIE-${Date.now()}-${index}`,
|
|
149
|
+
kind: 'content',
|
|
150
|
+
category: 'hardening',
|
|
151
|
+
confidence: 'medium',
|
|
152
|
+
severity: 'low',
|
|
153
|
+
title: 'Insecure Cookie (Missing httpOnly)',
|
|
154
|
+
description: `Cookie created without 'httpOnly' flag in ${path.basename(file)} at line ${index + 1}. This makes the cookie accessible via client-side scripts (XSS risk).`,
|
|
155
|
+
cwe: 'CWE-1004',
|
|
156
|
+
evidence: { file: path.basename(file), line: index + 1, code: line.trim() },
|
|
157
|
+
remediation: 'Always set { httpOnly: true } when creating sensitive cookies to prevent XSS-based theft.'
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Regra 12: Insecure Randomness
|
|
162
|
+
if (/Math\.random\(\)/.test(line)) {
|
|
163
|
+
vulnerabilities.push({
|
|
164
|
+
id: `LOC-RAND-${Date.now()}-${index}`,
|
|
165
|
+
kind: 'content',
|
|
166
|
+
category: 'hardening',
|
|
167
|
+
confidence: 'medium',
|
|
168
|
+
severity: 'low',
|
|
169
|
+
title: 'Insecure Randomness',
|
|
170
|
+
description: `Math.random() used in ${path.basename(file)} at line ${index + 1}. This is not cryptographically secure.`,
|
|
171
|
+
cwe: 'CWE-330',
|
|
172
|
+
evidence: { file: path.basename(file), line: index + 1, code: line.trim() },
|
|
173
|
+
remediation: 'Use crypto.getRandomValues() or the "crypto" module for security-sensitive random values.'
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Regra 13: Potential ReDoS (Regex Denial of Service)
|
|
178
|
+
if (/\/\(.*\+\)\+\//.test(line) || /\/\(.*\*\)\*\//.test(line)) {
|
|
179
|
+
vulnerabilities.push({
|
|
180
|
+
id: `LOC-REDOS-${Date.now()}-${index}`,
|
|
181
|
+
kind: 'content',
|
|
182
|
+
category: 'probable',
|
|
183
|
+
confidence: 'medium',
|
|
184
|
+
severity: 'medium',
|
|
185
|
+
title: 'Potential ReDoS Pattern',
|
|
186
|
+
description: `A potentially catastrophic backtracking regex pattern was found in ${path.basename(file)} at line ${index + 1}.`,
|
|
187
|
+
cwe: 'CWE-1333',
|
|
188
|
+
evidence: { file: path.basename(file), line: index + 1, code: line.trim() },
|
|
189
|
+
remediation: 'Review and simplify the regex pattern to avoid nested quantifiers that cause exponential backtracking.'
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Regra 8: Weak JWT Configuration
|
|
194
|
+
if (/jwt\.sign\(.*,\s*['"][^'"]{1,10}['"]\s*,/i.test(line)) {
|
|
195
|
+
vulnerabilities.push({
|
|
196
|
+
id: `LOC-AUTH-${Date.now()}`,
|
|
197
|
+
kind: 'content',
|
|
198
|
+
category: 'confirmed',
|
|
199
|
+
confidence: 'high',
|
|
200
|
+
severity: 'high',
|
|
201
|
+
title: 'Weak JWT Secret detected',
|
|
202
|
+
description: `The JWT signing secret appears to be a short, hardcoded string in ${path.basename(file)}: line ${index + 1}`,
|
|
203
|
+
cwe: 'CWE-522',
|
|
204
|
+
evidence: { file: path.basename(file), line: index + 1, code: line.trim() },
|
|
205
|
+
remediation: 'Use a strong, randomly generated secret stored in environment variables.'
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Regra 9: Missing CSRF Protection (Express example)
|
|
210
|
+
if (discoveryData && discoveryData.stack === 'Node/Express' && path.basename(file) === 'app.js') {
|
|
211
|
+
// This would require multi-line or AST, but let's do a simple check
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
// Regra 2: Uso de Eval
|
|
115
216
|
if (/eval\s*\(/.test(line)) {
|
|
116
217
|
vulnerabilities.push({
|
|
117
218
|
id: `LOC-VULN-${Date.now()}-4`,
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
219
|
+
kind: 'content',
|
|
220
|
+
category: 'confirmed',
|
|
221
|
+
confidence: 'high',
|
|
222
|
+
severity: 'critical',
|
|
223
|
+
title: 'Dangerous eval() Usage',
|
|
121
224
|
description: `Dangerous use of eval() detected in ${path.basename(file)} at line ${index + 1}`,
|
|
122
225
|
cwe: 'CWE-94',
|
|
123
|
-
evidence: { file: path.basename(file), line: index + 1, code: line.trim() }
|
|
226
|
+
evidence: { file: path.basename(file), line: index + 1, code: line.trim() },
|
|
227
|
+
remediation: 'Avoid using eval(). Use safer alternatives like JSON.parse() or specific logic.'
|
|
124
228
|
});
|
|
125
229
|
}
|
|
126
230
|
|
|
127
|
-
// Regra 3: SQLi
|
|
231
|
+
// Regra 3: SQLi
|
|
128
232
|
if (/SELECT.*FROM.*WHERE.*(\+|`|\${)/i.test(line)) {
|
|
129
233
|
vulnerabilities.push({
|
|
130
234
|
id: `LOC-VULN-${Date.now()}-5`,
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
235
|
+
kind: 'content',
|
|
236
|
+
category: 'probable',
|
|
237
|
+
confidence: 'medium',
|
|
238
|
+
severity: 'critical',
|
|
239
|
+
title: 'Potential SQL Injection',
|
|
134
240
|
description: `Potential SQL Injection (raw string concatenation) in ${path.basename(file)} at line ${index + 1}.`,
|
|
135
241
|
cwe: 'CWE-89',
|
|
136
|
-
evidence: { file: path.basename(file), line: index + 1, code: line.trim() }
|
|
242
|
+
evidence: { file: path.basename(file), line: index + 1, code: line.trim() },
|
|
243
|
+
remediation: 'Use parameterized queries or an ORM to prevent SQL injection.'
|
|
137
244
|
});
|
|
138
245
|
}
|
|
139
246
|
|
|
140
|
-
// Regra 6:
|
|
247
|
+
// Regra 6: LFI
|
|
141
248
|
if (/(require|import)\s*\(['"]?.*(\+|`|\${)/i.test(line)) {
|
|
142
249
|
vulnerabilities.push({
|
|
143
250
|
id: `LOC-VULN-${Date.now()}-6`,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
251
|
+
kind: 'content',
|
|
252
|
+
category: 'probable',
|
|
253
|
+
confidence: 'medium',
|
|
254
|
+
severity: 'high',
|
|
255
|
+
title: 'Potential LFI',
|
|
256
|
+
description: `Potential Local File Inclusion (LFI) detected in ${path.basename(file)} at line ${index + 1}.`,
|
|
148
257
|
cwe: 'CWE-22',
|
|
149
|
-
evidence: { file: path.basename(file), line: index + 1, code: line.trim() }
|
|
258
|
+
evidence: { file: path.basename(file), line: index + 1, code: line.trim() },
|
|
259
|
+
remediation: 'Validate and sanitize file paths before dynamic loading.'
|
|
150
260
|
});
|
|
151
261
|
}
|
|
152
262
|
|
|
@@ -154,12 +264,15 @@ export async function scanLocalProject() {
|
|
|
154
264
|
if (/\.prototype\.[a-zA-Z0-9_]+\s*=\s*/.test(line)) {
|
|
155
265
|
vulnerabilities.push({
|
|
156
266
|
id: `LOC-VULN-${Date.now()}-7`,
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
267
|
+
kind: 'content',
|
|
268
|
+
category: 'hardening',
|
|
269
|
+
confidence: 'low',
|
|
270
|
+
severity: 'medium',
|
|
271
|
+
title: 'Prototype Modification Risk',
|
|
272
|
+
description: `Direct prototype modification in ${path.basename(file)} at line ${index + 1}.`,
|
|
161
273
|
cwe: 'CWE-1321',
|
|
162
|
-
evidence: { file: path.basename(file), line: index + 1, code: line.trim() }
|
|
274
|
+
evidence: { file: path.basename(file), line: index + 1, code: line.trim() },
|
|
275
|
+
remediation: 'Avoid direct prototype modification. Use Object.defineProperty if necessary.'
|
|
163
276
|
});
|
|
164
277
|
}
|
|
165
278
|
|