vineguard-mcp-server-standalone
Version:
VineGuard MCP Server v2.1 - Intelligent QA Workflow System with advanced test generation for Jest/RTL, Cypress, and Playwright. Features smart project analysis, progressive testing strategies, and comprehensive quality patterns for React/Vue/Angular proje
450 lines • 18.9 kB
JavaScript
/**
* Security audit tool for VineGuard MCP Server
* Comprehensive security scanning and vulnerability detection
*/
import * as fs from 'fs/promises';
import * as path from 'path';
import { spawn } from 'child_process';
export class SecurityAuditor {
static SECURITY_PATTERNS = [
// Injection vulnerabilities
{
pattern: /eval\s*\(/g,
type: 'vulnerability',
severity: 'critical',
title: 'Code Injection - eval() usage',
description: 'Use of eval() can lead to code injection vulnerabilities',
suggestion: 'Replace eval() with safer alternatives like JSON.parse() or specific parsing logic',
cwe: 'CWE-94',
cvss: 9.0
},
{
pattern: /new\s+Function\s*\(/g,
type: 'vulnerability',
severity: 'high',
title: 'Code Injection - Function constructor',
description: 'Dynamic function creation can be exploited for code injection',
suggestion: 'Avoid dynamic function creation or use safer alternatives',
cwe: 'CWE-94',
cvss: 7.5
},
{
pattern: /document\.write\s*\(/g,
type: 'vulnerability',
severity: 'medium',
title: 'XSS Risk - document.write',
description: 'document.write can be exploited for XSS attacks',
suggestion: 'Use safer DOM manipulation methods like createElement',
cwe: 'CWE-79',
cvss: 6.1
},
{
pattern: /innerHTML\s*=/g,
type: 'security-risk',
severity: 'medium',
title: 'XSS Risk - innerHTML assignment',
description: 'Direct innerHTML assignment can lead to XSS if data is not sanitized',
suggestion: 'Use textContent or sanitize HTML content before assignment',
cwe: 'CWE-79',
cvss: 6.1
},
// Cryptographic issues
{
pattern: /Math\.random\s*\(\)/g,
type: 'security-risk',
severity: 'medium',
title: 'Weak Random Number Generation',
description: 'Math.random() is not cryptographically secure',
suggestion: 'Use crypto.randomBytes() or crypto.getRandomValues() for security-sensitive operations',
cwe: 'CWE-338',
cvss: 5.3
},
{
pattern: /md5|sha1(?!.*sha1[0-9])/gi,
type: 'security-risk',
severity: 'medium',
title: 'Weak Cryptographic Hash',
description: 'MD5 and SHA1 are cryptographically broken',
suggestion: 'Use SHA-256 or stronger hash functions',
cwe: 'CWE-327',
cvss: 5.9
},
// Command injection
{
pattern: /exec\s*\(/g,
type: 'vulnerability',
severity: 'high',
title: 'Command Injection Risk - exec()',
description: 'exec() with user input can lead to command injection',
suggestion: 'Use spawn() with argument arrays or validate/sanitize all inputs',
cwe: 'CWE-78',
cvss: 8.1
},
{
pattern: /system\s*\(/g,
type: 'vulnerability',
severity: 'high',
title: 'Command Injection Risk - system()',
description: 'system() calls can be exploited for command injection',
suggestion: 'Use safer alternatives like spawn() with proper input validation',
cwe: 'CWE-78',
cvss: 8.1
},
// Path traversal
{
pattern: /\.\.[\/\\]/g,
type: 'security-risk',
severity: 'high',
title: 'Path Traversal Risk',
description: 'Path traversal sequences detected',
suggestion: 'Validate and sanitize file paths, use path.resolve() and check bounds',
cwe: 'CWE-22',
cvss: 7.5
},
// Information disclosure
{
pattern: /console\.(log|error|warn|info)\s*\(/g,
type: 'best-practice',
severity: 'low',
title: 'Information Disclosure - Console Logging',
description: 'Console logs may expose sensitive information in production',
suggestion: 'Remove debug logs before production or use proper logging frameworks',
cwe: 'CWE-532',
cvss: 2.1
},
{
pattern: /password|secret|key|token.*=.*['"][^'"]+['"]/gi,
type: 'vulnerability',
severity: 'critical',
title: 'Hardcoded Secrets',
description: 'Potential hardcoded secrets detected',
suggestion: 'Move secrets to environment variables or secure configuration',
cwe: 'CWE-798',
cvss: 9.8
},
// Prototype pollution
{
pattern: /__proto__|constructor\.prototype|Object\.prototype/g,
type: 'vulnerability',
severity: 'high',
title: 'Prototype Pollution Risk',
description: 'Potential prototype pollution vulnerability',
suggestion: 'Avoid modifying object prototypes, use Object.create(null) for safe objects',
cwe: 'CWE-1321',
cvss: 7.5
},
// CORS issues
{
pattern: /Access-Control-Allow-Origin.*\*/g,
type: 'security-risk',
severity: 'medium',
title: 'Overly Permissive CORS',
description: 'Wildcard CORS policy detected',
suggestion: 'Specify explicit origins instead of using wildcards',
cwe: 'CWE-942',
cvss: 5.3
},
// SQL Injection (for projects that might use SQL)
{
pattern: /query.*\+.*|SELECT.*\+.*|INSERT.*\+.*/gi,
type: 'vulnerability',
severity: 'critical',
title: 'SQL Injection Risk',
description: 'Potential SQL injection vulnerability detected',
suggestion: 'Use parameterized queries or prepared statements',
cwe: 'CWE-89',
cvss: 9.0
}
];
/**
* Perform comprehensive security audit
*/
static async auditProject(projectPath, options = {}) {
const { includeNodeModules = false, includeDependencyAudit = true, maxFileSize = 1024 * 1024 // 1MB
} = options;
const result = {
projectPath,
scannedFiles: 0,
totalIssues: 0,
issuesBySeverity: {
critical: 0,
high: 0,
medium: 0,
low: 0,
info: 0
},
issues: [],
securityScore: 100,
recommendations: [],
scannedAt: new Date().toISOString()
};
try {
// Find all relevant files
const files = await this.findFiles(projectPath, includeNodeModules);
// Scan each file for security issues
for (const file of files) {
try {
const stats = await fs.stat(file);
if (stats.size > maxFileSize) {
continue; // Skip large files
}
const content = await fs.readFile(file, 'utf-8');
const fileIssues = this.scanFileContent(content, file);
result.issues.push(...fileIssues);
result.scannedFiles++;
}
catch (error) {
console.error(`Error scanning file ${file}:`, error);
}
}
// Perform dependency audit if requested
if (includeDependencyAudit) {
result.dependencyAudit = await this.auditDependencies(projectPath);
}
// Calculate statistics
this.calculateStatistics(result);
// Generate recommendations
result.recommendations = this.generateRecommendations(result);
}
catch (error) {
throw new Error(`Security audit failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
return result;
}
/**
* Scan file content for security issues
*/
static scanFileContent(content, filePath) {
const issues = [];
const lines = content.split('\n');
for (const pattern of this.SECURITY_PATTERNS) {
let match;
const regex = new RegExp(pattern.pattern.source, pattern.pattern.flags);
while ((match = regex.exec(content)) !== null) {
// Find the line number
const beforeMatch = content.substring(0, match.index);
const lineNumber = beforeMatch.split('\n').length;
issues.push({
type: pattern.type,
severity: pattern.severity,
title: pattern.title,
description: pattern.description,
file: filePath,
line: lineNumber,
suggestion: pattern.suggestion,
cwe: pattern.cwe,
cvss: pattern.cvss
});
}
}
// Additional file-specific checks
issues.push(...this.performAdditionalChecks(content, filePath));
return issues;
}
/**
* Perform additional security checks
*/
static performAdditionalChecks(content, filePath) {
const issues = [];
// Check for package.json security issues
if (filePath.endsWith('package.json')) {
try {
const packageData = JSON.parse(content);
// Check for scripts that might be dangerous
if (packageData.scripts) {
for (const [scriptName, scriptContent] of Object.entries(packageData.scripts)) {
if (typeof scriptContent === 'string' && /rm\s+-rf|del\s+\/s|format\s+c:|sudo/.test(scriptContent)) {
issues.push({
type: 'security-risk',
severity: 'high',
title: 'Dangerous npm script',
description: `Script "${scriptName}" contains potentially dangerous commands`,
file: filePath,
suggestion: 'Review and validate npm scripts for security risks',
cwe: 'CWE-78'
});
}
}
}
// Check for dependencies with known issues
const allDeps = { ...packageData.dependencies, ...packageData.devDependencies };
const dangerousDeps = ['lodash@4.17.15', 'debug@2.6.8', 'minimist@1.2.0'];
for (const [dep, version] of Object.entries(allDeps)) {
if (dangerousDeps.some(dangerous => `${dep}@${version}` === dangerous)) {
issues.push({
type: 'dependency-issue',
severity: 'high',
title: 'Vulnerable dependency',
description: `Dependency ${dep}@${version} has known vulnerabilities`,
file: filePath,
suggestion: 'Update to a secure version of this dependency'
});
}
}
}
catch (error) {
// Invalid JSON, but not necessarily a security issue
}
}
// Check for environment files with suspicious content
if (filePath.includes('.env')) {
const suspiciousEnvPatterns = [
/DATABASE_URL.*localhost/gi,
/DEBUG.*true/gi,
/NODE_ENV.*development/gi
];
for (const pattern of suspiciousEnvPatterns) {
if (pattern.test(content)) {
issues.push({
type: 'best-practice',
severity: 'medium',
title: 'Development configuration in env file',
description: 'Environment file contains development-specific settings',
file: filePath,
suggestion: 'Ensure production environment files don\'t contain development settings'
});
}
}
}
return issues;
}
/**
* Find all relevant files for security scanning
*/
static async findFiles(dir, includeNodeModules) {
const files = [];
const extensions = ['.js', '.ts', '.jsx', '.tsx', '.json', '.env', '.config.js', '.config.ts'];
async function scanDirectory(currentDir) {
try {
const items = await fs.readdir(currentDir);
for (const item of items) {
const fullPath = path.join(currentDir, item);
const stats = await fs.stat(fullPath);
if (stats.isDirectory()) {
if (!includeNodeModules && (item === 'node_modules' || item === '.git')) {
continue;
}
await scanDirectory(fullPath);
}
else if (stats.isFile()) {
const ext = path.extname(item);
if (extensions.includes(ext) || item.startsWith('.env')) {
files.push(fullPath);
}
}
}
}
catch (error) {
// Skip directories we can't read
}
}
await scanDirectory(dir);
return files;
}
/**
* Audit npm dependencies for vulnerabilities
*/
static async auditDependencies(projectPath) {
return new Promise((resolve) => {
const packageJsonPath = path.join(projectPath, 'package.json');
// Check if package.json exists
fs.access(packageJsonPath).then(() => {
// Try to run npm audit
const audit = spawn('npm', ['audit', '--json'], {
cwd: projectPath,
stdio: 'pipe'
});
let output = '';
audit.stdout?.on('data', (data) => {
output += data.toString();
});
audit.on('close', (code) => {
try {
if (output.trim()) {
const auditResult = JSON.parse(output);
const vulnerabilities = auditResult.metadata?.vulnerabilities?.total || 0;
resolve({
vulnerabilities,
outdatedPackages: 0, // Would need separate npm outdated check
recommendations: [
vulnerabilities > 0 ? 'Run npm audit fix to resolve vulnerabilities' : 'No known vulnerabilities found',
'Regularly update dependencies to latest secure versions',
'Consider using npm ci in production for reproducible builds'
]
});
}
else {
resolve({
vulnerabilities: 0,
outdatedPackages: 0,
recommendations: ['Could not perform dependency audit - no package.json or npm not available']
});
}
}
catch (error) {
resolve({
vulnerabilities: 0,
outdatedPackages: 0,
recommendations: ['Dependency audit failed - ensure npm is installed and package.json is valid']
});
}
});
}).catch(() => {
resolve({
vulnerabilities: 0,
outdatedPackages: 0,
recommendations: ['No package.json found - skipping dependency audit']
});
});
});
}
/**
* Calculate security statistics
*/
static calculateStatistics(result) {
result.totalIssues = result.issues.length;
// Count issues by severity
for (const issue of result.issues) {
result.issuesBySeverity[issue.severity]++;
}
// Calculate security score (0-100)
let score = 100;
score -= result.issuesBySeverity.critical * 20;
score -= result.issuesBySeverity.high * 10;
score -= result.issuesBySeverity.medium * 5;
score -= result.issuesBySeverity.low * 2;
score -= result.issuesBySeverity.info * 1;
// Factor in dependency vulnerabilities
if (result.dependencyAudit) {
score -= result.dependencyAudit.vulnerabilities * 5;
}
result.securityScore = Math.max(0, score);
}
/**
* Generate security recommendations
*/
static generateRecommendations(result) {
const recommendations = [];
if (result.issuesBySeverity.critical > 0) {
recommendations.push('URGENT: Address critical security vulnerabilities immediately');
}
if (result.issuesBySeverity.high > 0) {
recommendations.push('Address high-severity security issues as soon as possible');
}
if (result.issuesBySeverity.medium > 0) {
recommendations.push('Review and fix medium-severity security issues');
}
if (result.securityScore < 70) {
recommendations.push('Consider implementing a security-first development approach');
recommendations.push('Add security linting to your CI/CD pipeline');
}
if (result.dependencyAudit && result.dependencyAudit.vulnerabilities > 0) {
recommendations.push('Update vulnerable dependencies');
}
recommendations.push('Implement regular security audits in your development workflow');
recommendations.push('Consider using security-focused tools like ESLint security plugins');
recommendations.push('Follow OWASP security guidelines for your technology stack');
return recommendations;
}
}
//# sourceMappingURL=security-audit.js.map