const { spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
// Helper to run commands
function runCommand(command, args, options = {}) {
return new Promise((resolve, reject) => {
const proc = spawn(command, args, {
shell: true,
stdio: options.silent ? 'pipe' : 'inherit',
...options
});
let stdout = '';
let stderr = '';
if (options.silent) {
proc.stdout.on('data', (data) => stdout += data.toString());
proc.stderr.on('data', (data) => stderr += data.toString());
}
proc.on('close', (code) => {
resolve({ code, stdout, stderr, success: code === 0 });
});
proc.on('error', (error) => {
reject(error);
});
});
}
// Helper to make HTTP requests
async function fetch(url) {
const http = require('http');
const https = require('https');
const urlModule = require('url');
return new Promise((resolve, reject) => {
const parsedUrl = urlModule.parse(url);
const protocol = parsedUrl.protocol === 'https:' ? https : http;
const options = {
hostname: parsedUrl.hostname,
port: parsedUrl.port,
path: parsedUrl.path,
method: 'GET'
};
const req = protocol.request(options, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => {
resolve({
status: res.statusCode,
text: () => Promise.resolve(data),
json: () => Promise.resolve(JSON.parse(data))
});
});
});
req.on('error', reject);
req.setTimeout(5000, () => {
req.destroy();
reject(new Error('Request timeout'));
});
req.end();
});
}
// Test results storage
const testResults = {
sast: {},
dast: {},
sca: {},
iast: {}
};
// 1. SAST Testing
async function testSAST() {
console.log('π 1. SAST (Static Application Security Testing) ν
μ€νΈ...\n');
try {
console.log('π νλ‘μ νΈ νμΌ μ€μΊ μ€...');
// Check for common vulnerabilities patterns in code
const vulnerableFiles = [
'test-vulnerable-server.js'
];
let foundVulns = 0;
for (const file of vulnerableFiles) {
if (fs.existsSync(file)) {
const content = fs.readFileSync(file, 'utf8');
// Check for SQL Injection patterns
if (content.includes('SELECT') && content.includes('${')) {
console.log(` β
SQL Injection pattern detected in ${file}`);
foundVulns++;
}
// Check for XSS patterns
if (content.includes('innerHTML') || content.includes('<script>')) {
console.log(` β
XSS pattern detected in ${file}`);
foundVulns++;
}
// Check for Command Injection
if (content.includes('exec') || content.includes('spawn')) {
console.log(` β
Command Injection pattern detected in ${file}`);
foundVulns++;
}
// Check for Path Traversal
if (content.includes('../') || content.includes('readFile')) {
console.log(` β
Path Traversal pattern detected in ${file}`);
foundVulns++;
}
}
}
testResults.sast = {
vulnerabilities_found: foundVulns,
files_scanned: vulnerableFiles.length,
status: 'success'
};
console.log(`\nπ SAST κ²°κ³Ό: ${foundVulns}κ°μ μ·¨μ½μ ν¨ν΄ λ°κ²¬\n`);
} catch (error) {
console.log(`β SAST ν
μ€νΈ μ€λ₯: ${error.message}\n`);
testResults.sast.error = error.message;
}
}
// 2. SCA Testing
async function testSCA() {
console.log('π¦ 2. SCA (Software Composition Analysis) ν
μ€νΈ...\n');
try {
console.log('π μμ‘΄μ± μ·¨μ½μ μ€μΊ μ€...');
if (fs.existsSync('package.json')) {
const result = await runCommand('npm', ['audit', '--json'], { silent: true });
try {
const auditData = JSON.parse(result.stdout);
const vulnCount = auditData.metadata?.vulnerabilities || {};
testResults.sca = {
total: vulnCount.total || 0,
critical: vulnCount.critical || 0,
high: vulnCount.high || 0,
moderate: vulnCount.moderate || 0,
low: vulnCount.low || 0,
status: 'success'
};
console.log(` β
Total vulnerabilities: ${vulnCount.total || 0}`);
console.log(` - Critical: ${vulnCount.critical || 0}`);
console.log(` - High: ${vulnCount.high || 0}`);
console.log(` - Moderate: ${vulnCount.moderate || 0}`);
console.log(` - Low: ${vulnCount.low || 0}`);
} catch (parseError) {
console.log(' β οΈ No vulnerabilities found or npm audit format changed');
testResults.sca = { total: 0, status: 'success' };
}
} else {
console.log(' β οΈ package.json not found');
testResults.sca = { error: 'package.json not found' };
}
} catch (error) {
console.log(`β SCA ν
μ€νΈ μ€λ₯: ${error.message}`);
testResults.sca.error = error.message;
}
console.log('');
}
// 3. DAST Testing
async function testDAST() {
console.log('π 3. DAST (Dynamic Application Security Testing) ν
μ€νΈ...\n');
try {
// Verificar si el servidor vulnerable estΓ‘ corriendo
console.log('π Verificando servidor vulnerable...');
try {
const response = await fetch('http://localhost:3001/');
console.log('β
Servidor vulnerable estΓ‘ corriendo\n');
} catch (error) {
console.log('β Servidor vulnerable no estΓ‘ corriendo');
console.log('π‘ Inicia el servidor con: node test-vulnerable-server.js\n');
testResults.dast.error = 'Server not running';
return;
}
// Pruebas manuales de vulnerabilidades
console.log('π Probando vulnerabilidades manualmente...\n');
const vulnerabilityTests = [
{
name: 'SQL Injection',
url: 'http://localhost:3001/user/1\' OR \'1\'=\'1',
checkPatterns: ['SELECT', 'SQL', 'vulnerability']
},
{
name: 'XSS (Reflected)',
url: 'http://localhost:3001/search?q=<script>alert(1)</script>',
checkPatterns: ['<script>', 'alert', 'XSS']
},
{
name: 'Path Traversal',
url: 'http://localhost:3001/file?name=../../etc/passwd',
checkPatterns: ['../../', 'path', 'vulnerability']
},
{
name: 'Command Injection',
url: 'http://localhost:3001/ping?host=localhost;whoami',
checkPatterns: ['ping', 'command', 'vulnerability']
},
{
name: 'IDOR',
url: 'http://localhost:3001/document/999',
checkPatterns: ['document', 'IDOR', 'vulnerability']
},
{
name: 'Information Disclosure',
url: 'http://localhost:3001/debug',
checkPatterns: ['system_info', 'env_vars', 'vulnerability']
},
{
name: 'Authorization Bypass',
url: 'http://localhost:3001/admin/delete-users',
checkPatterns: ['admin', 'authorization', 'vulnerability']
},
{
name: 'Code Injection',
url: 'http://localhost:3001/eval?code=console.log(1)',
checkPatterns: ['code', 'eval', 'vulnerability']
}
];
let detectedVulnerabilities = 0;
for (const test of vulnerabilityTests) {
try {
const response = await fetch(test.url);
const text = await response.text();
// Verificar si la respuesta contiene indicadores de vulnerabilidad
const isVulnerable = test.checkPatterns.some(pattern =>
text.toLowerCase().includes(pattern.toLowerCase())
);
if (isVulnerable) {
console.log(` β
${test.name}: DETECTADO`);
detectedVulnerabilities++;
} else {
console.log(` β ${test.name}: No detectado`);
}
testResults.dast[test.name] = {
status: isVulnerable ? 'vulnerable' : 'secure',
url: test.url,
detected: isVulnerable
};
} catch (error) {
console.log(` β οΈ ${test.name}: Error al probar - ${error.message}`);
testResults.dast[test.name] = {
status: 'error',
error: error.message
};
}
}
testResults.dast.summary = {
total_tests: vulnerabilityTests.length,
detected: detectedVulnerabilities,
detection_rate: `${(detectedVulnerabilities / vulnerabilityTests.length * 100).toFixed(1)}%`
};
console.log(`\nπ Resumen DAST: ${detectedVulnerabilities}/${vulnerabilityTests.length} vulnerabilidades detectadas (${testResults.dast.summary.detection_rate})\n`);
} catch (error) {
console.log(`β DAST ν
μ€νΈ μ€λ₯: ${error.message}\n`);
testResults.dast.error = error.message;
}
}
// 4. IAST Testing
async function testIAST() {
console.log('π 4. IAST (Interactive Application Security Testing) ν
μ€νΈ...\n');
let serverProcess;
try {
// Ensure the vulnerable server is running
try {
await fetch('http://localhost:3001/');
console.log(' β
Servidor vulnerable ya estΓ‘ corriendo.');
} catch (error) {
console.log(' π Iniciando servidor vulnerable para prueba IAST...');
serverProcess = spawn('node', ['test-vulnerable-server.js'], { detached: true });
await new Promise(resolve => setTimeout(resolve, 3000)); // Wait for server to start
}
console.log(' π Ejecutando anΓ‘lisis IAST a travΓ©s de la herramienta MCP...');
// Execute the IAST scan via the CLI tool
const result = await runCommand('gemini', [
'run_iast_scan',
'--application_id',
'3001'
], { silent: true });
if (result.code !== 0) {
throw new Error(`IAST scan failed:\n${result.stderr}`);
}
// The tool output is now in stdout, parse it
const iastOutput = JSON.parse(result.stdout);
const iastResult = JSON.parse(iastOutput.content[0].text);
if (!iastResult.success && iastResult.error) {
throw new Error(iastResult.message);
}
const vulnerabilities = iastResult.vulnerabilities || [];
testResults.iast = {
vulnerabilities: vulnerabilities,
total: vulnerabilities.length,
critical: vulnerabilities.filter(v => v.severity === 'critical').length,
high: vulnerabilities.filter(v => v.severity === 'high').length,
medium: vulnerabilities.filter(v => v.severity === 'medium').length,
status: 'success'
};
console.log(` β
AnΓ‘lisis IAST completado. Se encontraron ${vulnerabilities.length} vulnerabilidades.\n`);
vulnerabilities.forEach(vuln => {
console.log(` - [${vuln.severity.toUpperCase()}] ${vuln.title}`);
console.log(` en ${vuln.method} ${vuln.url}`);
});
console.log('');
} catch (error) {
console.log(`β Error en prueba IAST: ${error.message}\n`);
testResults.iast.error = error.message;
testResults.iast.status = 'error';
} finally {
if (serverProcess) {
console.log(' π Deteniendo servidor vulnerable...');
process.kill(-serverProcess.pid);
}
}
}
// Main test execution
async function runAllTests() {
console.log('βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ');
console.log('π‘οΈ DevSecOps MCP - Security Testing Suite');
console.log('βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n');
const startTime = Date.now();
await testSAST();
await testSCA();
await testDAST();
await testIAST();
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
console.log('βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ');
console.log('π RESUMEN FINAL DE PRUEBAS');
console.log('βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n');
console.log('SAST:');
console.log(` - Vulnerabilidades encontradas: ${testResults.sast.vulnerabilities_found || 0}`);
console.log(` - Estado: ${testResults.sast.status || 'error'}\n`);
console.log('SCA:');
console.log(` - Dependencias vulnerables: ${testResults.sca.total || 0}`);
console.log(` - Estado: ${testResults.sca.status || 'error'}\n`);
console.log('DAST:');
console.log(` - Vulnerabilidades detectadas: ${testResults.dast.summary?.detected || 0}/${testResults.dast.summary?.total_tests || 0}`);
console.log(` - Tasa de detecciΓ³n: ${testResults.dast.summary?.detection_rate || 'N/A'}`);
console.log(` - Estado: ${testResults.dast.error ? 'error' : 'success'}\n`);
console.log('IAST:');
console.log(` - Vulnerabilidades detectadas: ${testResults.iast.total || 0}`);
console.log(` - Critical: ${testResults.iast.critical || 0}, High: ${testResults.iast.high || 0}, Medium: ${testResults.iast.medium || 0}`);
console.log(` - Cobertura: ${testResults.iast.coverage || 'N/A'}`);
console.log(` - Estado: ${testResults.iast.status || 'error'}\n`);
console.log('βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ');
console.log(`β±οΈ Tiempo total de ejecuciΓ³n: ${duration} segundos`);
console.log('βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n');
// Save results to file
const resultsPath = path.join(__dirname, 'test-results.json');
fs.writeFileSync(resultsPath, JSON.stringify(testResults, null, 2));
console.log(`πΎ Resultados guardados en: ${resultsPath}\n`);
}
// Run tests
runAllTests().catch(error => {
console.error('β Error fatal en la ejecuciΓ³n de pruebas:', error);
process.exit(1);
});