codecrucible-synth
Version:
Production-Ready AI Development Platform with Multi-Voice Synthesis, Smithery MCP Integration, Enterprise Security, and Zero-Timeout Reliability
475 lines (424 loc) • 13.8 kB
text/typescript
/**
* Secure Execution Manager - SECURITY CRITICAL COMPONENT
*
* This component enforces secure code execution policies and replaces
* all unsafe direct execution with E2B sandboxed execution.
*
* CRITICAL SECURITY FIXES:
* - Blocks direct shell command execution
* - Enforces E2B sandboxing for all code execution
* - Implements comprehensive command validation
* - Removes environment variable exposure
* - Adds audit logging for security monitoring
*/
import { E2BService } from '../e2b/e2b-service.js';
import { SecurityValidator } from '../e2b/security-validator.js';
import { logger } from '../logger.js';
import { z } from 'zod';
export interface SecureExecutionConfig {
enforceE2BOnly: boolean;
allowLocalExecution: boolean;
auditLog: boolean;
maxExecutionTime: number;
allowedCommands: string[];
blockedPatterns: RegExp[];
}
export interface ExecutionRequest {
command: string;
language?: string;
workingDirectory?: string;
timeout?: number;
environment?: Record<string, string>;
sessionId?: string;
}
export interface ExecutionResult {
success: boolean;
stdout?: string;
stderr?: string;
exitCode: number;
executionTime: number;
sessionId: string;
securityWarnings?: string[];
backend: 'e2b' | 'blocked' | 'error';
}
/**
* Secure Execution Manager - Enforces security policies for all code execution
*/
export class SecureExecutionManager {
private e2bService: E2BService;
private securityValidator: SecurityValidator;
private config: SecureExecutionConfig;
private isInitialized: boolean = false;
constructor(config?: Partial<SecureExecutionConfig>) {
this.config = {
enforceE2BOnly: true, // ✅ SECURITY: Only allow E2B execution
allowLocalExecution: false, // ❌ SECURITY: Block unsafe local execution
auditLog: true, // ✅ SECURITY: Enable audit logging
maxExecutionTime: 30000, // 30 second timeout
allowedCommands: [
'ls',
'cat',
'grep',
'find',
'pwd',
'whoami',
'git',
'npm',
'node',
'python',
'pip',
'tsc',
'jest',
'echo',
'mkdir',
'touch',
],
blockedPatterns: [
/rm\s+-rf\s*\/[^/\s]*/gi, // Dangerous delete commands
/sudo\s+(rm|chmod|chown|passwd)/gi, // Sudo with dangerous commands
/eval\s*\(\s*[^)]*\$[^)]*\)/gi, // Dynamic code evaluation
/exec\s*\(\s*[^)]*\$[^)]*\)/gi, // Dynamic code execution
/system\s*\(\s*[^)]*\$[^)]*\)/gi, // System calls with variables
/shell_exec\s*\(\s*[^)]*\$[^)]*\)/gi, // Shell execution with variables
/\|\s*(sh|bash|zsh|fish|csh)/gi, // Piping to shell
/>\s*\/dev\/(zero|null|random)/gi, // Redirecting to device files
/dd\s+if=/gi, // Disk dump commands
/mkfs/gi, // File system creation
/fdisk/gi, // Disk partitioning
/format/gi, // Format commands
/shutdown|reboot|halt|poweroff/gi, // System shutdown commands
/&&\s*(rm|del|format)/gi, // Chained dangerous commands
/;\s*(rm|del|format)/gi, // Semicolon chained commands
/\$\(.*\)/gi, // Command substitution
/`.*`/gi, // Backtick command execution
/curl\s+.*\|\s*(sh|bash)/gi, // Remote code execution
/wget\s+.*\|\s*(sh|bash)/gi, // Remote code execution
/nc\s+-[^s]*e/gi, // Netcat with command execution
],
...config,
};
this.e2bService = new E2BService();
this.securityValidator = new SecurityValidator();
}
/**
* Initialize the secure execution manager
*/
async initialize(): Promise<void> {
try {
await this.e2bService.initialize();
this.isInitialized = true;
logger.info('🔒 Secure Execution Manager initialized - E2B enforcement active');
if (this.config.enforceE2BOnly) {
logger.warn('⚠️ SECURITY ENFORCEMENT: Local command execution is BLOCKED');
logger.info('✅ All code execution will be sandboxed via E2B');
}
} catch (error) {
logger.error('❌ Failed to initialize Secure Execution Manager:', error);
if (this.config.enforceE2BOnly) {
throw new Error(
'SECURITY CRITICAL: Cannot initialize E2B service. Code execution disabled for security.'
);
}
throw error;
}
}
/**
* Execute code securely with comprehensive security validation
*/
async executeSecurely(request: ExecutionRequest): Promise<ExecutionResult> {
const startTime = Date.now();
try {
// Audit log the execution request
if (this.config.auditLog) {
this.auditLogExecution(request);
}
// Validate that E2B is available if enforced
if (this.config.enforceE2BOnly && !this.isInitialized) {
return this.createBlockedResult(
'E2B service not available and local execution is blocked for security',
startTime,
request.sessionId
);
}
// Comprehensive security validation
const securityValidation = await this.validateExecutionSecurity(request);
if (!securityValidation.isValid) {
return this.createBlockedResult(
`Security validation failed: ${securityValidation.reason}`,
startTime,
request.sessionId,
[securityValidation.reason || 'Security validation failed']
);
}
// Force E2B execution if enforcement is enabled
if (this.config.enforceE2BOnly) {
return await this.executeViaE2B(request, startTime);
}
// This should never be reached in production with enforceE2BOnly=true
logger.error('🚨 SECURITY WARNING: Execution request not handled by E2B enforcement');
return this.createBlockedResult(
'Execution blocked: No secure execution path available',
startTime,
request.sessionId
);
} catch (error) {
logger.error('❌ Secure execution failed:', error);
return {
success: false,
stderr: `Secure execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
exitCode: 1,
executionTime: Date.now() - startTime,
sessionId: request.sessionId || 'unknown',
backend: 'error',
};
}
}
/**
* Execute code via E2B sandbox
*/
private async executeViaE2B(
request: ExecutionRequest,
startTime: number
): Promise<ExecutionResult> {
try {
const sessionId = request.sessionId || this.generateSessionId();
// Prepare secure execution environment
const sanitizedRequest = this.sanitizeExecutionRequest(request);
// Execute in E2B sandbox
const result = await this.e2bService.executeCode(
sessionId,
sanitizedRequest.command,
sanitizedRequest.language || 'python'
);
logger.info(
`✅ E2B execution completed - Success: ${result.success}, Time: ${result.executionTime}ms`
);
return {
success: result.success,
stdout: result.output,
stderr: result.error,
exitCode: result.success ? 0 : 1,
executionTime: Date.now() - startTime,
sessionId,
backend: 'e2b',
};
} catch (error) {
logger.error('❌ E2B execution failed:', error);
return {
success: false,
stderr: `E2B execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
exitCode: 1,
executionTime: Date.now() - startTime,
sessionId: request.sessionId || 'unknown',
backend: 'error',
};
}
}
/**
* Validate execution security
*/
private async validateExecutionSecurity(
request: ExecutionRequest
): Promise<{ isValid: boolean; reason?: string; severity?: string }> {
try {
// Basic input validation
if (!request.command || typeof request.command !== 'string') {
return {
isValid: false,
reason: 'Invalid command: must be a non-empty string',
severity: 'high',
};
}
if (request.command.length > 10000) {
return {
isValid: false,
reason: 'Command too long (max 10,000 characters)',
severity: 'high',
};
}
// Check against blocked patterns
for (const pattern of this.config.blockedPatterns) {
if (pattern.test(request.command)) {
return {
isValid: false,
reason: `Command matches blocked security pattern: ${pattern.source}`,
severity: 'critical',
};
}
}
// Command allowlist validation (if enforcing allowlist)
if (this.config.allowedCommands.length > 0) {
const firstWord = request.command.trim().split(/\s+/)[0];
const isAllowed = this.config.allowedCommands.some(
allowed => firstWord === allowed || firstWord.startsWith(allowed + '.')
);
if (!isAllowed) {
return {
isValid: false,
reason: `Command not in allowlist: ${firstWord}`,
severity: 'high',
};
}
}
// Use the advanced security validator
const validationResult = await this.securityValidator.validateCommand(request.command);
if (!validationResult.isValid) {
return {
isValid: false,
reason: validationResult.reason,
severity: validationResult.severity,
};
}
return { isValid: true };
} catch (error) {
logger.error('Security validation error:', error);
return {
isValid: false,
reason: 'Security validation system error',
severity: 'critical',
};
}
}
/**
* Sanitize execution request to remove potentially dangerous elements
*/
private sanitizeExecutionRequest(request: ExecutionRequest): ExecutionRequest {
const sanitized: ExecutionRequest = {
command: request.command.trim(),
language: request.language || 'python',
workingDirectory: request.workingDirectory || '/tmp',
timeout: Math.min(request.timeout || 30000, this.config.maxExecutionTime),
sessionId: request.sessionId,
};
// Remove dangerous environment variables
if (request.environment) {
sanitized.environment = {};
for (const [key, value] of Object.entries(request.environment)) {
// Only allow safe environment variables
if (this.isSafeEnvironmentVariable(key, value)) {
sanitized.environment[key] = value;
}
}
}
return sanitized;
}
/**
* Check if environment variable is safe to pass through
*/
private isSafeEnvironmentVariable(key: string, value: string): boolean {
// Block dangerous environment variables
const dangerousEnvVars = [
'PATH',
'LD_LIBRARY_PATH',
'LD_PRELOAD',
'DYLD_LIBRARY_PATH',
'HOME',
'USER',
'USERNAME',
'SHELL',
'TERM',
'SSH_AUTH_SOCK',
'SSH_AGENT_PID',
'SSH_CONNECTION',
'SUDO_USER',
'SUDO_UID',
'SUDO_GID',
'SUDO_COMMAND',
];
if (dangerousEnvVars.includes(key.toUpperCase())) {
return false;
}
// Block environment variables with dangerous patterns
if (
key.startsWith('_') ||
key.includes('PASSWORD') ||
key.includes('SECRET') ||
key.includes('TOKEN')
) {
return false;
}
// Block values with dangerous patterns
if (
value.includes(';') ||
value.includes('&&') ||
value.includes('||') ||
value.includes('`')
) {
return false;
}
return true;
}
/**
* Create a blocked execution result
*/
private createBlockedResult(
reason: string,
startTime: number,
sessionId?: string,
securityWarnings?: string[]
): ExecutionResult {
logger.warn(`🚨 Execution blocked: ${reason}`);
return {
success: false,
stderr: `Execution blocked for security: ${reason}`,
exitCode: 403, // Forbidden
executionTime: Date.now() - startTime,
sessionId: sessionId || 'unknown',
securityWarnings,
backend: 'blocked',
};
}
/**
* Audit log execution requests for security monitoring
*/
private auditLogExecution(request: ExecutionRequest): void {
const auditEntry = {
timestamp: new Date().toISOString(),
action: 'code_execution',
command: request.command,
language: request.language,
sessionId: request.sessionId,
workingDirectory: request.workingDirectory,
hasEnvironment: !!request.environment,
environmentVarCount: request.environment ? Object.keys(request.environment).length : 0,
commandLength: request.command.length,
timeout: request.timeout,
};
logger.info('🔍 AUDIT: Code execution request', auditEntry);
}
/**
* Generate a secure session ID
*/
private generateSessionId(): string {
const timestamp = Date.now().toString(36);
const random = Math.random().toString(36).substring(2);
return `sec_${timestamp}_${random}`;
}
/**
* Get execution statistics for monitoring
*/
getStats(): {
e2bService: any;
config: SecureExecutionConfig;
isInitialized: boolean;
} {
return {
e2bService: this.e2bService.getStats(),
config: this.config,
isInitialized: this.isInitialized,
};
}
/**
* Shutdown and cleanup resources
*/
async shutdown(): Promise<void> {
await this.e2bService.shutdown();
this.isInitialized = false;
logger.info('🔒 Secure Execution Manager shut down');
}
}
/**
* Default secure execution manager instance
*/
export const secureExecutionManager = new SecureExecutionManager();