mason-keller
feat: add kernel capability revocation & ephemeral syscall confinement synthesizer (v1.40.0)
a253c72 Download src/capability_revocation/capability_revocation_audit.ts from mason-keller/vulnforge-mcp: direct link, hf CLI and curl.
- Browser
- Download file 29.4 kB
-
https://huggingface.co/mason-keller/vulnforge-mcp/resolve/main/src/capability_revocation/capability_revocation_audit.ts
- Command line
-
hf download hf://mason-keller/vulnforge-mcp/src/capability_revocation/capability_revocation_audit.ts
-
curl -L -o capability_revocation_audit.ts https://huggingface.co/mason-keller/vulnforge-mcp/resolve/main/src/capability_revocation/capability_revocation_audit.ts
29.4 kB
| /** | |
| * VulnForge MCP - Autonomous Kernel Capability Revocation & Ephemeral Syscall Confinement Synthesizer | |
| * @module capability_revocation/capability_revocation_audit | |
| * | |
| * Implements static and dynamic architectural security auditing for: | |
| * 1. VF-CAPREV-001 (CRITICAL, CWE-250/CWE-269): Unrestricted Ambient Linux Capabilities & Missing Ephemeral Capability Dropping | |
| * 2. VF-CAPREV-002 (CRITICAL, CWE-284/CWE-693): Inadequate Landlock LSM Filesystem Confinement & Unrestricted Path Traversal | |
| * 3. VF-CAPREV-003 (CRITICAL, CWE-754/CWE-653): Unenforced eBPF LSM Syscall Confinement & Missing LSM Probes | |
| * 4. VF-CAPREV-004 (HIGH, CWE-276/CWE-281): Permissive Inherited File Descriptor & Socket Capability Leakage | |
| * 5. VF-CAPREV-005 (HIGH, CWE-400/CWE-770): Absent Ephemeral Process Lifetime Quotas & Missing cgroups v2 Kernel Resource Confinement | |
| * 6. VF-CAPREV-006 (HIGH, CWE-385/CWE-362): Time-of-Check to Time-of-Use (TOCTOU) Capability Restoration Race | |
| * 7. VF-CAPREV-007 (HIGH, CWE-778/CWE-754): Unaudited Capability Transition Events & Missing Tamper-Evident Confinement Audit Logging | |
| * 8. VF-CAPREV-008 (HIGH, CWE-284/CWE-732): Fail-Open Kernel Capability Fallback on Unsupported LSM Environment | |
| */ | |
| import { | |
| FuzzMutationCase, | |
| CapabilityRevocationArtifactFormat, | |
| CapabilityRevocationAuditInput, | |
| CapabilityRevocationAuditResult, | |
| CapabilityRevocationAuditSummary, | |
| CapabilityRevocationFindingCode, | |
| CapabilityRevocationSecurityPolicy, | |
| PatchRecommendation, | |
| SecurityFinding | |
| } from '../types/index.js'; | |
| export const DEFAULT_CAPABILITY_REVOCATION_POLICY: CapabilityRevocationSecurityPolicy = { | |
| policyVersion: '1.40.0', | |
| capabilityDropping: { | |
| enforceCapabilityDrop: true, | |
| clearAmbientCapabilities: true, | |
| dropBoundingSet: true, | |
| allowedCapabilities: [], | |
| disallowRootCapabilities: true | |
| }, | |
| landlockLsmConfinement: { | |
| enforceLandlockRuleset: true, | |
| abiVersion: 3, | |
| enforceNoNewPrivs: true, | |
| readOnlyPaths: ['/usr', '/lib', '/etc/ssl'], | |
| readWritePaths: ['/tmp/agent-ephemeral'], | |
| deniedPaths: ['/proc/sys', '/sys', '/root'], | |
| disallowExecutablePaths: true | |
| }, | |
| ebpfLsmHooks: { | |
| enforceEbpfLsmHooks: true, | |
| monitoredHooks: ['file_open', 'socket_connect', 'task_prctl', 'bpf'], | |
| blockUnauthorizedSockets: true, | |
| blockRawSockets: true, | |
| blockPrivilegedSyscalls: true | |
| }, | |
| fdCloexecSanitization: { | |
| enforceFdCloexec: true, | |
| closeInheritedFds: true, | |
| maxFdToPreserve: 2, | |
| disallowLeakedSockets: true | |
| }, | |
| cgroupsResourceConfinement: { | |
| enforceCgroupsLimits: true, | |
| maxPids: 64, | |
| maxMemoryBytes: 2147483648, | |
| cpuQuotaUs: 100000, | |
| executionTimeoutSeconds: 300 | |
| }, | |
| atomicPrivilegeTransition: { | |
| enforceAtomicTransition: true, | |
| enforceSecurebits: true, | |
| securebitsFlags: ['SECBIT_NOROOT', 'SECBIT_NO_SETUID_FIXUP', 'SECBIT_NOROOT_LOCKED'], | |
| synchronizeThreadPrivileges: true | |
| }, | |
| auditTrailVerification: { | |
| cryptographicEventChaining: true, | |
| hashAlgorithm: 'SHA-256', | |
| logCapabilityTransitions: true, | |
| failSecureOnAuditTampering: true | |
| }, | |
| failClosedPosture: { | |
| failClosedOnUnsupportedLsm: true, | |
| requireLandlockSupport: true, | |
| requireEbpfLsmSupport: true, | |
| abortOnDegradedEnvironment: true | |
| } | |
| }; | |
| /** | |
| * Detects whether content belongs to Kernel Capability Revocation & Ephemeral Syscall Confinement artifacts. | |
| */ | |
| export function isCapabilityRevocationContent(content: string): boolean { | |
| if (!content) return false; | |
| const c = content.toLowerCase(); | |
| return ( | |
| c.includes('capability_revocation') || | |
| c.includes('capabilityrevocation') || | |
| c.includes('landlock') || | |
| c.includes('landlock_create_ruleset') || | |
| c.includes('landlock_restrict_self') || | |
| c.includes('cap_set_proc') || | |
| c.includes('pr_cap_ambient_clear_all') || | |
| c.includes('pr_set_no_new_privs') || | |
| c.includes('ebpf_lsm') || | |
| c.includes('bpf_lsm') || | |
| c.includes('fd_cloexec') || | |
| c.includes('o_cloexec') || | |
| c.includes('confinement_manifest') || | |
| c.includes('cgroupsresourceconfinement') || | |
| c.includes('capabilitydropping') || | |
| c.includes('landlocklsmconfinement') || | |
| c.includes('failclosedposture') | |
| ); | |
| } | |
| /** | |
| * Detects artifact format of Capability Revocation & Ephemeral Syscall Confinement specs. | |
| */ | |
| export function detectCapabilityRevocationFormat( | |
| content: string, | |
| filePath?: string | |
| ): CapabilityRevocationArtifactFormat { | |
| if (filePath) { | |
| const lower = filePath.toLowerCase(); | |
| if (lower.endsWith('.landlock') || lower.includes('landlock')) return 'LANDLOCK_RULES'; | |
| if (lower.endsWith('.lsm.c') || lower.includes('ebpf_lsm') || lower.includes('bpf_lsm')) return 'EBPF_LSM_POLICY'; | |
| if (lower.includes('cap_drop') || lower.includes('capability')) return 'CAPABILITY_DROP_SPEC'; | |
| if (lower.includes('confinement') || lower.includes('confinement_manifest')) return 'CONFINEMENT_MANIFEST'; | |
| } | |
| const c = content.toLowerCase(); | |
| if (c.includes('landlock_create_ruleset') || c.includes('landlock_access_fs') || c.includes('landlock_ruleset_attr')) { | |
| return 'LANDLOCK_RULES'; | |
| } | |
| if (c.includes('sec("lsm/') || c.includes('bpf_lsm_') || c.includes('bpf_prog_type_lsm')) { | |
| return 'EBPF_LSM_POLICY'; | |
| } | |
| if (c.includes('pr_cap_ambient_clear_all') || c.includes('cap_set_proc') || c.includes('allowedcapabilities')) { | |
| return 'CAPABILITY_DROP_SPEC'; | |
| } | |
| if (c.includes('confinement_manifest') || c.includes('confinementmanifest') || c.includes('cgroupsresourceconfinement')) { | |
| return 'CONFINEMENT_MANIFEST'; | |
| } | |
| if (content.trim().startsWith('{') || content.trim().startsWith('[')) { | |
| return 'JSON'; | |
| } | |
| if (content.includes('---') || (content.includes(':') && !content.includes(';'))) { | |
| return 'YAML'; | |
| } | |
| return 'UNKNOWN'; | |
| } | |
| /** | |
| * Synthesizes a hardened Capability Revocation & Ephemeral Syscall Confinement policy from partial configuration. | |
| */ | |
| export function synthesizeCapabilityRevocationPolicyFromConfig( | |
| config?: Partial<CapabilityRevocationSecurityPolicy> | |
| ): CapabilityRevocationSecurityPolicy { | |
| return { | |
| policyVersion: config?.policyVersion || DEFAULT_CAPABILITY_REVOCATION_POLICY.policyVersion, | |
| capabilityDropping: { | |
| ...DEFAULT_CAPABILITY_REVOCATION_POLICY.capabilityDropping, | |
| ...(config?.capabilityDropping || {}) | |
| }, | |
| landlockLsmConfinement: { | |
| ...DEFAULT_CAPABILITY_REVOCATION_POLICY.landlockLsmConfinement, | |
| ...(config?.landlockLsmConfinement || {}) | |
| }, | |
| ebpfLsmHooks: { | |
| ...DEFAULT_CAPABILITY_REVOCATION_POLICY.ebpfLsmHooks, | |
| ...(config?.ebpfLsmHooks || {}) | |
| }, | |
| fdCloexecSanitization: { | |
| ...DEFAULT_CAPABILITY_REVOCATION_POLICY.fdCloexecSanitization, | |
| ...(config?.fdCloexecSanitization || {}) | |
| }, | |
| cgroupsResourceConfinement: { | |
| ...DEFAULT_CAPABILITY_REVOCATION_POLICY.cgroupsResourceConfinement, | |
| ...(config?.cgroupsResourceConfinement || {}) | |
| }, | |
| atomicPrivilegeTransition: { | |
| ...DEFAULT_CAPABILITY_REVOCATION_POLICY.atomicPrivilegeTransition, | |
| ...(config?.atomicPrivilegeTransition || {}) | |
| }, | |
| auditTrailVerification: { | |
| ...DEFAULT_CAPABILITY_REVOCATION_POLICY.auditTrailVerification, | |
| ...(config?.auditTrailVerification || {}) | |
| }, | |
| failClosedPosture: { | |
| ...DEFAULT_CAPABILITY_REVOCATION_POLICY.failClosedPosture, | |
| ...(config?.failClosedPosture || {}) | |
| } | |
| }; | |
| } | |
| export const synthesizeCapabilityRevocationSecurityPolicy = synthesizeCapabilityRevocationPolicyFromConfig; | |
| /** | |
| * Generates an adversarial mutation fuzz suite for Capability Revocation & Ephemeral Syscall Confinement testing. | |
| */ | |
| export function generateCapabilityRevocationFuzzSuite( | |
| basePolicy?: Partial<CapabilityRevocationSecurityPolicy> | |
| ): FuzzMutationCase[] { | |
| const policy = synthesizeCapabilityRevocationPolicyFromConfig(basePolicy); | |
| const fuzzCases: FuzzMutationCase[] = [ | |
| { | |
| id: 'FUZZ-CAPREV-001', | |
| field: 'capabilityDropping.enforceCapabilityDrop', | |
| mutationType: 'STATE_INJECTION', | |
| payload: { enforceCapabilityDrop: false, clearAmbientCapabilities: false, allowedCapabilities: ['CAP_SYS_ADMIN'] }, | |
| description: 'Retain ambient Linux capabilities and skip prctl ambient clear', | |
| expectedStatus: 400 | |
| }, | |
| { | |
| id: 'FUZZ-CAPREV-002', | |
| field: 'landlockLsmConfinement.enforceLandlockRuleset', | |
| mutationType: 'STATE_INJECTION', | |
| payload: { enforceLandlockRuleset: false, enforceNoNewPrivs: false, readWritePaths: ['/'] }, | |
| description: 'Disable Landlock ruleset enforcement and permit root filesystem write access', | |
| expectedStatus: 400 | |
| }, | |
| { | |
| id: 'FUZZ-CAPREV-003', | |
| field: 'ebpfLsmHooks.enforceEbpfLsmHooks', | |
| mutationType: 'STATE_INJECTION', | |
| payload: { enforceEbpfLsmHooks: false, blockUnauthorizedSockets: false }, | |
| description: 'Disable eBPF LSM syscall hook interception allowing arbitrary sockets', | |
| expectedStatus: 400 | |
| }, | |
| { | |
| id: 'FUZZ-CAPREV-004', | |
| field: 'fdCloexecSanitization.enforceFdCloexec', | |
| mutationType: 'STATE_INJECTION', | |
| payload: { enforceFdCloexec: false, closeInheritedFds: false, maxFdToPreserve: 1024 }, | |
| description: 'Disable FD_CLOEXEC allowing child processes to inherit privileged descriptors', | |
| expectedStatus: 400 | |
| }, | |
| { | |
| id: 'FUZZ-CAPREV-005', | |
| field: 'cgroupsResourceConfinement.enforceCgroupsLimits', | |
| mutationType: 'STATE_INJECTION', | |
| payload: { enforceCgroupsLimits: false, maxPids: 999999 }, | |
| description: 'Remove cgroups v2 process table boundaries risking runaway fork bombs', | |
| expectedStatus: 400 | |
| }, | |
| { | |
| id: 'FUZZ-CAPREV-006', | |
| field: 'atomicPrivilegeTransition.enforceAtomicTransition', | |
| mutationType: 'STATE_INJECTION', | |
| payload: { enforceAtomicTransition: false, enforceSecurebits: false }, | |
| description: 'Omit securebits locks allowing threads to re-acquire root privileges across execve', | |
| expectedStatus: 400 | |
| }, | |
| { | |
| id: 'FUZZ-CAPREV-007', | |
| field: 'auditTrailVerification.cryptographicEventChaining', | |
| mutationType: 'STATE_INJECTION', | |
| payload: { cryptographicEventChaining: false, logCapabilityTransitions: false }, | |
| description: 'Disable cryptographic SHA-256 hash chaining on capability transition audit events', | |
| expectedStatus: 400 | |
| }, | |
| { | |
| id: 'FUZZ-CAPREV-008', | |
| field: 'failClosedPosture.failClosedOnUnsupportedLsm', | |
| mutationType: 'STATE_INJECTION', | |
| payload: { failClosedOnUnsupportedLsm: false, abortOnDegradedEnvironment: false }, | |
| description: 'Permit unconfined fail-open execution on unsupported kernel LSM host environments', | |
| expectedStatus: 400 | |
| } | |
| ]; | |
| return fuzzCases; | |
| } | |
| /** | |
| * Conducts static and dynamic architectural security audits for Kernel Capability Revocation & Ephemeral Syscall Confinement. | |
| */ | |
| export async function auditCapabilityRevocationSecurity( | |
| input: CapabilityRevocationAuditInput | |
| ): Promise<CapabilityRevocationAuditResult> { | |
| const content = input.content || ''; | |
| const filePath = input.filePath || 'confinement_policy.json'; | |
| const format = input.format || detectCapabilityRevocationFormat(content, filePath); | |
| const findings: SecurityFinding[] = []; | |
| const patchRecommendations: PatchRecommendation[] = []; | |
| let parsedConfig: any = null; | |
| try { | |
| parsedConfig = JSON.parse(content); | |
| } catch { | |
| parsedConfig = null; | |
| } | |
| const raw = content.toLowerCase(); | |
| // Helper check functions | |
| const has = (key: string): boolean => raw.includes(key.toLowerCase()); | |
| const hasInConfig = (path: string[], expectedVal?: any): boolean => { | |
| if (!parsedConfig) return false; | |
| let curr = parsedConfig; | |
| for (const p of path) { | |
| if (curr && typeof curr === 'object' && p in curr) { | |
| curr = curr[p]; | |
| } else { | |
| return false; | |
| } | |
| } | |
| if (expectedVal !== undefined) { | |
| return curr === expectedVal; | |
| } | |
| return Boolean(curr); | |
| }; | |
| // 1. VF-CAPREV-001 (CRITICAL, CWE-250/CWE-269): Unrestricted Ambient Linux Capabilities & Missing Ephemeral Capability Dropping | |
| const retainsAmbientCaps = | |
| hasInConfig(['capabilityDropping', 'clearAmbientCapabilities'], false) || | |
| hasInConfig(['capabilityDropping', 'enforceCapabilityDrop'], false) || | |
| has('allow_ambient_capabilities: true') || | |
| has('clear_ambient_capabilities: false') || | |
| has('cap_sys_admin') || | |
| has('cap_net_admin') || | |
| (parsedConfig?.capabilityDropping?.allowedCapabilities && | |
| parsedConfig.capabilityDropping.allowedCapabilities.some((cap: string) => | |
| ['CAP_SYS_ADMIN', 'CAP_NET_ADMIN', 'CAP_SYS_PTRACE', 'CAP_DAC_OVERRIDE', 'CAP_SYS_RAWIO'].includes( | |
| cap.toUpperCase() | |
| ) | |
| )) || | |
| (!has('pr_cap_ambient_clear_all') && | |
| !has('clearambientcapabilities') && | |
| !hasInConfig(['capabilityDropping', 'clearAmbientCapabilities'], true)); | |
| if (retainsAmbientCaps) { | |
| findings.push({ | |
| id: 'VF-CAPREV-001', | |
| findingCode: 'VF-CAPREV-001', | |
| title: 'Unrestricted Ambient Linux Capabilities & Missing Ephemeral Capability Dropping', | |
| severity: 'CRITICAL', | |
| category: 'kernel_capability_revocation', | |
| cwe: 'CWE-250', | |
| target: filePath, | |
| description: | |
| 'The process does not deterministically drop ambient or bounding Linux capabilities after initialization. Retaining high-privilege capabilities (e.g., CAP_SYS_ADMIN, CAP_NET_ADMIN) allows compromised AI agent subprocesses to perform privileged operations or escape container boundaries.', | |
| evidence: parsedConfig?.capabilityDropping | |
| ? `capabilityDropping: ${JSON.stringify(parsedConfig.capabilityDropping)}` | |
| : 'Missing PR_CAP_AMBIENT_CLEAR_ALL or cap_set_proc capability reduction routine', | |
| impact: | |
| 'Compromised child processes inherit dangerous administrative capabilities, leading to complete host/container compromise.', | |
| remediation: | |
| 'Invoke prctl(PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0, 0) and cap_set_proc() immediately after process startup, ensuring an empty ambient capability set.', | |
| patchRecommendation: { | |
| patchType: 'capability_dropping_enforce', | |
| targetFile: filePath, | |
| description: 'Drop all ambient and bounding capabilities via PR_CAP_AMBIENT_CLEAR_ALL and cap_set_proc().' | |
| } | |
| }); | |
| } | |
| // 2. VF-CAPREV-002 (CRITICAL, CWE-284/CWE-693): Inadequate Landlock LSM Filesystem Confinement & Unrestricted Path Traversal | |
| const lacksLandlockConfinement = | |
| hasInConfig(['landlockLsmConfinement', 'enforceLandlockRuleset'], false) || | |
| hasInConfig(['landlockLsmConfinement', 'enforceNoNewPrivs'], false) || | |
| has('enforce_landlock_ruleset: false') || | |
| has('enforce_no_new_privs: false') || | |
| (parsedConfig?.landlockLsmConfinement?.readWritePaths && | |
| parsedConfig.landlockLsmConfinement.readWritePaths.includes('/')) || | |
| (!has('landlock_create_ruleset') && | |
| !has('landlocklsmconfinement') && | |
| !hasInConfig(['landlockLsmConfinement', 'enforceLandlockRuleset'], true)); | |
| if (lacksLandlockConfinement) { | |
| findings.push({ | |
| id: 'VF-CAPREV-002', | |
| findingCode: 'VF-CAPREV-002', | |
| title: 'Inadequate Landlock LSM Filesystem Confinement & Unrestricted Path Traversal', | |
| severity: 'CRITICAL', | |
| category: 'landlock_filesystem_confinement', | |
| cwe: 'CWE-284', | |
| target: filePath, | |
| description: | |
| 'Filesystem confinement via Linux Landlock LSM is missing or misconfigured. Running without PR_SET_NO_NEW_PRIVS or with unconstrained root directory write access exposes the host system to arbitrary file overwriting and path traversal.', | |
| evidence: parsedConfig?.landlockLsmConfinement | |
| ? `landlockLsmConfinement: ${JSON.stringify(parsedConfig.landlockLsmConfinement)}` | |
| : 'Missing landlock_create_ruleset or landlock_restrict_self invocation', | |
| impact: | |
| 'Autonomous AI agents can traverse host directory hierarchies, overwrite critical binaries, and persist malicious artifacts.', | |
| remediation: | |
| 'Define explicit Landlock ABI v3 rulesets restricting read-only hierarchies to dependency directories and isolated ephemeral write paths, preceded by prctl(PR_SET_NO_NEW_PRIVS, 1).', | |
| patchRecommendation: { | |
| patchType: 'landlock_ruleset_enforce', | |
| targetFile: filePath, | |
| description: 'Apply strict Landlock filesystem confinement ruleset with isolated ephemeral read/write boundaries.' | |
| } | |
| }); | |
| } | |
| // 3. VF-CAPREV-003 (CRITICAL, CWE-754/CWE-653): Unenforced eBPF LSM Syscall Confinement & Missing LSM Probes | |
| const lacksEbpfLsm = | |
| hasInConfig(['ebpfLsmHooks', 'enforceEbpfLsmHooks'], false) || | |
| hasInConfig(['ebpfLsmHooks', 'blockUnauthorizedSockets'], false) || | |
| has('enforce_ebpf_lsm_hooks: false') || | |
| has('block_unauthorized_sockets: false') || | |
| (!has('bpf_lsm_') && | |
| !has('ebpflsmhooks') && | |
| !hasInConfig(['ebpfLsmHooks', 'enforceEbpfLsmHooks'], true)); | |
| if (lacksEbpfLsm) { | |
| findings.push({ | |
| id: 'VF-CAPREV-003', | |
| findingCode: 'VF-CAPREV-003', | |
| title: 'Unenforced eBPF LSM Syscall Confinement & Missing LSM Probes', | |
| severity: 'CRITICAL', | |
| category: 'ebpf_lsm_syscall_confinement', | |
| cwe: 'CWE-754', | |
| target: filePath, | |
| description: | |
| 'The execution environment does not attach eBPF LSM hooks to sensitive kernel syscall checkpoints (file_open, socket_connect, task_prctl, bpf), permitting arbitrary raw socket creation or unconfined syscall invocation.', | |
| evidence: parsedConfig?.ebpfLsmHooks | |
| ? `ebpfLsmHooks: ${JSON.stringify(parsedConfig.ebpfLsmHooks)}` | |
| : 'Missing eBPF LSM attachment hooks on sensitive kernel operations', | |
| impact: | |
| 'Agent workloads can establish unauthorized outbound network sockets or load malicious unverified eBPF programs.', | |
| remediation: | |
| 'Attach eBPF LSM hooks to intercept security_socket_connect, security_file_open, and security_task_prctl, enforcing strict protocol denylists.', | |
| patchRecommendation: { | |
| patchType: 'ebpf_lsm_hooks_enforce', | |
| targetFile: filePath, | |
| description: 'Attach eBPF LSM hooks to deny unconfined socket connections and privileged syscalls.' | |
| } | |
| }); | |
| } | |
| // 4. VF-CAPREV-004 (HIGH, CWE-276/CWE-281): Permissive Inherited File Descriptor & Socket Capability Leakage | |
| const leaksFds = | |
| hasInConfig(['fdCloexecSanitization', 'enforceFdCloexec'], false) || | |
| hasInConfig(['fdCloexecSanitization', 'closeInheritedFds'], false) || | |
| has('enforce_fd_cloexec: false') || | |
| has('close_inherited_fds: false') || | |
| (parsedConfig?.fdCloexecSanitization?.maxFdToPreserve !== undefined && | |
| parsedConfig.fdCloexecSanitization.maxFdToPreserve > 2) || | |
| (!has('fd_cloexec') && | |
| !has('o_cloexec') && | |
| !hasInConfig(['fdCloexecSanitization', 'enforceFdCloexec'], true)); | |
| if (leaksFds) { | |
| findings.push({ | |
| id: 'VF-CAPREV-004', | |
| findingCode: 'VF-CAPREV-004', | |
| title: 'Permissive Inherited File Descriptor & Socket Capability Leakage', | |
| severity: 'HIGH', | |
| category: 'fd_cloexec_leakage', | |
| cwe: 'CWE-276', | |
| target: filePath, | |
| description: | |
| 'File descriptors allocated by the parent runtime do not enforce FD_CLOEXEC, allowing child agent processes to inherit active database connections, IPC pipes, or administrative sockets.', | |
| evidence: parsedConfig?.fdCloexecSanitization | |
| ? `fdCloexecSanitization: ${JSON.stringify(parsedConfig.fdCloexecSanitization)}` | |
| : 'Missing FD_CLOEXEC flags on allocated file descriptors and inherited sockets', | |
| impact: | |
| 'Child processes can read, write, or hijack communication channels established by the parent orchestrator.', | |
| remediation: | |
| 'Apply O_CLOEXEC / SOCK_CLOEXEC on all descriptor allocations and close all file descriptors greater than STDERR_FILENO prior to executing subcommands.', | |
| patchRecommendation: { | |
| patchType: 'fd_cloexec_enforce', | |
| targetFile: filePath, | |
| description: 'Set FD_CLOEXEC on all descriptors and close inherited non-standard descriptors before exec.' | |
| } | |
| }); | |
| } | |
| // 5. VF-CAPREV-005 (HIGH, CWE-400/CWE-770): Absent Ephemeral Process Lifetime Quotas & Missing cgroups v2 Kernel Resource Confinement | |
| const lacksCgroups = | |
| hasInConfig(['cgroupsResourceConfinement', 'enforceCgroupsLimits'], false) || | |
| has('enforce_cgroups_limits: false') || | |
| (parsedConfig?.cgroupsResourceConfinement?.maxPids !== undefined && | |
| parsedConfig.cgroupsResourceConfinement.maxPids > 256) || | |
| (!has('cgroups') && | |
| !has('pids.max') && | |
| !hasInConfig(['cgroupsResourceConfinement', 'enforceCgroupsLimits'], true)); | |
| if (lacksCgroups) { | |
| findings.push({ | |
| id: 'VF-CAPREV-005', | |
| findingCode: 'VF-CAPREV-005', | |
| title: 'Absent Ephemeral Process Lifetime Quotas & Missing cgroups v2 Kernel Resource Confinement', | |
| severity: 'HIGH', | |
| category: 'cgroups_resource_confinement', | |
| cwe: 'CWE-400', | |
| target: filePath, | |
| description: | |
| 'Autonomous AI agent processes run without cgroups v2 slice boundaries (pids.max, memory.high, cpu.max). Unmetered agent execution can result in fork-bomb exhaustion or runaway memory consumption.', | |
| evidence: parsedConfig?.cgroupsResourceConfinement | |
| ? `cgroupsResourceConfinement: ${JSON.stringify(parsedConfig.cgroupsResourceConfinement)}` | |
| : 'Missing cgroups v2 resource controller bindings (pids.max, memory.max)', | |
| impact: | |
| 'Runaway or hostile agent child tasks can deplete host process tables and memory, inducing node-wide Denial of Service.', | |
| remediation: | |
| 'Enforce cgroups v2 resource confinement setting pids.max <= 64, memory.high <= 2GB, and bind process execution to bounded lifetime watchdogs.', | |
| patchRecommendation: { | |
| patchType: 'cgroups_confinement_enforce', | |
| targetFile: filePath, | |
| description: 'Bind agent execution to cgroups v2 with strict pids.max and memory limits.' | |
| } | |
| }); | |
| } | |
| // 6. VF-CAPREV-006 (HIGH, CWE-385/CWE-362): Time-of-Check to Time-of-Use (TOCTOU) Capability Restoration Race | |
| const vulnerableToctou = | |
| hasInConfig(['atomicPrivilegeTransition', 'enforceAtomicTransition'], false) || | |
| hasInConfig(['atomicPrivilegeTransition', 'enforceSecurebits'], false) || | |
| has('enforce_atomic_transition: false') || | |
| has('enforce_securebits: false') || | |
| (parsedConfig?.atomicPrivilegeTransition?.securebitsFlags && | |
| parsedConfig.atomicPrivilegeTransition.securebitsFlags.length === 0) || | |
| (!has('securebits') && | |
| !has('secbit_noroot') && | |
| !hasInConfig(['atomicPrivilegeTransition', 'enforceAtomicTransition'], true)); | |
| if (vulnerableToctou) { | |
| findings.push({ | |
| id: 'VF-CAPREV-006', | |
| findingCode: 'VF-CAPREV-006', | |
| title: 'Time-of-Check to Time-of-Use (TOCTOU) Capability Restoration Race', | |
| severity: 'HIGH', | |
| category: 'toctou_privilege_restoration', | |
| cwe: 'CWE-385', | |
| target: filePath, | |
| description: | |
| 'Privilege transitions are not executed atomically across all task threads or omit locked securebits (SECBIT_NOROOT_LOCKED, SECBIT_NO_SETUID_FIXUP_LOCKED), permitting capability re-acquisition across execve or thread cloning.', | |
| evidence: parsedConfig?.atomicPrivilegeTransition | |
| ? `atomicPrivilegeTransition: ${JSON.stringify(parsedConfig.atomicPrivilegeTransition)}` | |
| : 'Missing PR_SET_SECUREBITS lock flags and thread synchronization', | |
| impact: | |
| 'Threads can exploit transition latency windows to re-elevate capabilities or execute setuid binaries.', | |
| remediation: | |
| 'Lock securebits flags (SECBIT_NOROOT | SECBIT_NOROOT_LOCKED | SECBIT_NO_SETUID_FIXUP_LOCKED) and ensure atomic capability transition synchronization across threads.', | |
| patchRecommendation: { | |
| patchType: 'securebits_lock_enforce', | |
| targetFile: filePath, | |
| description: 'Lock securebits flags and enforce atomic process-wide privilege transitions.' | |
| } | |
| }); | |
| } | |
| // 7. VF-CAPREV-007 (HIGH, CWE-778/CWE-754): Unaudited Capability Transition Events & Missing Tamper-Evident Confinement Audit Logging | |
| const lacksAuditTrail = | |
| hasInConfig(['auditTrailVerification', 'cryptographicEventChaining'], false) || | |
| hasInConfig(['auditTrailVerification', 'logCapabilityTransitions'], false) || | |
| has('cryptographic_event_chaining: false') || | |
| has('log_capability_transitions: false') || | |
| (!has('cryptographiceventchaining') && | |
| !has('logcapabilitytransitions') && | |
| !hasInConfig(['auditTrailVerification', 'cryptographicEventChaining'], true)); | |
| if (lacksAuditTrail) { | |
| findings.push({ | |
| id: 'VF-CAPREV-007', | |
| findingCode: 'VF-CAPREV-007', | |
| title: 'Unaudited Capability Transition Events & Missing Tamper-Evident Confinement Audit Logging', | |
| severity: 'HIGH', | |
| category: 'confinement_audit_trail', | |
| cwe: 'CWE-778', | |
| target: filePath, | |
| description: | |
| 'Capability drops, Landlock rule applications, and eBPF LSM denials are executed without cryptographically verifiable hash chaining, preventing forensic validation and audit integrity.', | |
| evidence: parsedConfig?.auditTrailVerification | |
| ? `auditTrailVerification: ${JSON.stringify(parsedConfig.auditTrailVerification)}` | |
| : 'Missing cryptographic hash-chained audit telemetry for confinement transitions', | |
| impact: | |
| 'Security incidents cannot be attributed or audited, and hostile privilege escalation attempts remain unrecorded.', | |
| remediation: | |
| 'Implement tamper-evident SHA-256 chained audit event logging for all capability transitions and Landlock LSM violations.', | |
| patchRecommendation: { | |
| patchType: 'audit_trail_chain_enforce', | |
| targetFile: filePath, | |
| description: 'Enable cryptographic SHA-256 hash chaining on capability and LSM transition audit logs.' | |
| } | |
| }); | |
| } | |
| // 8. VF-CAPREV-008 (HIGH, CWE-284/CWE-732): Fail-Open Kernel Capability Fallback on Unsupported LSM Environment | |
| const failOpenFallback = | |
| hasInConfig(['failClosedPosture', 'failClosedOnUnsupportedLsm'], false) || | |
| hasInConfig(['failClosedPosture', 'abortOnDegradedEnvironment'], false) || | |
| has('fail_closed_on_unsupported_lsm: false') || | |
| has('abort_on_degraded_environment: false') || | |
| (!has('failclosedonunsupportedlsm') && | |
| !has('abortondegradedenvironment') && | |
| !hasInConfig(['failClosedPosture', 'failClosedOnUnsupportedLsm'], true)); | |
| if (failOpenFallback) { | |
| findings.push({ | |
| id: 'VF-CAPREV-008', | |
| findingCode: 'VF-CAPREV-008', | |
| title: 'Fail-Open Kernel Capability Fallback on Unsupported LSM Environment', | |
| severity: 'HIGH', | |
| category: 'fail_closed_lsm_posture', | |
| cwe: 'CWE-284', | |
| target: filePath, | |
| description: | |
| 'The confinement policy permits fail-open execution if the underlying kernel lacks Landlock or eBPF LSM support, allowing autonomous AI agents to run unconfined in degraded host environments.', | |
| evidence: parsedConfig?.failClosedPosture | |
| ? `failClosedPosture: ${JSON.stringify(parsedConfig.failClosedPosture)}` | |
| : 'Missing fail-closed assertion on unsupported kernel LSM capabilities', | |
| impact: | |
| 'Agents deployed on older or stripped host kernels execute with unconfined privileges without administrative warning.', | |
| remediation: | |
| 'Set failClosedOnUnsupportedLsm: true to immediately abort process initialization if required LSM subsystems are uninitialized or unsupported.', | |
| patchRecommendation: { | |
| patchType: 'fail_closed_lsm_posture_enforce', | |
| targetFile: filePath, | |
| description: 'Enforce strict fail-closed termination when required kernel LSM subsystems are unavailable.' | |
| } | |
| }); | |
| } | |
| // Calculate audit score & summary | |
| const totalChecks = 8; | |
| const findingsCount = findings.length; | |
| const passedChecks = totalChecks - findingsCount; | |
| const score = Math.max(0, Math.round((passedChecks / totalChecks) * 100)); | |
| const critical = findings.filter((f) => f.severity === 'CRITICAL').length; | |
| const high = findings.filter((f) => f.severity === 'HIGH').length; | |
| const medium = findings.filter((f) => f.severity === 'MEDIUM').length; | |
| const low = findings.filter((f) => f.severity === 'LOW').length; | |
| const passed = findingsCount === 0; | |
| const complianceStatus = critical > 0 || high > 0 ? 'FAIL' : medium > 0 ? 'WARN' : 'PASS'; | |
| const attestationStatus = passed ? 'VERIFIED_SECURE' : 'ATTESTATION_FAILED'; | |
| const summary: CapabilityRevocationAuditSummary = { | |
| score, | |
| totalChecks, | |
| passedChecks, | |
| findingsCount, | |
| severityCounts: { critical, high, medium, low }, | |
| format, | |
| complianceStatus, | |
| passed, | |
| capabilityDropEnforced: !retainsAmbientCaps, | |
| landlockConfinementAttested: !lacksLandlockConfinement, | |
| ebpfLsmHooksVerified: !lacksEbpfLsm, | |
| fdCloexecSanitized: !leaksFds, | |
| cgroupsLimitsBound: !lacksCgroups, | |
| atomicTransitionEnforced: !vulnerableToctou, | |
| auditTrailChained: !lacksAuditTrail, | |
| failClosedPostureGuaranteed: !failOpenFallback | |
| }; | |
| const recommendedPolicy = synthesizeCapabilityRevocationPolicyFromConfig(parsedConfig || {}); | |
| return { | |
| targetFile: filePath, | |
| findings, | |
| summary, | |
| recommendedPolicy, | |
| patchRecommendations, | |
| passed, | |
| complianceStatus, | |
| attestationStatus, | |
| fuzzCasesGenerated: 8 | |
| }; | |
| } | |