UNPKG

vibe-guard

Version:

🛡️ Vibe-Guard Security Scanner - Catch security issues before they catch you!

152 lines 7.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InsecureDependenciesRule = void 0; const types_1 = require("../types"); class InsecureDependenciesRule extends types_1.BaseRule { constructor() { super(...arguments); this.name = 'insecure-dependencies'; this.description = 'Detects potentially insecure dependencies and packages'; this.severity = 'medium'; this.vulnerablePackages = [ // Known vulnerable packages { name: 'lodash', versions: ['<4.17.21'], reason: 'Prototype pollution vulnerabilities' }, { name: 'moment', versions: ['*'], reason: 'Deprecated package, use date-fns or dayjs instead' }, { name: 'request', versions: ['*'], reason: 'Deprecated package with security issues' }, { name: 'node-uuid', versions: ['*'], reason: 'Deprecated, use uuid package instead' }, { name: 'growl', versions: ['<1.10.0'], reason: 'Command injection vulnerability' }, { name: 'handlebars', versions: ['<4.7.7'], reason: 'Template injection vulnerabilities' }, { name: 'serialize-javascript', versions: ['<3.1.0'], reason: 'XSS vulnerability' }, { name: 'minimist', versions: ['<1.2.6'], reason: 'Prototype pollution vulnerability' }, { name: 'yargs-parser', versions: ['<13.1.2'], reason: 'Prototype pollution vulnerability' }, { name: 'ini', versions: ['<1.3.6'], reason: 'Prototype pollution vulnerability' }, // Python packages { name: 'django', versions: ['<3.2.13'], reason: 'Multiple security vulnerabilities' }, { name: 'flask', versions: ['<2.0.0'], reason: 'Security improvements in newer versions' }, { name: 'requests', versions: ['<2.20.0'], reason: 'SSL verification issues' }, { name: 'pyyaml', versions: ['<5.4'], reason: 'Arbitrary code execution vulnerability' }, { name: 'pillow', versions: ['<8.3.2'], reason: 'Multiple image processing vulnerabilities' }, // PHP packages { name: 'symfony/symfony', versions: ['<4.4.35'], reason: 'Multiple security vulnerabilities' }, { name: 'laravel/framework', versions: ['<8.75.0'], reason: 'Security vulnerabilities' }, { name: 'monolog/monolog', versions: ['<2.3.5'], reason: 'Remote code execution vulnerability' } ]; this.suspiciousPatterns = [ // Suspicious package names { pattern: /(?:^|\s)(?:eval|exec|shell|cmd|system|proc|spawn)(?:-|_)?(?:js|py|php|rb)?\s*[:=]/gi, type: 'Suspicious package name' }, { pattern: /(?:^|\s)(?:backdoor|malware|virus|trojan|keylogger)\s*[:=]/gi, type: 'Malicious package name' }, // Typosquatting patterns (common misspellings) { pattern: /(?:^|\s)(?:lodahs|momnet|expres|reactt|angualr|vuejs)\s*[:=]/gi, type: 'Potential typosquatting' }, // Suspicious version patterns { pattern: /["'](?:\*|latest|>.*|>=.*\|\|.*|.*\.\*\.\*)["']/g, type: 'Overly permissive version range' }, // Development dependencies in production { pattern: /"devDependencies"\s*:\s*\{[^}]*"(?:nodemon|webpack-dev-server|jest|mocha|chai|sinon)"/gi, type: 'Development dependency' } ]; } check(fileContent) { const issues = []; // Only check dependency files if (!this.isDependencyFile(fileContent.path)) { return issues; } // Check for vulnerable packages this.checkVulnerablePackages(fileContent, issues); // Check for suspicious patterns this.checkSuspiciousPatterns(fileContent, issues); return issues; } isDependencyFile(filePath) { const dependencyFiles = [ /package\.json$/i, /requirements\.txt$/i, /Pipfile$/i, /composer\.json$/i, /Gemfile$/i, /pom\.xml$/i, /build\.gradle$/i, /yarn\.lock$/i, /package-lock\.json$/i ]; return dependencyFiles.some(pattern => pattern.test(filePath)); } checkVulnerablePackages(fileContent, issues) { for (const pkg of this.vulnerablePackages) { const pattern = new RegExp(`["']${pkg.name}["']\\s*:\\s*["']([^"']+)["']`, 'gi'); const matches = this.findMatches(fileContent.content, pattern); for (const { match, line, column, lineContent } of matches) { const version = match[1]; if (version && this.isVulnerableVersion(version, pkg.versions)) { issues.push(this.createIssue(fileContent.path, line, column, lineContent, `Vulnerable dependency: ${pkg.name}@${version}`, `${pkg.reason}. Update to a secure version or find an alternative package.`)); } } } } checkSuspiciousPatterns(fileContent, issues) { for (const { pattern, type } of this.suspiciousPatterns) { const matches = this.findMatches(fileContent.content, pattern); for (const { line, column, lineContent } of matches) { // Skip development dependencies check if it's actually in devDependencies section if (type === 'Development dependency' && this.isInDevDependencies(fileContent.content, line)) { continue; } issues.push(this.createIssue(fileContent.path, line, column, lineContent, `Suspicious dependency pattern: ${type}`, `Review this dependency carefully. Ensure it's from a trusted source and serves a legitimate purpose.`)); } } } isVulnerableVersion(version, vulnerableVersions) { // Simple version checking - in a real implementation, you'd use semver for (const vulnVersion of vulnerableVersions) { if (vulnVersion === '*') { return true; } if (vulnVersion.startsWith('<')) { // This is a simplified check - real implementation would use proper semver comparison const targetVersion = vulnVersion.substring(1); if (this.compareVersions(version, targetVersion) < 0) { return true; } } if (version === vulnVersion) { return true; } } return false; } compareVersions(version1, version2) { // Simplified version comparison - real implementation would handle all semver cases const v1Parts = version1.replace(/[^\d.]/g, '').split('.').map(Number); const v2Parts = version2.replace(/[^\d.]/g, '').split('.').map(Number); for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) { const v1Part = v1Parts[i] || 0; const v2Part = v2Parts[i] || 0; if (v1Part < v2Part) return -1; if (v1Part > v2Part) return 1; } return 0; } isInDevDependencies(content, lineNumber) { const lines = content.split('\n'); // Look backwards from the current line to find the section for (let i = lineNumber - 1; i >= 0; i--) { const line = lines[i]; if (!line) continue; const trimmedLine = line.trim(); if (trimmedLine.includes('"devDependencies"')) { return true; } if (trimmedLine.includes('"dependencies"') && !trimmedLine.includes('"devDependencies"')) { return false; } // If we hit another top-level section, stop looking if (trimmedLine.match(/^"[^"]+"\s*:\s*\{/) && !trimmedLine.includes('Dependencies')) { break; } } return false; } } exports.InsecureDependenciesRule = InsecureDependenciesRule; //# sourceMappingURL=insecure-dependencies.js.map