defense-mcp-server 0.9.2 → 0.9.4
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/build/core/auto-installer.js +31 -31
- package/build/core/command-allowlist.js +1 -1
- package/build/core/dependency-validator.js +9 -9
- package/build/core/distro-adapter.js +0 -7
- package/build/core/distro.js +0 -48
- package/build/core/encrypted-state.js +0 -7
- package/build/core/logger.js +1 -1
- package/build/core/pam-utils.js +1 -1
- package/build/core/parsers.js +1 -1
- package/build/core/preflight.js +13 -13
- package/build/core/progress.js +20 -20
- package/build/core/run-command.js +46 -0
- package/build/core/sudo-guard.js +4 -4
- package/build/core/third-party-installer.js +4 -4
- package/build/core/tool-wrapper.js +3 -3
- package/build/tools/access-control.js +6 -6
- package/build/tools/api-security.js +5 -51
- package/build/tools/app-hardening.js +23 -25
- package/build/tools/cloud-security.js +5 -51
- package/build/tools/compliance.js +9 -13
- package/build/tools/container-security.js +51 -52
- package/build/tools/deception.js +8 -54
- package/build/tools/dns-security.js +2 -48
- package/build/tools/encryption.js +86 -87
- package/build/tools/firewall.js +324 -30
- package/build/tools/hardening.js +12 -13
- package/build/tools/incident-response.js +3 -3
- package/build/tools/logging.js +17 -59
- package/build/tools/malware.js +2 -2
- package/build/tools/meta.js +86 -165
- package/build/tools/network-defense.js +3 -3
- package/build/tools/patch-management.js +8 -8
- package/build/tools/process-security.js +38 -92
- package/build/tools/sudo-management.js +36 -36
- package/build/tools/threat-intel.js +2 -48
- package/build/tools/vulnerability-management.js +3 -49
- package/build/tools/waf.js +47 -93
- package/build/tools/wireless-security.js +9 -55
- package/package.json +5 -3
- package/build/core/auto-installer.d.ts +0 -102
- package/build/core/auto-installer.d.ts.map +0 -1
- package/build/core/backup-manager.d.ts +0 -63
- package/build/core/backup-manager.d.ts.map +0 -1
- package/build/core/changelog.d.ts +0 -119
- package/build/core/changelog.d.ts.map +0 -1
- package/build/core/command-allowlist.d.ts +0 -129
- package/build/core/command-allowlist.d.ts.map +0 -1
- package/build/core/config.d.ts +0 -107
- package/build/core/config.d.ts.map +0 -1
- package/build/core/dependency-validator.d.ts +0 -106
- package/build/core/dependency-validator.d.ts.map +0 -1
- package/build/core/distro-adapter.d.ts +0 -177
- package/build/core/distro-adapter.d.ts.map +0 -1
- package/build/core/distro.d.ts +0 -68
- package/build/core/distro.d.ts.map +0 -1
- package/build/core/encrypted-state.d.ts +0 -76
- package/build/core/encrypted-state.d.ts.map +0 -1
- package/build/core/executor.d.ts +0 -65
- package/build/core/executor.d.ts.map +0 -1
- package/build/core/installer.d.ts +0 -129
- package/build/core/installer.d.ts.map +0 -1
- package/build/core/logger.d.ts +0 -118
- package/build/core/logger.d.ts.map +0 -1
- package/build/core/metrics.d.ts +0 -74
- package/build/core/metrics.d.ts.map +0 -1
- package/build/core/metrics.js +0 -97
- package/build/core/output-redactor.d.ts +0 -26
- package/build/core/output-redactor.d.ts.map +0 -1
- package/build/core/pam-utils.d.ts +0 -356
- package/build/core/pam-utils.d.ts.map +0 -1
- package/build/core/parsers.d.ts +0 -191
- package/build/core/parsers.d.ts.map +0 -1
- package/build/core/policy-engine.d.ts +0 -170
- package/build/core/policy-engine.d.ts.map +0 -1
- package/build/core/preflight.d.ts +0 -157
- package/build/core/preflight.d.ts.map +0 -1
- package/build/core/privilege-manager.d.ts +0 -108
- package/build/core/privilege-manager.d.ts.map +0 -1
- package/build/core/progress.d.ts +0 -99
- package/build/core/progress.d.ts.map +0 -1
- package/build/core/rate-limiter.d.ts +0 -101
- package/build/core/rate-limiter.d.ts.map +0 -1
- package/build/core/rollback.d.ts +0 -73
- package/build/core/rollback.d.ts.map +0 -1
- package/build/core/safeguards.d.ts +0 -58
- package/build/core/safeguards.d.ts.map +0 -1
- package/build/core/sanitizer.d.ts +0 -118
- package/build/core/sanitizer.d.ts.map +0 -1
- package/build/core/secure-fs.d.ts +0 -67
- package/build/core/secure-fs.d.ts.map +0 -1
- package/build/core/spawn-safe.d.ts +0 -55
- package/build/core/spawn-safe.d.ts.map +0 -1
- package/build/core/sudo-guard.d.ts +0 -167
- package/build/core/sudo-guard.d.ts.map +0 -1
- package/build/core/sudo-session.d.ts +0 -143
- package/build/core/sudo-session.d.ts.map +0 -1
- package/build/core/third-party-installer.d.ts +0 -58
- package/build/core/third-party-installer.d.ts.map +0 -1
- package/build/core/third-party-manifest.d.ts +0 -48
- package/build/core/third-party-manifest.d.ts.map +0 -1
- package/build/core/tool-annotations.d.ts +0 -13
- package/build/core/tool-annotations.d.ts.map +0 -1
- package/build/core/tool-dependencies.d.ts +0 -60
- package/build/core/tool-dependencies.d.ts.map +0 -1
- package/build/core/tool-durations.d.ts +0 -71
- package/build/core/tool-durations.d.ts.map +0 -1
- package/build/core/tool-registry.d.ts +0 -112
- package/build/core/tool-registry.d.ts.map +0 -1
- package/build/core/tool-wrapper.d.ts +0 -73
- package/build/core/tool-wrapper.d.ts.map +0 -1
- package/build/index.d.ts +0 -3
- package/build/index.d.ts.map +0 -1
- package/build/tools/access-control.d.ts +0 -11
- package/build/tools/access-control.d.ts.map +0 -1
- package/build/tools/api-security.d.ts +0 -12
- package/build/tools/api-security.d.ts.map +0 -1
- package/build/tools/app-hardening.d.ts +0 -11
- package/build/tools/app-hardening.d.ts.map +0 -1
- package/build/tools/backup.d.ts +0 -8
- package/build/tools/backup.d.ts.map +0 -1
- package/build/tools/cloud-security.d.ts +0 -17
- package/build/tools/cloud-security.d.ts.map +0 -1
- package/build/tools/compliance.d.ts +0 -11
- package/build/tools/compliance.d.ts.map +0 -1
- package/build/tools/container-security.d.ts +0 -14
- package/build/tools/container-security.d.ts.map +0 -1
- package/build/tools/deception.d.ts +0 -13
- package/build/tools/deception.d.ts.map +0 -1
- package/build/tools/dns-security.d.ts +0 -93
- package/build/tools/dns-security.d.ts.map +0 -1
- package/build/tools/ebpf-security.d.ts +0 -15
- package/build/tools/ebpf-security.d.ts.map +0 -1
- package/build/tools/encryption.d.ts +0 -12
- package/build/tools/encryption.d.ts.map +0 -1
- package/build/tools/firewall.d.ts +0 -9
- package/build/tools/firewall.d.ts.map +0 -1
- package/build/tools/hardening.d.ts +0 -8
- package/build/tools/hardening.d.ts.map +0 -1
- package/build/tools/incident-response.d.ts +0 -11
- package/build/tools/incident-response.d.ts.map +0 -1
- package/build/tools/integrity.d.ts +0 -15
- package/build/tools/integrity.d.ts.map +0 -1
- package/build/tools/logging.d.ts +0 -21
- package/build/tools/logging.d.ts.map +0 -1
- package/build/tools/malware.d.ts +0 -10
- package/build/tools/malware.d.ts.map +0 -1
- package/build/tools/meta.d.ts +0 -13
- package/build/tools/meta.d.ts.map +0 -1
- package/build/tools/network-defense.d.ts +0 -11
- package/build/tools/network-defense.d.ts.map +0 -1
- package/build/tools/patch-management.d.ts +0 -3
- package/build/tools/patch-management.d.ts.map +0 -1
- package/build/tools/process-security.d.ts +0 -12
- package/build/tools/process-security.d.ts.map +0 -1
- package/build/tools/secrets.d.ts +0 -8
- package/build/tools/secrets.d.ts.map +0 -1
- package/build/tools/sudo-management.d.ts +0 -17
- package/build/tools/sudo-management.d.ts.map +0 -1
- package/build/tools/supply-chain-security.d.ts +0 -8
- package/build/tools/supply-chain-security.d.ts.map +0 -1
- package/build/tools/threat-intel.d.ts +0 -22
- package/build/tools/threat-intel.d.ts.map +0 -1
- package/build/tools/vulnerability-management.d.ts +0 -11
- package/build/tools/vulnerability-management.d.ts.map +0 -1
- package/build/tools/waf.d.ts +0 -12
- package/build/tools/waf.d.ts.map +0 -1
- package/build/tools/wireless-security.d.ts +0 -19
- package/build/tools/wireless-security.d.ts.map +0 -1
- package/build/tools/zero-trust-network.d.ts +0 -8
- package/build/tools/zero-trust-network.d.ts.map +0 -1
|
@@ -382,7 +382,7 @@ export function registerNetworkDefenseTools(server) {
|
|
|
382
382
|
findings.push({ check: sc.key, status: current === sc.expected ? "PASS" : "FAIL", value: current, description: `${sc.desc} (should be ${sc.expected})` });
|
|
383
383
|
}
|
|
384
384
|
}
|
|
385
|
-
return { content: [createTextContent(JSON.stringify({ summary: { total: findings.length, pass: findings.filter(f => f.status === "PASS").length, fail: findings.filter(f => f.status === "FAIL").length }, ipv6Enabled: !disabled, findings }
|
|
385
|
+
return { content: [createTextContent(JSON.stringify({ summary: { total: findings.length, pass: findings.filter(f => f.status === "PASS").length, fail: findings.filter(f => f.status === "FAIL").length }, ipv6Enabled: !disabled, findings }))] };
|
|
386
386
|
}
|
|
387
387
|
catch (error) {
|
|
388
388
|
return { content: [createErrorContent(error instanceof Error ? error.message : String(error))], isError: true };
|
|
@@ -557,7 +557,7 @@ export function registerNetworkDefenseTools(server) {
|
|
|
557
557
|
if (violations.length > 0) {
|
|
558
558
|
text += `--- Violations ---\n`;
|
|
559
559
|
for (const v of violations) {
|
|
560
|
-
text += `
|
|
560
|
+
text += ` WARNING: ${v}\n`;
|
|
561
561
|
}
|
|
562
562
|
}
|
|
563
563
|
if (natBypasses.length > 0) {
|
|
@@ -692,7 +692,7 @@ export function registerNetworkDefenseTools(server) {
|
|
|
692
692
|
if (concerns.length > 0) {
|
|
693
693
|
text += `--- Security Concerns ---\n`;
|
|
694
694
|
for (const c of concerns) {
|
|
695
|
-
text += `
|
|
695
|
+
text += ` WARNING: ${c}\n`;
|
|
696
696
|
}
|
|
697
697
|
}
|
|
698
698
|
return { content: [createTextContent(text)] };
|
|
@@ -183,7 +183,7 @@ export function registerPatchManagementTools(server) {
|
|
|
183
183
|
status: packages.length === 0 ? "UP_TO_DATE" : securityPkgs.length > 0 ? "SECURITY_UPDATES_PENDING" : "UPDATES_AVAILABLE",
|
|
184
184
|
},
|
|
185
185
|
packages: displayPkgs.slice(0, 100),
|
|
186
|
-
}
|
|
186
|
+
}))],
|
|
187
187
|
};
|
|
188
188
|
}
|
|
189
189
|
catch (error) {
|
|
@@ -206,7 +206,7 @@ export function registerPatchManagementTools(server) {
|
|
|
206
206
|
supported: false,
|
|
207
207
|
message: `Automatic updates are not natively supported on ${da.distro.name}.`,
|
|
208
208
|
recommendation: au.installHint,
|
|
209
|
-
}
|
|
209
|
+
}))],
|
|
210
210
|
};
|
|
211
211
|
}
|
|
212
212
|
const pkgCheckResult = await executeCommand({
|
|
@@ -325,8 +325,8 @@ export function registerPatchManagementTools(server) {
|
|
|
325
325
|
? `CRITICAL: Install auto-updates: ${au.installHint}`
|
|
326
326
|
: failCount > 0
|
|
327
327
|
? "WARNING: Automatic security updates not fully configured"
|
|
328
|
-
: "
|
|
329
|
-
}
|
|
328
|
+
: "Automatic security updates properly configured",
|
|
329
|
+
}))],
|
|
330
330
|
};
|
|
331
331
|
}
|
|
332
332
|
catch (error) {
|
|
@@ -347,7 +347,7 @@ export function registerPatchManagementTools(server) {
|
|
|
347
347
|
distro: da.summary,
|
|
348
348
|
error: "Package integrity checking not supported on this distribution",
|
|
349
349
|
recommendation: ic.installHint,
|
|
350
|
-
}
|
|
350
|
+
}))],
|
|
351
351
|
};
|
|
352
352
|
}
|
|
353
353
|
let cmd;
|
|
@@ -414,7 +414,7 @@ export function registerPatchManagementTools(server) {
|
|
|
414
414
|
note: changed.length > 0
|
|
415
415
|
? "Modified files detected. Review if changes are legitimate (config edits) or suspicious (potential compromise)."
|
|
416
416
|
: "All checked files match their package checksums.",
|
|
417
|
-
}
|
|
417
|
+
}))],
|
|
418
418
|
};
|
|
419
419
|
}
|
|
420
420
|
catch (error) {
|
|
@@ -425,7 +425,7 @@ export function registerPatchManagementTools(server) {
|
|
|
425
425
|
content: [createTextContent(JSON.stringify({
|
|
426
426
|
error: `${da?.integrity.toolName ?? "Integrity tool"} not available`,
|
|
427
427
|
recommendation: da?.integrity.installHint ?? "Install the appropriate integrity checking tool",
|
|
428
|
-
}
|
|
428
|
+
}))],
|
|
429
429
|
};
|
|
430
430
|
}
|
|
431
431
|
return {
|
|
@@ -560,7 +560,7 @@ export function registerPatchManagementTools(server) {
|
|
|
560
560
|
...(unmitigated.length > 0 ? [`${unmitigated.length} CPU vulnerabilities not fully mitigated`] : []),
|
|
561
561
|
...(installedKernels.length > 3 ? [`Multiple old kernels installed — consider removing unused: ${cleanupHint}`] : []),
|
|
562
562
|
],
|
|
563
|
-
}
|
|
563
|
+
}))],
|
|
564
564
|
};
|
|
565
565
|
}
|
|
566
566
|
catch (error) {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* capability abuse, namespace isolation, anomalous behavior, and cgroup resource limits.
|
|
9
9
|
*/
|
|
10
10
|
import { z } from "zod";
|
|
11
|
-
import {
|
|
11
|
+
import { runCommand } from "../core/run-command.js";
|
|
12
12
|
import { createTextContent, createErrorContent, } from "../core/parsers.js";
|
|
13
13
|
// ── Constants ──────────────────────────────────────────────────────────────────
|
|
14
14
|
/** Processes known to legitimately run as root */
|
|
@@ -27,53 +27,6 @@ const DANGEROUS_CAPABILITIES = new Set([
|
|
|
27
27
|
]);
|
|
28
28
|
/** Maximum number of processes to inspect to avoid overwhelming output */
|
|
29
29
|
const MAX_PROCESSES = 100;
|
|
30
|
-
/**
|
|
31
|
-
* Run a command via spawnSafe and collect output as a promise.
|
|
32
|
-
* Handles errors gracefully — returns error info instead of throwing.
|
|
33
|
-
*/
|
|
34
|
-
async function runCommand(command, args, timeoutMs = 30_000) {
|
|
35
|
-
return new Promise((resolve) => {
|
|
36
|
-
let child;
|
|
37
|
-
try {
|
|
38
|
-
child = spawnSafe(command, args);
|
|
39
|
-
}
|
|
40
|
-
catch (err) {
|
|
41
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
42
|
-
resolve({ stdout: "", stderr: msg, exitCode: -1 });
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
let stdout = "";
|
|
46
|
-
let stderr = "";
|
|
47
|
-
let resolved = false;
|
|
48
|
-
const timer = setTimeout(() => {
|
|
49
|
-
if (!resolved) {
|
|
50
|
-
resolved = true;
|
|
51
|
-
child.kill("SIGTERM");
|
|
52
|
-
resolve({ stdout, stderr: stderr + "\n[TIMEOUT]", exitCode: -1 });
|
|
53
|
-
}
|
|
54
|
-
}, timeoutMs);
|
|
55
|
-
child.stdout?.on("data", (data) => {
|
|
56
|
-
stdout += data.toString();
|
|
57
|
-
});
|
|
58
|
-
child.stderr?.on("data", (data) => {
|
|
59
|
-
stderr += data.toString();
|
|
60
|
-
});
|
|
61
|
-
child.on("close", (code) => {
|
|
62
|
-
if (!resolved) {
|
|
63
|
-
resolved = true;
|
|
64
|
-
clearTimeout(timer);
|
|
65
|
-
resolve({ stdout, stderr, exitCode: code ?? -1 });
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
child.on("error", (err) => {
|
|
69
|
-
if (!resolved) {
|
|
70
|
-
resolved = true;
|
|
71
|
-
clearTimeout(timer);
|
|
72
|
-
resolve({ stdout, stderr: err.message, exitCode: -1 });
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
30
|
/**
|
|
78
31
|
* Parse `ps auxf` output into structured process info.
|
|
79
32
|
*/
|
|
@@ -133,12 +86,12 @@ function isUnusualPath(command) {
|
|
|
133
86
|
async function auditRunning(pid, filter, showAll) {
|
|
134
87
|
const sections = [];
|
|
135
88
|
const findings = [];
|
|
136
|
-
sections.push("
|
|
137
|
-
sections.push("
|
|
89
|
+
sections.push("Process Security Audit");
|
|
90
|
+
sections.push("");
|
|
138
91
|
// Get process list
|
|
139
92
|
const psResult = await runCommand("ps", ["auxf"]);
|
|
140
93
|
if (psResult.exitCode !== 0) {
|
|
141
|
-
sections.push(`\
|
|
94
|
+
sections.push(`\nWARNING: Failed to get process list: ${psResult.stderr}`);
|
|
142
95
|
return { sections, findings };
|
|
143
96
|
}
|
|
144
97
|
let processes = parsePsOutput(psResult.stdout);
|
|
@@ -146,7 +99,7 @@ async function auditRunning(pid, filter, showAll) {
|
|
|
146
99
|
if (pid !== undefined) {
|
|
147
100
|
processes = processes.filter((p) => p.pid === pid);
|
|
148
101
|
if (processes.length === 0) {
|
|
149
|
-
sections.push(`\
|
|
102
|
+
sections.push(`\nWARNING: No process found with PID ${pid}`);
|
|
150
103
|
return { sections, findings };
|
|
151
104
|
}
|
|
152
105
|
}
|
|
@@ -233,7 +186,7 @@ async function auditRunning(pid, filter, showAll) {
|
|
|
233
186
|
if (deletedExe.length > 0) {
|
|
234
187
|
sections.push("\n── Processes with Deleted Executables ──");
|
|
235
188
|
for (const p of deletedExe) {
|
|
236
|
-
sections.push(`
|
|
189
|
+
sections.push(` CRITICAL: PID ${p.pid}: ${p.command}`);
|
|
237
190
|
findings.push({
|
|
238
191
|
severity: "CRITICAL",
|
|
239
192
|
category: "deleted_exe",
|
|
@@ -245,7 +198,7 @@ async function auditRunning(pid, filter, showAll) {
|
|
|
245
198
|
}
|
|
246
199
|
// Summary
|
|
247
200
|
if (!showAll && findings.length === 0) {
|
|
248
|
-
sections.push("\
|
|
201
|
+
sections.push("\nNo suspicious processes detected.");
|
|
249
202
|
}
|
|
250
203
|
else if (showAll) {
|
|
251
204
|
sections.push("\n── All Processes ──");
|
|
@@ -258,13 +211,13 @@ async function auditRunning(pid, filter, showAll) {
|
|
|
258
211
|
async function checkCapabilities(pid, filter) {
|
|
259
212
|
const sections = [];
|
|
260
213
|
const findings = [];
|
|
261
|
-
sections.push("
|
|
262
|
-
sections.push("
|
|
214
|
+
sections.push("Process Capabilities Check");
|
|
215
|
+
sections.push("");
|
|
263
216
|
if (pid !== undefined) {
|
|
264
217
|
// Check specific PID capabilities
|
|
265
218
|
const capsResult = await runCommand("getpcaps", [String(pid)]);
|
|
266
219
|
if (capsResult.exitCode !== 0) {
|
|
267
|
-
sections.push(`\
|
|
220
|
+
sections.push(`\nWARNING: Failed to get capabilities for PID ${pid}: ${capsResult.stderr}`);
|
|
268
221
|
return { sections, findings };
|
|
269
222
|
}
|
|
270
223
|
sections.push(`\nCapabilities for PID ${pid}:`);
|
|
@@ -286,7 +239,7 @@ async function checkCapabilities(pid, filter) {
|
|
|
286
239
|
// Scan processes for elevated capabilities
|
|
287
240
|
const psResult = await runCommand("ps", ["-eo", "pid"]);
|
|
288
241
|
if (psResult.exitCode !== 0) {
|
|
289
|
-
sections.push("\
|
|
242
|
+
sections.push("\nWARNING: Failed to list processes");
|
|
290
243
|
return { sections, findings };
|
|
291
244
|
}
|
|
292
245
|
const pids = psResult.stdout.trim().split("\n")
|
|
@@ -340,7 +293,7 @@ async function checkCapabilities(pid, filter) {
|
|
|
340
293
|
}
|
|
341
294
|
}
|
|
342
295
|
else {
|
|
343
|
-
sections.push("\
|
|
296
|
+
sections.push("\nNo processes with elevated capabilities found.");
|
|
344
297
|
}
|
|
345
298
|
}
|
|
346
299
|
return { sections, findings };
|
|
@@ -348,13 +301,13 @@ async function checkCapabilities(pid, filter) {
|
|
|
348
301
|
async function checkNamespaces(pid, _filter) {
|
|
349
302
|
const sections = [];
|
|
350
303
|
const findings = [];
|
|
351
|
-
sections.push("
|
|
352
|
-
sections.push("
|
|
304
|
+
sections.push("Process Namespace Analysis");
|
|
305
|
+
sections.push("");
|
|
353
306
|
if (pid !== undefined) {
|
|
354
307
|
// Show namespace details for specific PID
|
|
355
308
|
const nsResult = await runCommand("ls", ["-la", `/proc/${pid}/ns/`]);
|
|
356
309
|
if (nsResult.exitCode !== 0) {
|
|
357
|
-
sections.push(`\
|
|
310
|
+
sections.push(`\nCannot read namespaces for PID ${pid}: ${nsResult.stderr}`);
|
|
358
311
|
return { sections, findings };
|
|
359
312
|
}
|
|
360
313
|
sections.push(`\nNamespace details for PID ${pid}:`);
|
|
@@ -380,7 +333,7 @@ async function checkNamespaces(pid, _filter) {
|
|
|
380
333
|
for (const [nsType, nsId] of pidNsMap) {
|
|
381
334
|
const initId = initNsMap.get(nsType);
|
|
382
335
|
const inRootNs = initId === nsId;
|
|
383
|
-
const icon = inRootNs ? "
|
|
336
|
+
const icon = inRootNs ? "WARNING" : "PASS";
|
|
384
337
|
sections.push(` ${icon} ${nsType}: ${inRootNs ? "in root namespace" : "isolated"} (${nsId})`);
|
|
385
338
|
if (inRootNs && !["user", "cgroup"].includes(nsType)) {
|
|
386
339
|
findings.push({
|
|
@@ -400,7 +353,7 @@ async function checkNamespaces(pid, _filter) {
|
|
|
400
353
|
// Retry with sudo
|
|
401
354
|
const sudoLsnsResult = await runCommand("sudo", ["lsns"]);
|
|
402
355
|
if (sudoLsnsResult.exitCode !== 0) {
|
|
403
|
-
sections.push("\
|
|
356
|
+
sections.push("\nCannot list namespaces (lsns not available or permission denied)");
|
|
404
357
|
return { sections, findings };
|
|
405
358
|
}
|
|
406
359
|
sections.push("\n── Active Namespaces ──");
|
|
@@ -437,12 +390,12 @@ async function checkNamespaces(pid, _filter) {
|
|
|
437
390
|
async function detectAnomalies(pid, filter) {
|
|
438
391
|
const sections = [];
|
|
439
392
|
const findings = [];
|
|
440
|
-
sections.push("
|
|
441
|
-
sections.push("
|
|
393
|
+
sections.push("Process Anomaly Detection");
|
|
394
|
+
sections.push("");
|
|
442
395
|
// Get process list for analysis
|
|
443
396
|
const psResult = await runCommand("ps", ["-eo", "pid,ppid,user,comm"]);
|
|
444
397
|
if (psResult.exitCode !== 0) {
|
|
445
|
-
sections.push("\
|
|
398
|
+
sections.push("\nWARNING: Failed to get process list");
|
|
446
399
|
return { sections, findings };
|
|
447
400
|
}
|
|
448
401
|
const psLines = psResult.stdout.trim().split("\n").slice(1);
|
|
@@ -472,7 +425,7 @@ async function detectAnomalies(pid, filter) {
|
|
|
472
425
|
const exeResult = await runCommand("ls", ["-la", `/proc/${proc.pid}/exe`]);
|
|
473
426
|
if (exeResult.exitCode === 0 && exeResult.stdout.includes("(deleted)")) {
|
|
474
427
|
deletedCount++;
|
|
475
|
-
sections.push(`
|
|
428
|
+
sections.push(` CRITICAL: PID ${proc.pid} (${proc.comm}): executable deleted`);
|
|
476
429
|
findings.push({
|
|
477
430
|
severity: "CRITICAL",
|
|
478
431
|
category: "deleted_binary",
|
|
@@ -483,7 +436,7 @@ async function detectAnomalies(pid, filter) {
|
|
|
483
436
|
}
|
|
484
437
|
}
|
|
485
438
|
if (deletedCount === 0)
|
|
486
|
-
sections.push("
|
|
439
|
+
sections.push(" No processes with deleted binaries");
|
|
487
440
|
// 2. Cross-reference network connections with expected services
|
|
488
441
|
sections.push("\n── Unexpected Network Connections ──");
|
|
489
442
|
const ssResult = await runCommand("ss", ["-tlnp"]);
|
|
@@ -493,11 +446,11 @@ async function detectAnomalies(pid, filter) {
|
|
|
493
446
|
sections.push(` ${line.trim()}`);
|
|
494
447
|
}
|
|
495
448
|
if (ssLines.length === 0) {
|
|
496
|
-
sections.push("
|
|
449
|
+
sections.push(" No listening TCP connections");
|
|
497
450
|
}
|
|
498
451
|
}
|
|
499
452
|
else {
|
|
500
|
-
sections.push("
|
|
453
|
+
sections.push(" Could not check network connections");
|
|
501
454
|
}
|
|
502
455
|
// 3. Check for shell spawning from non-shell parents
|
|
503
456
|
sections.push("\n── Shell Spawning Analysis ──");
|
|
@@ -511,7 +464,7 @@ async function detectAnomalies(pid, filter) {
|
|
|
511
464
|
parent.comm !== "screen" && parent.comm !== "tmux" && parent.comm !== "script" &&
|
|
512
465
|
parent.comm !== "getty" && parent.comm !== "agetty" && parent.comm !== "systemd") {
|
|
513
466
|
suspiciousShellCount++;
|
|
514
|
-
sections.push(`
|
|
467
|
+
sections.push(` WARNING: PID ${shell.pid} (${shell.comm}) spawned by ${parent.comm} (PID ${parent.pid})`);
|
|
515
468
|
findings.push({
|
|
516
469
|
severity: "HIGH",
|
|
517
470
|
category: "suspicious_shell",
|
|
@@ -522,7 +475,7 @@ async function detectAnomalies(pid, filter) {
|
|
|
522
475
|
}
|
|
523
476
|
}
|
|
524
477
|
if (suspiciousShellCount === 0)
|
|
525
|
-
sections.push("
|
|
478
|
+
sections.push(" No suspicious shell spawning detected");
|
|
526
479
|
// 4. Check for open file descriptors to sensitive files
|
|
527
480
|
sections.push("\n── Sensitive File Access ──");
|
|
528
481
|
const sensitiveFiles = ["/etc/shadow", "/etc/passwd", ".ssh/id_rsa", ".ssh/id_ed25519", "private.key"];
|
|
@@ -535,7 +488,7 @@ async function detectAnomalies(pid, filter) {
|
|
|
535
488
|
for (const sf of sensitiveFiles) {
|
|
536
489
|
if (fdResult.stdout.includes(sf)) {
|
|
537
490
|
sensitiveAccessCount++;
|
|
538
|
-
sections.push(`
|
|
491
|
+
sections.push(` WARNING: PID ${proc.pid} (${proc.comm}) has open fd to ${sf}`);
|
|
539
492
|
findings.push({
|
|
540
493
|
severity: "HIGH",
|
|
541
494
|
category: "sensitive_file_access",
|
|
@@ -547,7 +500,7 @@ async function detectAnomalies(pid, filter) {
|
|
|
547
500
|
}
|
|
548
501
|
}
|
|
549
502
|
if (sensitiveAccessCount === 0)
|
|
550
|
-
sections.push("
|
|
503
|
+
sections.push(" No suspicious sensitive file access");
|
|
551
504
|
// 5. Check for suspicious environment variables
|
|
552
505
|
sections.push("\n── Suspicious Environment Variables ──");
|
|
553
506
|
let suspiciousEnvCount = 0;
|
|
@@ -561,7 +514,7 @@ async function detectAnomalies(pid, filter) {
|
|
|
561
514
|
envStr.includes("nc -e") || envStr.includes("mkfifo") ||
|
|
562
515
|
envStr.includes("PAYLOAD") || envStr.includes("SHELLCODE")) {
|
|
563
516
|
suspiciousEnvCount++;
|
|
564
|
-
sections.push(`
|
|
517
|
+
sections.push(` CRITICAL: PID ${proc.pid} (${proc.comm}): suspicious environment variables detected`);
|
|
565
518
|
findings.push({
|
|
566
519
|
severity: "CRITICAL",
|
|
567
520
|
category: "suspicious_env",
|
|
@@ -572,19 +525,19 @@ async function detectAnomalies(pid, filter) {
|
|
|
572
525
|
}
|
|
573
526
|
}
|
|
574
527
|
if (suspiciousEnvCount === 0)
|
|
575
|
-
sections.push("
|
|
528
|
+
sections.push(" No suspicious environment variables detected");
|
|
576
529
|
return { sections, findings };
|
|
577
530
|
}
|
|
578
531
|
async function cgroupAudit(pid, _filter) {
|
|
579
532
|
const sections = [];
|
|
580
533
|
const findings = [];
|
|
581
|
-
sections.push("
|
|
582
|
-
sections.push("
|
|
534
|
+
sections.push("Cgroup Resource Audit");
|
|
535
|
+
sections.push("");
|
|
583
536
|
if (pid !== undefined) {
|
|
584
537
|
// Inspect specific process cgroup membership
|
|
585
538
|
const cgroupResult = await runCommand("cat", [`/proc/${pid}/cgroup`]);
|
|
586
539
|
if (cgroupResult.exitCode !== 0) {
|
|
587
|
-
sections.push(`\
|
|
540
|
+
sections.push(`\nCannot read cgroup for PID ${pid}: ${cgroupResult.stderr}`);
|
|
588
541
|
return { sections, findings };
|
|
589
542
|
}
|
|
590
543
|
sections.push(`\nCgroup membership for PID ${pid}:`);
|
|
@@ -600,7 +553,7 @@ async function cgroupAudit(pid, _filter) {
|
|
|
600
553
|
const memMaxResult = await runCommand("cat", [`/sys/fs/cgroup${cgroupPath}/memory.max`]);
|
|
601
554
|
if (memMaxResult.exitCode === 0) {
|
|
602
555
|
const memMax = memMaxResult.stdout.trim();
|
|
603
|
-
sections.push(` Memory limit: ${memMax === "max" ? "unlimited
|
|
556
|
+
sections.push(` Memory limit: ${memMax === "max" ? "unlimited WARNING" : memMax}`);
|
|
604
557
|
if (memMax === "max") {
|
|
605
558
|
findings.push({
|
|
606
559
|
severity: "LOW",
|
|
@@ -613,7 +566,7 @@ async function cgroupAudit(pid, _filter) {
|
|
|
613
566
|
const cpuMaxResult = await runCommand("cat", [`/sys/fs/cgroup${cgroupPath}/cpu.max`]);
|
|
614
567
|
if (cpuMaxResult.exitCode === 0) {
|
|
615
568
|
const cpuMax = cpuMaxResult.stdout.trim();
|
|
616
|
-
sections.push(` CPU limit: ${cpuMax === "max 100000" ? "unlimited
|
|
569
|
+
sections.push(` CPU limit: ${cpuMax === "max 100000" ? "unlimited WARNING" : cpuMax}`);
|
|
617
570
|
if (cpuMax.startsWith("max")) {
|
|
618
571
|
findings.push({
|
|
619
572
|
severity: "LOW",
|
|
@@ -669,7 +622,7 @@ async function cgroupAudit(pid, _filter) {
|
|
|
669
622
|
// ── Format helpers ─────────────────────────────────────────────────────────────
|
|
670
623
|
function formatFindings(findings) {
|
|
671
624
|
if (findings.length === 0)
|
|
672
|
-
return "\
|
|
625
|
+
return "\nNo security findings.";
|
|
673
626
|
const lines = ["\n── Security Findings Summary ──"];
|
|
674
627
|
const bySeverity = {};
|
|
675
628
|
for (const f of findings) {
|
|
@@ -678,18 +631,11 @@ function formatFindings(findings) {
|
|
|
678
631
|
bySeverity[f.severity].push(f);
|
|
679
632
|
}
|
|
680
633
|
const severityOrder = ["CRITICAL", "HIGH", "MEDIUM", "LOW", "INFO"];
|
|
681
|
-
const icons = {
|
|
682
|
-
CRITICAL: "⛔",
|
|
683
|
-
HIGH: "🔴",
|
|
684
|
-
MEDIUM: "🟠",
|
|
685
|
-
LOW: "🟡",
|
|
686
|
-
INFO: "ℹ️",
|
|
687
|
-
};
|
|
688
634
|
for (const sev of severityOrder) {
|
|
689
635
|
const items = bySeverity[sev];
|
|
690
636
|
if (!items || items.length === 0)
|
|
691
637
|
continue;
|
|
692
|
-
lines.push(`\n ${
|
|
638
|
+
lines.push(`\n ${sev} (${items.length}):`);
|
|
693
639
|
for (const f of items) {
|
|
694
640
|
const pidStr = f.pid ? ` [PID ${f.pid}]` : "";
|
|
695
641
|
lines.push(` - ${f.message}${pidStr}`);
|
|
@@ -710,7 +656,7 @@ function formatAsJson(action, findings, rawSections) {
|
|
|
710
656
|
process: f.process || null,
|
|
711
657
|
})),
|
|
712
658
|
rawOutput: rawSections.join("\n"),
|
|
713
|
-
}
|
|
659
|
+
});
|
|
714
660
|
}
|
|
715
661
|
// ── Registration entry point ───────────────────────────────────────────────
|
|
716
662
|
export function registerProcessSecurityTools(server) {
|