check_system_extension
check_system_extension
Verifies that security agent system extensions are loaded and user-approved. Security agents require system extensions to function at the kernel level. Unapproved extensions appear installed but are non-functional. macOS only for system extensions; Windows checks driver/service status.
Metadata
Name
check_system_extension
Updated
2 months ago
Source
Risk
Low
Requires consent
false
Affected scope
user
Code
/**
* mcp/skills/checkSystemExtension.ts — check_system_extension skill
*
* Verifies that security agent system extensions are loaded and user-approved.
* Security agents require system extensions to function at the kernel level.
* Unapproved extensions appear installed but are non-functional.
* macOS only for system extensions; Windows checks driver/service status.
*
* Platform strategy
* -----------------
* darwin `systemextensionsctl list` — parse tabular output
* win32 PowerShell Get-MpComputerStatus and Get-Service
*
* Smoke test
* npx tsx -r dotenv/config mcp/skills/checkSystemExtension.ts
*/
import * as os from "os";
import { exec } from "child_process";
import { promisify } from "util";
import { z } from "zod";
const execAsync = promisify(exec);
// -- Meta ---------------------------------------------------------------------
export const meta = {
name: "check_system_extension",
description:
"Verifies that security agent system extensions are loaded and user-approved. " +
"Security agents require system extensions to function at the kernel level. " +
"Unapproved extensions appear installed but are non-functional. " +
"macOS only for system extensions; Windows checks driver/service status.",
riskLevel: "low",
destructive: false,
requiresConsent: false,
supportsDryRun: false,
affectedScope: ["user"],
auditRequired: false,
schema: {
bundleId: z
.string()
.optional()
.describe(
"Extension bundle ID to check (e.g. 'com.crowdstrike.falcon.Agent'). " +
"Omit to list all security-related extensions",
),
},
} as const;
// -- Types --------------------------------------------------------------------
interface ExtensionEntry {
teamId: string;
bundleId: string;
version: string;
state: string;
isActive: boolean;
requiresApproval: boolean;
}
// -- PowerShell helper --------------------------------------------------------
async function runPS(script: string): Promise<string> {
const encoded = Buffer.from(script, "utf16le").toString("base64");
const { stdout } = await execAsync(
`powershell.exe -NoProfile -NonInteractive -EncodedCommand ${encoded}`,
{ maxBuffer: 20 * 1024 * 1024 },
);
return stdout.trim();
}
// -- darwin implementation ----------------------------------------------------
async function checkSystemExtensionDarwin(
bundleId?: string,
): Promise<{ platform: string; extensions: ExtensionEntry[]; allActive: boolean }> {
let stdout = "";
try {
({ stdout } = await execAsync("systemextensionsctl list 2>/dev/null", {
maxBuffer: 2 * 1024 * 1024,
}));
} catch (err) {
stdout = (err as { stdout?: string }).stdout ?? "";
}
const lines = stdout.trim().split("\n");
const extensions: ExtensionEntry[] = [];
// Each data line looks like:
// <teamId> * <bundleId> (version) [state]
// e.g.:
// X9E956P446 * com.crowdstrike.falcon.Agent (21.10.8813.0) [activated enabled]
const lineRe = /^\(\S+\s+[\*\s]\s+(\S+)\s+\(([^)]+)\)\s+\[([^\]]+)\]/;
for (const line of lines) {
const m = line.trim().match(lineRe);
if (!m) continue;
const [, teamId, bid, version, state] = m;
if (bundleId && bid !== bundleId) continue;
// Filter to security-related extensions when no bundleId specified
const securityKeywords = [
"crowdstrike", "sentinelone", "jamf", "carbonblack", "cylance",
"defender", "microsoft", "security", "endpoint", "falcon", "sentinel",
];
if (!bundleId) {
const lower = bid.toLowerCase();
if (!securityKeywords.some((kw) => lower.includes(kw))) continue;
}
const isActive = state.includes("activated") && state.includes("enabled");
const requiresApproval = state.includes("waiting for user");
extensions.push({ teamId, bundleId: bid, version, state, isActive, requiresApproval });
}
return {
platform: "darwin",
extensions,
allActive: extensions.length > 0 && extensions.every((e) => e.isActive),
};
}
// -- win32 implementation -----------------------------------------------------
async function checkSystemExtensionWin32(
_bundleId?: string,
): Promise<{ platform: string; extensions: ExtensionEntry[]; allActive: boolean }> {
const ps = `
$ErrorActionPreference = 'SilentlyContinue'
$mpStatus = Get-MpComputerStatus | Select-Object AMRunningMode,AntispywareEnabled,RealTimeProtectionEnabled,NISEnabled
$secSvcs = Get-Service | Where-Object { $_.DisplayName -match 'security|endpoint|falcon|sentinel|defender|crowdstrike' } |
Select-Object Name,DisplayName,Status
[PSCustomObject]@{
mpStatus = $mpStatus
services = @($secSvcs)
} | ConvertTo-Json -Depth 3 -Compress`.trim();
const raw = await runPS(ps);
const extensions: ExtensionEntry[] = [];
if (raw) {
try {
const parsed = JSON.parse(raw) as {
mpStatus?: { AMRunningMode?: string; AntispywareEnabled?: boolean; RealTimeProtectionEnabled?: boolean };
services?: Array<{ Name: string; DisplayName: string; Status: string }>;
};
if (parsed.mpStatus) {
const mp = parsed.mpStatus;
const state = mp.RealTimeProtectionEnabled ? "active" : "inactive";
extensions.push({
teamId: "Microsoft",
bundleId: "com.microsoft.defender",
version: mp.AMRunningMode ?? "unknown",
state,
isActive: !!mp.RealTimeProtectionEnabled,
requiresApproval: false,
});
}
for (const svc of parsed.services ?? []) {
const isActive = svc.Status === "Running";
extensions.push({
teamId: "service",
bundleId: svc.Name,
version: svc.DisplayName,
state: svc.Status,
isActive,
requiresApproval: false,
});
}
} catch {
// JSON parse failure — return empty
}
}
return {
platform: "win32",
extensions,
allActive: extensions.length > 0 && extensions.every((e) => e.isActive),
};
}
// -- Exported run function ----------------------------------------------------
export async function run({
bundleId,
}: {
bundleId?: string;
} = {}) {
const platform = os.platform();
return platform === "win32"
? checkSystemExtensionWin32(bundleId)
: checkSystemExtensionDarwin(bundleId);
}
// -- CLI smoke test -----------------------------------------------------------
if (false) {
run({})
.then(r => console.log(JSON.stringify(r, null, 2)))
.catch((err: Error) => { console.error(err.message); process.exit(1); });
}