mcp-siber-security-audit
Version:
MCP server for security code audit with auto-fix capabilities
146 lines (128 loc) • 4.99 kB
JavaScript
const fs = require('fs');
const path = require('path');
const ESLintScanner = require('./src/scanners/eslint-scanner');
const SecretScanner = require('./src/scanners/secret-scanner');
const SemgrepScanner = require('./src/scanners/semgrep-scanner');
const DependencyScanner = require('./src/scanners/dependency-scanner');
const InsecureURLFixer = require('./src/fixers/common-fixes');
const ESLintFixer = require('./src/fixers/eslint-fixer');
const XSSFixer = require('./src/fixers/xss-fixer');
const SQLInjectionFixer = require('./src/fixers/sql-injection-fixer');
const SecretFixer = require('./src/fixers/secret-fixer');
const ReportGenerator = require('./src/utils/report-generator');
class SecurityAuditor {
constructor() {
this.scanners = [
new ESLintScanner(),
new SecretScanner(),
new SemgrepScanner(),
new DependencyScanner(),
];
this.fixers = {
'HARDCODED_API_KEY': new SecretFixer(),
'INSECURE_URL': new SecretFixer(),
'SRC.CONFIG.EXPRESS_XSS': new XSSFixer(),
'SRC.CONFIG.EXPRESS_SQL_INJECTION': new SQLInjectionFixer(),
};
}
async scan(directory) {
const issues = [];
const files = this._getAllFiles(directory);
for (const file of files) {
for (const scanner of this.scanners) {
const results = await scanner.scanFile(file);
issues.push(...results);
}
}
return issues;
}
async fix(issues) {
for (const issue of issues) {
const fixer = this.fixers[issue.type];
if (fixer) {
const fileContent = fs.readFileSync(issue.file, 'utf-8');
const { fixedContent, isFixed } = fixer.applyFix(fileContent, issue);
if (isFixed) {
fs.writeFileSync(issue.file, fixedContent);
console.log(`Fixed: ${issue.description} in ${issue.file}`);
}
}
}
}
_getAllFiles(dir) {
try {
let files = [];
// Normalize path to handle . and .. correctly
const normalizedDir = path.resolve(dir);
// Check if directory exists
if (!fs.existsSync(normalizedDir)) {
console.error(`Error: Directory "${dir}" does not exist.`);
console.error('Usage: mcp-siber-security-audit <directory> [--fix]');
console.error('Example: ');
console.error(' mcp-siber-security-audit .');
console.error(' mcp-siber-security-audit my-project');
process.exit(1);
}
const entries = fs.readdirSync(normalizedDir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(normalizedDir, entry.name);
if (entry.isDirectory()) {
if (entry.name === 'node_modules') continue;
files = files.concat(this._getAllFiles(fullPath));
} else {
if (path.extname(entry.name) === '.js' || entry.name === 'package.json') {
files.push(fullPath);
}
}
}
return files;
} catch (error) {
console.error(`Error scanning directory: ${error.message}`);
process.exit(1);
}
}
async run() {
const args = process.argv.slice(2);
const directory = args[0];
const shouldFix = args.includes('--fix');
const shouldGenerateReport = args.includes('--report');
const reportDir = args.find(arg => arg.startsWith('--report-dir='))?.split('=')?.[1] || 'security-reports';
if (!directory) {
console.error('Usage: mcp-siber-security-audit <directory> [--fix] [--report] [--report-dir=path]');
console.error('Options:');
console.error(' --fix Automatically fix detected issues when possible');
console.error(' --report Generate detailed reports (JSON, Markdown, and HTML)');
console.error(' --report-dir=path Specify output directory for reports (default: security-reports)');
process.exit(1);
}
const issues = await this.scan(directory);
// Always show summary in console
console.log('\nSecurity Scan Results:');
const severityCounts = issues.reduce((acc, issue) => {
acc[issue.severity] = (acc[issue.severity] || 0) + 1;
return acc;
}, {});
console.log('\nIssues found by severity:');
Object.entries(severityCounts).forEach(([severity, count]) => {
console.log(`${severity.toUpperCase()}: ${count}`);
});
// Generate report
const reporter = new ReportGenerator();
reporter.addIssues(issues);
if (shouldGenerateReport) {
const reportPaths = reporter.saveReport(reportDir);
console.log(`\nReport saved to: ${reportPaths.jsonPath}`);
} else {
// If no report requested, show structured output in console
console.log(JSON.stringify(reporter.report, null, 2));
}
if (shouldFix) {
console.log('\nApplying fixes...');
await this.fix(issues);
console.log('Fixes applied.');
}
}
}
const auditor = new SecurityAuditor();
auditor.run().catch(error => console.error(error));