UNPKG

@syntropysoft/praetorian

Version:

Praetorian CLI – A universal multi-environment configuration validator for DevSecOps teams. Validate, compare, and secure YAML/ENV files with ease.

317 lines 11.6 kB
"use strict"; /** * Vulnerability Scanner - Functional Programming * * Single Responsibility: Scan for security vulnerabilities only * Pure functions, no state, no side effects */ Object.defineProperty(exports, "__esModule", { value: true }); exports.getVulnerabilitySeverity = exports.detectXSS = exports.detectSQLInjection = exports.detectWeakCredentials = exports.detectInsecureProtocols = exports.detectWeakEncryption = exports.scanVulnerabilities = void 0; /** * Pure function to scan for vulnerabilities */ const scanVulnerabilities = (content, rules, context) => { // Guard clause: no content if (!content || content.trim().length === 0) { return []; } // Guard clause: no rules if (!rules || rules.length === 0) { return []; } return rules .filter(rule => rule.enabled) .flatMap(rule => scanVulnerabilitiesWithRule(content, rule, context)); }; exports.scanVulnerabilities = scanVulnerabilities; /** * Pure function to scan vulnerabilities with a specific rule */ const scanVulnerabilitiesWithRule = (content, rule, context) => { // Guard clause: invalid rule if (!rule || !rule.pattern) { return []; } const matches = findVulnerabilityMatches(content, rule.pattern); return matches.map(match => createVulnerabilityResult(match, rule, content)); }; /** * Pure function to find vulnerability matches */ const findVulnerabilityMatches = (content, pattern) => { const matches = []; let match; // Reset regex lastIndex to ensure global search works pattern.lastIndex = 0; while ((match = pattern.exec(content)) !== null) { matches.push({ value: match[0], index: match.index }); // Prevent infinite loop on zero-length matches if (match.index === pattern.lastIndex) { pattern.lastIndex++; } } return matches; }; /** * Pure function to create vulnerability result */ const createVulnerabilityResult = (match, rule, content) => { const { lineNumber, columnNumber } = getLineAndColumn(content, match.index); return { type: rule.category, cve: rule.cve, cvssScore: rule.cvssScore, description: rule.description, remediation: rule.remediation, references: rule.references, lineNumber, columnNumber }; }; /** * Pure function to get line and column from index */ const getLineAndColumn = (content, index) => { const beforeMatch = content.substring(0, index); const lineNumber = (beforeMatch.match(/\n/g) || []).length + 1; const lastNewline = beforeMatch.lastIndexOf('\n'); const columnNumber = index - lastNewline; return { lineNumber, columnNumber }; }; /** * Pure function to detect weak encryption */ const detectWeakEncryption = (content) => { // Guard clause: no content if (!content || content.trim().length === 0) { return []; } const weakEncryptionPatterns = [ { pattern: /MD5\s*\(/gi, type: 'encryption', description: 'MD5 hash function detected - cryptographically broken', remediation: 'Use SHA-256 or stronger hash functions', cve: 'CVE-2004-2761' }, { pattern: /SHA1\s*\(/gi, type: 'encryption', description: 'SHA-1 hash function detected - cryptographically weak', remediation: 'Use SHA-256 or stronger hash functions', cve: 'CVE-2005-4900' }, { pattern: /DES\s*\(/gi, type: 'encryption', description: 'DES encryption detected - cryptographically weak', remediation: 'Use AES-256 or stronger encryption', cve: 'CVE-1999-0017' }, { pattern: /RC4\s*\(/gi, type: 'encryption', description: 'RC4 encryption detected - cryptographically weak', remediation: 'Use AES-256 or stronger encryption', cve: 'CVE-2015-2808' } ]; return weakEncryptionPatterns.flatMap(weakPattern => findVulnerabilityMatches(content, weakPattern.pattern).map(match => ({ type: weakPattern.type, cve: weakPattern.cve, description: weakPattern.description, remediation: weakPattern.remediation, lineNumber: getLineAndColumn(content, match.index).lineNumber, columnNumber: getLineAndColumn(content, match.index).columnNumber }))); }; exports.detectWeakEncryption = detectWeakEncryption; /** * Pure function to detect insecure protocols */ const detectInsecureProtocols = (content) => { // Guard clause: no content if (!content || content.trim().length === 0) { return []; } const insecureProtocolPatterns = [ { pattern: /http:\/\//gi, type: 'protocol', description: 'HTTP protocol detected - data transmitted in plain text', remediation: 'Use HTTPS for all communications', cve: 'CVE-2014-3566' }, { pattern: /ftp:\/\//gi, type: 'protocol', description: 'FTP protocol detected - credentials transmitted in plain text', remediation: 'Use SFTP or FTPS for secure file transfer', cve: 'CVE-1999-0017' }, { pattern: /telnet:\/\//gi, type: 'protocol', description: 'Telnet protocol detected - credentials transmitted in plain text', remediation: 'Use SSH for secure remote access', cve: 'CVE-1999-0017' } ]; return insecureProtocolPatterns.flatMap(protocolPattern => findVulnerabilityMatches(content, protocolPattern.pattern).map(match => ({ type: protocolPattern.type, cve: protocolPattern.cve, description: protocolPattern.description, remediation: protocolPattern.remediation, lineNumber: getLineAndColumn(content, match.index).lineNumber, columnNumber: getLineAndColumn(content, match.index).columnNumber }))); }; exports.detectInsecureProtocols = detectInsecureProtocols; /** * Pure function to detect weak credentials */ const detectWeakCredentials = (content) => { // Guard clause: no content if (!content || content.trim().length === 0) { return []; } const weakCredentialPatterns = [ { pattern: /password\s*[:=]\s*["']?admin["']?/gi, type: 'credential', description: 'Default admin password detected', remediation: 'Use strong, unique passwords', cve: 'CVE-2019-11043' }, { pattern: /password\s*[:=]\s*["']?password["']?/gi, type: 'credential', description: 'Weak password detected', remediation: 'Use strong, unique passwords', cve: 'CVE-2019-11043' }, { pattern: /password\s*[:=]\s*["']?123456["']?/gi, type: 'credential', description: 'Weak numeric password detected', remediation: 'Use strong, unique passwords', cve: 'CVE-2019-11043' }, { pattern: /password\s*[:=]\s*["']?[a-zA-Z0-9]{1,6}["']?/gi, type: 'credential', description: 'Short password detected', remediation: 'Use passwords with at least 8 characters', cve: 'CVE-2019-11043' } ]; return weakCredentialPatterns.flatMap(credPattern => findVulnerabilityMatches(content, credPattern.pattern).map(match => ({ type: credPattern.type, cve: credPattern.cve, description: credPattern.description, remediation: credPattern.remediation, lineNumber: getLineAndColumn(content, match.index).lineNumber, columnNumber: getLineAndColumn(content, match.index).columnNumber }))); }; exports.detectWeakCredentials = detectWeakCredentials; /** * Pure function to detect SQL injection vulnerabilities */ const detectSQLInjection = (content) => { // Guard clause: no content if (!content || content.trim().length === 0) { return []; } const sqlInjectionPatterns = [ { pattern: /SELECT\s+.*\s+FROM\s+.*\s+WHERE\s+.*\$\{/gi, type: 'injection', description: 'Potential SQL injection vulnerability - string interpolation in WHERE clause', remediation: 'Use parameterized queries or prepared statements', cve: 'CVE-2019-5418' }, { pattern: /INSERT\s+INTO\s+.*\s+VALUES\s+.*\$\{/gi, type: 'injection', description: 'Potential SQL injection vulnerability - string interpolation in INSERT', remediation: 'Use parameterized queries or prepared statements', cve: 'CVE-2019-5418' }, { pattern: /UPDATE\s+.*\s+SET\s+.*\s+WHERE\s+.*\$\{/gi, type: 'injection', description: 'Potential SQL injection vulnerability - string interpolation in UPDATE', remediation: 'Use parameterized queries or prepared statements', cve: 'CVE-2019-5418' } ]; return sqlInjectionPatterns.flatMap(sqlPattern => findVulnerabilityMatches(content, sqlPattern.pattern).map(match => ({ type: sqlPattern.type, cve: sqlPattern.cve, description: sqlPattern.description, remediation: sqlPattern.remediation, lineNumber: getLineAndColumn(content, match.index).lineNumber, columnNumber: getLineAndColumn(content, match.index).columnNumber }))); }; exports.detectSQLInjection = detectSQLInjection; /** * Pure function to detect XSS vulnerabilities */ const detectXSS = (content) => { // Guard clause: no content if (!content || content.trim().length === 0) { return []; } const xssPatterns = [ { pattern: /innerHTML\s*=\s*.*\$\{/gi, type: 'xss', description: 'Potential XSS vulnerability - innerHTML with string interpolation', remediation: 'Use textContent or sanitize HTML content', cve: 'CVE-2019-5418' }, { pattern: /document\.write\s*\(.*\$\{/gi, type: 'xss', description: 'Potential XSS vulnerability - document.write with string interpolation', remediation: 'Use DOM manipulation methods or sanitize content', cve: 'CVE-2019-5418' } ]; return xssPatterns.flatMap(xssPattern => findVulnerabilityMatches(content, xssPattern.pattern).map(match => ({ type: xssPattern.type, cve: xssPattern.cve, description: xssPattern.description, remediation: xssPattern.remediation, lineNumber: getLineAndColumn(content, match.index).lineNumber, columnNumber: getLineAndColumn(content, match.index).columnNumber }))); }; exports.detectXSS = detectXSS; /** * Pure function to get vulnerability severity */ const getVulnerabilitySeverity = (cve, cvssScore) => { // Guard clause: no CVE or CVSS score if (!cve && !cvssScore) { return 'medium'; } if (cvssScore !== undefined) { if (cvssScore >= 9.0) return 'critical'; if (cvssScore >= 7.0) return 'high'; if (cvssScore >= 4.0) return 'medium'; return 'low'; } // Default based on CVE presence return cve ? 'high' : 'medium'; }; exports.getVulnerabilitySeverity = getVulnerabilitySeverity; //# sourceMappingURL=VulnerabilityScanner.js.map