UNPKG

recoder-security

Version:

Enterprise-grade security and compliance layer for CodeCraft CLI

183 lines 8 kB
"use strict"; /** * Code Vulnerability Scanner * Scans code for security vulnerabilities and issues */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.CodeVulnerabilityScanner = void 0; const shared_1 = require("@recoder/shared"); const fs = __importStar(require("fs")); const path = __importStar(require("path")); class CodeVulnerabilityScanner { constructor() { this.vulnerabilityPatterns = [ { pattern: /(?:password|pwd|pass)\s*=\s*['""][^'""]+['""];?/gi, severity: 'high', category: 'hardcoded_secret', title: 'Hardcoded Password', description: 'Password found hardcoded in source code', recommendation: 'Use environment variables or secure configuration files' }, { pattern: /(?:api_key|apikey|secret)\s*=\s*['""][^'""]+['""];?/gi, severity: 'critical', category: 'hardcoded_secret', title: 'Hardcoded API Key', description: 'API key found hardcoded in source code', recommendation: 'Store API keys in environment variables or secure vault' }, { pattern: /innerHTML\s*=\s*[^;]+;?/gi, severity: 'medium', category: 'xss', title: 'Potential XSS via innerHTML', description: 'Direct innerHTML assignment may lead to XSS vulnerabilities', recommendation: 'Use textContent or properly sanitize HTML content' }, { pattern: /eval\s*\([^)]+\)/gi, severity: 'high', category: 'injection', title: 'Code Injection via eval()', description: 'Use of eval() can lead to code injection vulnerabilities', recommendation: 'Avoid eval() and use safer alternatives like JSON.parse()' }, { pattern: /\.\.\//g, severity: 'medium', category: 'path_traversal', title: 'Path Traversal', description: 'Directory traversal patterns detected', recommendation: 'Validate and sanitize file paths, use path.resolve()' }, { pattern: /exec\s*\([^)]+\)/gi, severity: 'high', category: 'command_injection', title: 'Command Injection', description: 'Use of exec() can lead to command injection', recommendation: 'Use safer alternatives or properly validate input' } ]; } async scanDirectory(dirPath) { const vulnerabilities = []; try { await this.scanDirectoryRecursive(dirPath, vulnerabilities); } catch (error) { shared_1.Logger.error('Error scanning directory:', error); } return vulnerabilities; } async scanFile(filePath) { const vulnerabilities = []; try { const content = await fs.promises.readFile(filePath, 'utf-8'); const lines = content.split('\n'); lines.forEach((line, lineIndex) => { this.vulnerabilityPatterns.forEach(pattern => { const matches = line.match(pattern.pattern); if (matches) { matches.forEach(match => { const columnIndex = line.indexOf(match); vulnerabilities.push({ id: `vuln-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, title: pattern.title, description: pattern.description, severity: pattern.severity, category: pattern.category, file: filePath, line: lineIndex + 1, column: columnIndex + 1, code: line.trim(), recommendation: pattern.recommendation }); }); } }); }); } catch (error) { shared_1.Logger.error(`Error scanning file ${filePath}:`, error); } return vulnerabilities; } generateReport(vulnerabilities) { const summary = { critical: vulnerabilities.filter(v => v.severity === 'critical').length, high: vulnerabilities.filter(v => v.severity === 'high').length, medium: vulnerabilities.filter(v => v.severity === 'medium').length, low: vulnerabilities.filter(v => v.severity === 'low').length }; // Calculate security score (0-100) const totalIssues = summary.critical + summary.high + summary.medium + summary.low; const weightedScore = (summary.critical * 10) + (summary.high * 5) + (summary.medium * 2) + (summary.low * 1); const securityScore = totalIssues === 0 ? 100 : Math.max(0, 100 - weightedScore); return { totalFiles: new Set(vulnerabilities.map(v => v.file)).size, vulnerabilities, securityScore, summary }; } async scanDirectoryRecursive(dirPath, vulnerabilities) { const entries = await fs.promises.readdir(dirPath, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dirPath, entry.name); if (entry.isDirectory()) { // Skip node_modules and other common directories if (!['node_modules', '.git', 'dist', 'build', '.next'].includes(entry.name)) { await this.scanDirectoryRecursive(fullPath, vulnerabilities); } } else if (entry.isFile()) { // Only scan code files if (this.isCodeFile(entry.name)) { const fileVulns = await this.scanFile(fullPath); vulnerabilities.push(...fileVulns); } } } } isCodeFile(filename) { const codeExtensions = ['.js', '.ts', '.jsx', '.tsx', '.py', '.java', '.cs', '.php', '.rb', '.go', '.rs', '.cpp', '.c', '.h']; return codeExtensions.some(ext => filename.endsWith(ext)); } } exports.CodeVulnerabilityScanner = CodeVulnerabilityScanner; //# sourceMappingURL=code-vulnerability-scanner.js.map