omen-sec-cli 1.0.20 → 1.0.21
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 +2 -2
- package/bin/index.js +1 -1
- package/core/engine-v2.js +6 -1
- package/core/remote-scanner.js +115 -85
- package/core/reporters/fix-plan-reporter.js +1 -1
- package/core/ui-server.js +5 -5
- package/package.json +1 -1
- package/ui/banner.js +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# <p align="center"> <img src="https://img.icons8.com/nolan/128/security-shield.png" width="100" /> <br> OMEN SEC-CLI v1.0.
|
|
1
|
+
# <p align="center"> <img src="https://img.icons8.com/nolan/128/security-shield.png" width="100" /> <br> OMEN SEC-CLI v1.0.21 </p>
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
<img src="https://img.shields.io/badge/Version-1.0.
|
|
4
|
+
<img src="https://img.shields.io/badge/Version-1.0.21-red?style=for-the-badge" />
|
|
5
5
|
<img src="https://img.shields.io/badge/Phase--Based-DevSecOps-000000?style=for-the-badge&logo=openai" />
|
|
6
6
|
<img src="https://img.shields.io/badge/Zero--Copy-AI--Protocol-green?style=for-the-badge" />
|
|
7
7
|
</p>
|
package/bin/index.js
CHANGED
package/core/engine-v2.js
CHANGED
|
@@ -134,7 +134,12 @@ export async function execute() {
|
|
|
134
134
|
target: state.discovery?.path || process.cwd(),
|
|
135
135
|
scan_id: `OMEN-${Date.now()}`,
|
|
136
136
|
discovery: state.discovery || {},
|
|
137
|
-
plan: state.plan || {}
|
|
137
|
+
plan: state.plan || {},
|
|
138
|
+
attack_surface: {
|
|
139
|
+
endpoints: state.discovery?.entrypoints || [],
|
|
140
|
+
tech_stack: state.discovery?.stack ? [state.discovery.stack] : [],
|
|
141
|
+
critical_files: state.discovery?.critical_files || []
|
|
142
|
+
}
|
|
138
143
|
};
|
|
139
144
|
|
|
140
145
|
await saveState(resultData);
|
package/core/remote-scanner.js
CHANGED
|
@@ -15,12 +15,18 @@ export async function scanRemoteTarget(targetUrl) {
|
|
|
15
15
|
const response = await axios.get(targetUrl, {
|
|
16
16
|
timeout: 15000,
|
|
17
17
|
validateStatus: () => true,
|
|
18
|
-
headers: { 'User-Agent': 'OMEN-SEC-CLI/1.0.
|
|
18
|
+
headers: { 'User-Agent': 'OMEN-SEC-CLI/1.0.21 (Security Audit)' }
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
serverStatus = response.status;
|
|
22
22
|
const headers = response.headers;
|
|
23
|
-
const html = response.data;
|
|
23
|
+
const html = response.data || '';
|
|
24
|
+
|
|
25
|
+
// --- WAF / CHALLENGE DETECTION ---
|
|
26
|
+
const isVercelChallenge = headers['x-vercel-mitigated'] === 'challenge' || (typeof html === 'string' && html.includes('Vercel Security Checkpoint'));
|
|
27
|
+
if (isVercelChallenge) {
|
|
28
|
+
techStack.push('Vercel WAF (Challenge Active)');
|
|
29
|
+
}
|
|
24
30
|
|
|
25
31
|
// --- TECHNOLOGY FINGERPRINTING ---
|
|
26
32
|
if (headers['x-powered-by']) techStack.push(headers['x-powered-by']);
|
|
@@ -32,98 +38,100 @@ export async function scanRemoteTarget(targetUrl) {
|
|
|
32
38
|
if (html.includes('nuxt')) techStack.push('Nuxt.js');
|
|
33
39
|
|
|
34
40
|
// --- Header Analysis (Existing - Refined Descriptions) ---
|
|
35
|
-
if (!
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
41
|
+
if (!isVercelChallenge) {
|
|
42
|
+
if (!headers['strict-transport-security']) {
|
|
43
|
+
headers_analysis["Strict-Transport-Security"] = "Missing";
|
|
44
|
+
vulnerabilities.push({
|
|
45
|
+
id: `REM-VULN-${Date.now()}-1`,
|
|
46
|
+
kind: 'header',
|
|
47
|
+
category: 'hardening',
|
|
48
|
+
confidence: 'high',
|
|
49
|
+
severity: 'medium',
|
|
50
|
+
title: 'HSTS Header Missing',
|
|
51
|
+
description: `HTTP Strict-Transport-Security (HSTS) header is missing. This prevents the browser from enforcing HTTPS-only connections for future visits.`,
|
|
52
|
+
cwe: 'CWE-319',
|
|
53
|
+
evidence: {
|
|
54
|
+
request: { headers: { ...response.request.headers } },
|
|
55
|
+
response: { status: response.status, headers: response.headers },
|
|
56
|
+
reason: 'Security header "Strict-Transport-Security" not found in server response.'
|
|
57
|
+
},
|
|
58
|
+
remediation: 'Implement the Strict-Transport-Security header with a long max-age (e.g., 31536000) and the includeSubDomains directive.'
|
|
59
|
+
});
|
|
60
|
+
}
|
|
54
61
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
vulnerabilities.push({
|
|
58
|
-
id: `REM-VULN-${Date.now()}-2`,
|
|
59
|
-
kind: 'header',
|
|
60
|
-
category: 'confirmed',
|
|
61
|
-
confidence: 'high',
|
|
62
|
-
severity: 'high',
|
|
63
|
-
title: 'Content-Security-Policy Missing',
|
|
64
|
-
description: `CSP header is missing. Without a strict Content-Security-Policy, the application is highly vulnerable to Cross-Site Scripting (XSS) and data injection attacks.`,
|
|
65
|
-
cwe: 'CWE-1022',
|
|
66
|
-
evidence: {
|
|
67
|
-
request: { headers: { ...response.request.headers } },
|
|
68
|
-
response: { status: response.status, headers: response.headers },
|
|
69
|
-
reason: 'Security header "Content-Security-Policy" not found in server response.'
|
|
70
|
-
},
|
|
71
|
-
remediation: 'Define a strict Content-Security-Policy to restrict source domains for scripts, styles, and other resources.'
|
|
72
|
-
});
|
|
73
|
-
} else {
|
|
74
|
-
headers_analysis["Content-Security-Policy"] = headers['content-security-policy'];
|
|
75
|
-
if (headers['content-security-policy'].includes("unsafe-inline")) {
|
|
62
|
+
if (!headers['content-security-policy']) {
|
|
63
|
+
headers_analysis["Content-Security-Policy"] = "Missing";
|
|
76
64
|
vulnerabilities.push({
|
|
77
|
-
id: `REM-VULN-${Date.now()}-
|
|
65
|
+
id: `REM-VULN-${Date.now()}-2`,
|
|
78
66
|
kind: 'header',
|
|
79
67
|
category: 'confirmed',
|
|
80
68
|
confidence: 'high',
|
|
81
69
|
severity: 'high',
|
|
82
|
-
title: '
|
|
83
|
-
description: `
|
|
84
|
-
cwe: 'CWE-
|
|
85
|
-
evidence: {
|
|
86
|
-
|
|
70
|
+
title: 'Content-Security-Policy Missing',
|
|
71
|
+
description: `CSP header is missing. Without a strict Content-Security-Policy, the application is highly vulnerable to Cross-Site Scripting (XSS) and data injection attacks.`,
|
|
72
|
+
cwe: 'CWE-1022',
|
|
73
|
+
evidence: {
|
|
74
|
+
request: { headers: { ...response.request.headers } },
|
|
75
|
+
response: { status: response.status, headers: response.headers },
|
|
76
|
+
reason: 'Security header "Content-Security-Policy" not found in server response.'
|
|
77
|
+
},
|
|
78
|
+
remediation: 'Define a strict Content-Security-Policy to restrict source domains for scripts, styles, and other resources.'
|
|
87
79
|
});
|
|
80
|
+
} else {
|
|
81
|
+
headers_analysis["Content-Security-Policy"] = headers['content-security-policy'];
|
|
82
|
+
if (headers['content-security-policy'].includes("unsafe-inline")) {
|
|
83
|
+
vulnerabilities.push({
|
|
84
|
+
id: `REM-VULN-${Date.now()}-3`,
|
|
85
|
+
kind: 'header',
|
|
86
|
+
category: 'confirmed',
|
|
87
|
+
confidence: 'high',
|
|
88
|
+
severity: 'high',
|
|
89
|
+
title: 'Insecure CSP (unsafe-inline)',
|
|
90
|
+
description: `The Content-Security-Policy allows 'unsafe-inline' for scripts or styles, significantly weakening protection against XSS.`,
|
|
91
|
+
cwe: 'CWE-16',
|
|
92
|
+
evidence: { finding: `policy: ${headers['content-security-policy']}` },
|
|
93
|
+
remediation: 'Refactor the application to avoid inline scripts and styles, then remove "unsafe-inline" from the CSP.'
|
|
94
|
+
});
|
|
95
|
+
}
|
|
88
96
|
}
|
|
89
|
-
}
|
|
90
97
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
98
|
+
// 3. Analisar X-Frame-Options
|
|
99
|
+
if (!headers['x-frame-options']) {
|
|
100
|
+
headers_analysis["X-Frame-Options"] = "Missing";
|
|
101
|
+
vulnerabilities.push({
|
|
102
|
+
id: `REM-VULN-${Date.now()}-4`,
|
|
103
|
+
kind: 'header',
|
|
104
|
+
category: 'hardening',
|
|
105
|
+
confidence: 'high',
|
|
106
|
+
severity: 'low',
|
|
107
|
+
title: 'X-Frame-Options Missing',
|
|
108
|
+
description: `Missing X-Frame-Options header. This allows the application to be embedded in an iframe on other domains, increasing Clickjacking risk.`,
|
|
109
|
+
cwe: 'CWE-1021',
|
|
110
|
+
evidence: {
|
|
111
|
+
request: { headers: { ...response.request.headers } },
|
|
112
|
+
response: { status: response.status, headers: response.headers },
|
|
113
|
+
reason: 'Security header "X-Frame-Options" not found. This allows the site to be embedded in iframes on third-party domains.'
|
|
114
|
+
},
|
|
115
|
+
remediation: 'Set the X-Frame-Options header to DENY or SAMEORIGIN.'
|
|
116
|
+
});
|
|
117
|
+
}
|
|
111
118
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
119
|
+
// 3.1 Analisar X-Content-Type-Options
|
|
120
|
+
if (!headers['x-content-type-options']) {
|
|
121
|
+
headers_analysis["X-Content-Type-Options"] = "Missing";
|
|
122
|
+
vulnerabilities.push({
|
|
123
|
+
id: `REM-VULN-${Date.now()}-6`,
|
|
124
|
+
kind: 'header',
|
|
125
|
+
category: 'hardening',
|
|
126
|
+
confidence: 'high',
|
|
127
|
+
severity: 'low',
|
|
128
|
+
title: 'X-Content-Type-Options Missing',
|
|
129
|
+
description: `The X-Content-Type-Options: nosniff header is missing. This could allow the browser to "sniff" the content type, potentially leading to MIME-type sniffing attacks.`,
|
|
130
|
+
cwe: 'CWE-116',
|
|
131
|
+
evidence: { response: { headers: response.headers } },
|
|
132
|
+
remediation: 'Add the "X-Content-Type-Options: nosniff" header to all responses.'
|
|
133
|
+
});
|
|
134
|
+
}
|
|
127
135
|
}
|
|
128
136
|
|
|
129
137
|
// 4. Server Header Leak
|
|
@@ -297,6 +305,8 @@ export async function scanRemoteTarget(targetUrl) {
|
|
|
297
305
|
'/api/auth/session', '/api/graphql', '/actuator/health', '/.ssh/id_rsa'
|
|
298
306
|
];
|
|
299
307
|
|
|
308
|
+
const forbiddenPaths = [];
|
|
309
|
+
|
|
300
310
|
for (const path of aggressivePaths) {
|
|
301
311
|
try {
|
|
302
312
|
const fuzzUrl = new URL(path, targetUrl).href;
|
|
@@ -305,6 +315,11 @@ export async function scanRemoteTarget(targetUrl) {
|
|
|
305
315
|
validateStatus: (status) => status >= 200 && status < 500
|
|
306
316
|
});
|
|
307
317
|
|
|
318
|
+
if (fuzzRes.status === 403) {
|
|
319
|
+
forbiddenPaths.push(path);
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
|
|
308
323
|
const finding = await validateFuzzerFinding(path, fuzzRes, fuzzUrl);
|
|
309
324
|
if (finding) {
|
|
310
325
|
vulnerabilities.push(finding);
|
|
@@ -314,6 +329,21 @@ export async function scanRemoteTarget(targetUrl) {
|
|
|
314
329
|
}
|
|
315
330
|
}
|
|
316
331
|
|
|
332
|
+
if (forbiddenPaths.length > 0) {
|
|
333
|
+
vulnerabilities.push({
|
|
334
|
+
id: `REM-ENUM-FORBIDDEN-${Date.now()}`,
|
|
335
|
+
kind: 'path',
|
|
336
|
+
category: 'informational',
|
|
337
|
+
confidence: 'high',
|
|
338
|
+
severity: 'info',
|
|
339
|
+
title: 'Path Enumeration: Protected Resources',
|
|
340
|
+
description: `Multiple paths (${forbiddenPaths.length}) returned 403 Forbidden, confirming their existence but restricted access.`,
|
|
341
|
+
cwe: 'CWE-204',
|
|
342
|
+
evidence: { forbidden_paths: forbiddenPaths },
|
|
343
|
+
remediation: 'Ensure that 403 responses do not leak internal structure and that access controls are correctly configured.'
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
317
347
|
// --- OFFENSIVE PARAMETER FUZZING ---
|
|
318
348
|
const injectionPayloads = [
|
|
319
349
|
{ type: 'SQLi', param: "' OR '1'='1", severity: 'Critical', cwe: 'CWE-89' },
|
|
@@ -338,7 +368,7 @@ export async function scanRemoteTarget(targetUrl) {
|
|
|
338
368
|
const res = await axios.get(testUrl.href, {
|
|
339
369
|
timeout: 5000,
|
|
340
370
|
validateStatus: () => true,
|
|
341
|
-
headers: { 'User-Agent': 'OMEN-SEC-CLI/1.0.
|
|
371
|
+
headers: { 'User-Agent': 'OMEN-SEC-CLI/1.0.21 (Security Audit)' }
|
|
342
372
|
});
|
|
343
373
|
|
|
344
374
|
const evidence = {
|
|
@@ -41,6 +41,6 @@ export function generateFixPlan(scanData) {
|
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
md += `\n*Gerado automaticamente pelo OMEN SEC-CLI v1.0.
|
|
44
|
+
md += `\n*Gerado automaticamente pelo OMEN SEC-CLI v1.0.21 - Protocolo Zero-Copy AI Ativo*\n`;
|
|
45
45
|
return md;
|
|
46
46
|
}
|
package/core/ui-server.js
CHANGED
|
@@ -128,10 +128,10 @@ export async function startUIServer() {
|
|
|
128
128
|
<span class="w-2 h-2 bg-blue-500 rounded-full mr-2"></span> Phase Intelligence
|
|
129
129
|
</h2>
|
|
130
130
|
<div class="space-y-4 text-sm">
|
|
131
|
-
<div class="flex justify-between border-b border-gray-800 pb-2"> <span class="text-gray-500">
|
|
132
|
-
<div class="flex justify-between border-b border-gray-800 pb-2"> <span class="text-gray-500">
|
|
133
|
-
<div class="flex justify-between border-b border-gray-800 pb-2"> <span class="text-gray-500">
|
|
134
|
-
<div class="flex justify-between border-b border-gray-800 pb-2"> <span class="text-gray-500">
|
|
131
|
+
<div class="flex justify-between border-b border-gray-800 pb-2"> <span class="text-gray-500">Target URL</span> <span class="mono text-gray-300">${(report && report.target) || 'N/A'}</span> </div>
|
|
132
|
+
<div class="flex justify-between border-b border-gray-800 pb-2"> <span class="text-gray-500">Tech Stack</span> <span class="text-gray-300">${(report && report.attack_surface && report.attack_surface.tech_stack && report.attack_surface.tech_stack.join(', ')) || 'N/A'}</span> </div>
|
|
133
|
+
<div class="flex justify-between border-b border-gray-800 pb-2"> <span class="text-gray-500">Endpoints Discovered</span> <span class="text-gray-300">${(report && report.attack_surface && report.attack_surface.endpoints && report.attack_surface.endpoints.length) || 0}</span> </div>
|
|
134
|
+
<div class="flex justify-between border-b border-gray-800 pb-2"> <span class="text-gray-500">Critical Files</span> <span class="text-gray-300">${(report && report.attack_surface && report.attack_surface.critical_files && report.attack_surface.critical_files.length) || 0}</span> </div>
|
|
135
135
|
</div>
|
|
136
136
|
</div>
|
|
137
137
|
</div>
|
|
@@ -266,7 +266,7 @@ export async function startUIServer() {
|
|
|
266
266
|
</div>
|
|
267
267
|
|
|
268
268
|
<footer class="text-center text-gray-600 mt-16 border-t border-gray-900 pt-8 mb-10">
|
|
269
|
-
<p class="text-xs uppercase tracking-widest font-bold mb-2">OMEN Security Framework - v1.0.
|
|
269
|
+
<p class="text-xs uppercase tracking-widest font-bold mb-2">OMEN Security Framework - v1.0.21</p>
|
|
270
270
|
<p class="text-[10px] text-gray-700 italic">"The eye that never sleeps, the code that never fails."</p>
|
|
271
271
|
</footer>
|
|
272
272
|
</div>
|
package/package.json
CHANGED
package/ui/banner.js
CHANGED
|
@@ -9,7 +9,7 @@ export function showBanner() {
|
|
|
9
9
|
╚██████╔╝██║ ╚═╝ ██║███████╗██║ ╚████║
|
|
10
10
|
`));
|
|
11
11
|
console.log(chalk.cyan.bold(' OMEN — AI Security Engine '));
|
|
12
|
-
console.log(chalk.gray(' Version: 1.0.
|
|
12
|
+
console.log(chalk.gray(' Version: 1.0.21 \n'));
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export function showHelp() {
|