mcp-siber-security-audit
Version:
MCP server for security code audit with auto-fix capabilities
125 lines (114 loc) • 3.99 kB
JavaScript
const { ESLint } = require('eslint');
const path = require('path');
const fs = require('fs');
class ESLintScanner {
constructor() {
// Get the path to our package's node_modules
const packageRoot = path.dirname(require.resolve('../../package.json'));
const pluginPath = path.join(packageRoot, 'node_modules', 'eslint-plugin-security');
this.eslint = new ESLint({
resolvePluginsRelativeTo: packageRoot,
useEslintrc: false,
overrideConfigFile: null,
overrideConfig: {
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module',
},
plugins: ['security'],
rules: {
'security/detect-buffer-noassert': 'error',
'security/detect-child-process': 'error',
'security/detect-disable-mustache-escape': 'error',
'security/detect-eval-with-expression': 'error',
'security/detect-new-buffer': 'error',
'security/detect-no-csrf-before-method-override': 'error',
'security/detect-non-literal-fs-filename': 'error',
'security/detect-non-literal-regexp': 'error',
'security/detect-non-literal-require': 'error',
'security/detect-object-injection': 'error',
'security/detect-possible-timing-attacks': 'error',
'security/detect-pseudoRandomBytes': 'error',
'security/detect-unsafe-regex': 'error',
'security/detect-bidi-characters': 'error',
'no-eval': 'error',
},
},
});
}
async scanFile(filePath) {
const results = await this.eslint.lintFiles([filePath]);
return this.formatResults(results, filePath);
}
formatResults(results, filePath) {
// Use Map to group similar issues
const issueGroups = new Map();
for (const result of results) {
for (const message of result.messages) {
const type = this.mapRuleToType(message.ruleId);
const description = message.message;
// Create a key that uniquely identifies similar issues
const key = `${type}:${description}:${filePath}`;
if (!issueGroups.has(key)) {
issueGroups.set(key, {
scanner: 'eslint',
file: filePath,
locations: [],
type: type,
severity: this.mapSeverity(message.severity),
description: description,
ruleId: message.ruleId,
auto_fix_available: false
});
}
// Add location to the group
issueGroups.get(key).locations.push({
line: message.line,
column: message.column
});
}
}
// Convert grouped issues to final format
return Array.from(issueGroups.values()).map(issue => {
if (issue.locations.length === 1) {
// If only one location, use the original format
return {
...issue,
line: issue.locations[0].line,
column: issue.locations[0].column,
locations: undefined
};
} else {
// If multiple locations, include first one in main fields and list all in locations
return {
...issue,
line: issue.locations[0].line,
column: issue.locations[0].column,
description: `${issue.description} (Found in ${issue.locations.length} locations)`
};
}
});
}
mapRuleToType(ruleId) {
if (!ruleId) {
return 'LINT_ERROR';
}
if (ruleId.includes('sql-injection')) return 'SQL_INJECTION';
if (ruleId.includes('xss')) return 'XSS';
if (ruleId.startsWith('security/')) {
return ruleId.replace('security/', '').toUpperCase().replace(/-/g, '_');
}
if (ruleId === 'no-eval') {
return 'CODE_EXECUTION';
}
return 'UNKNOWN';
}
mapSeverity(eslintSeverity) {
switch (eslintSeverity) {
case 2: return 'high';
case 1: return 'medium';
default: return 'low';
}
}
}
module.exports = ESLintScanner;