codecrucible-synth
Version:
Production-Ready AI Development Platform with Multi-Voice Synthesis, Smithery MCP Integration, Enterprise Security, and Zero-Timeout Reliability
135 lines • 4.59 kB
JavaScript
import { SecurityUtils } from '../core/security.js';
import { logger } from '../core/logger.js';
export class MCPSecurityValidator {
static SENSITIVE_COMMANDS = [
'rm -rf',
'sudo',
'su ',
'chmod +x',
'passwd',
'useradd',
'userdel',
'curl.*|.*sh',
'wget.*|.*sh',
'nc.*-e',
'python.*-c.*exec',
];
static ALLOWED_REMOTE_COMMANDS = [
'ls',
'pwd',
'cd',
'cat',
'echo',
'grep',
'find',
'git',
'npm',
'node',
'tsc',
'jest',
'eslint',
'prettier',
];
static async validateToolCall(serverId, toolName, args) {
// Basic argument validation
if (!args || typeof args !== 'object') {
logger.warn(`Invalid arguments for ${serverId}.${toolName}`);
return false;
}
// Server-specific validation
switch (serverId) {
case 'terminal-controller':
return await this.validateTerminalControllerCall(toolName, args);
case 'task-manager':
return this.validateTaskManagerCall(toolName, args);
case 'remote-shell':
return this.validateRemoteShellCall(toolName, args);
default:
logger.warn(`Unknown MCP server: ${serverId}`);
return false;
}
}
static async validateTerminalControllerCall(toolName, args) {
switch (toolName) {
case 'execute_command':
return this.validateCommand(args.command);
case 'write_file':
case 'read_file':
return await this.validateFilePath(args.path || args.file_path);
case 'change_directory':
return await this.validateDirectoryPath(args.path);
default:
return true; // Allow other operations
}
}
static validateTaskManagerCall(toolName, args) {
// Task manager operations are generally safe
// Validate task content for potential code injection
if (args.task && typeof args.task === 'string') {
return !this.containsSensitiveContent(args.task);
}
return true;
}
static validateRemoteShellCall(toolName, args) {
if (toolName === 'shell-exec') {
// More restrictive validation for remote execution
return this.validateRemoteCommand(args.command);
}
return true;
}
static validateCommand(command) {
if (!command || typeof command !== 'string') {
return false;
}
// Check for sensitive command patterns
for (const pattern of this.SENSITIVE_COMMANDS) {
const regex = new RegExp(pattern, 'i');
if (regex.test(command)) {
logger.warn(`Blocked sensitive command: ${command}`);
return false;
}
}
return true;
}
static validateRemoteCommand(command) {
if (!this.validateCommand(command)) {
return false;
}
// Additional restrictions for remote execution
const baseCommand = command.trim().split(' ')[0];
const isAllowed = this.ALLOWED_REMOTE_COMMANDS.some(allowed => baseCommand === allowed || baseCommand.startsWith(allowed));
if (!isAllowed) {
logger.warn(`Remote command not in allowed list: ${baseCommand}`);
return false;
}
return true;
}
static async validateFilePath(filePath) {
if (!filePath || typeof filePath !== 'string') {
return false;
}
try {
// Use existing security validation - create instance if needed
const securityUtils = new SecurityUtils();
const validation = await securityUtils.validatePath(filePath);
return validation.isValid;
}
catch (error) {
logger.warn(`File path validation failed: ${error}`);
return false;
}
}
static async validateDirectoryPath(dirPath) {
return await this.validateFilePath(dirPath);
}
static containsSensitiveContent(content) {
const sensitivePatterns = [
/password\s*[=:]\s*['"]/i,
/api[_-]?key\s*[=:]\s*['"]/i,
/secret\s*[=:]\s*['"]/i,
/token\s*[=:]\s*['"]/i,
];
return sensitivePatterns.some(pattern => pattern.test(content));
}
}
//# sourceMappingURL=mcp-security-validator.js.map