bugnitor-security-scanner
Version:
AI-Era Security Scanner: Intelligent automated security review agent specializing in AI-generated vulnerability patterns
412 lines (406 loc) • 17.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AIVulnerabilityDetector = exports.aiVulnerabilityPatterns = void 0;
exports.aiVulnerabilityPatterns = [
{
id: 'missing-auth-check-delete',
name: 'Missing Authorization Check on DELETE Operations',
category: 'Broken Access Control',
description: 'DELETE operations without proper authorization verification',
aiContext: 'AI generates database deletion logic but lacks application context about user roles and permissions',
patterns: [
/(?:DELETE\s+FROM|\.delete\s*\(|\.remove\s*\(|\.destroy\s*\()(?![\s\S]{0,200}(?:auth|permission|role|isAdmin|canDelete|checkAuth|authorize|verify|middleware))/gi,
/router\.(delete|del)\s*\([^)]*\)(?![\s\S]{0,200}(?:auth|permission|middleware|isAdmin|canDelete))/gi,
/app\.delete\s*\([^)]*\)(?![\s\S]{0,200}(?:auth|permission|middleware|isAdmin|canDelete))/gi,
/prisma\.\w+\.delete\s*\((?![\s\S]{0,100}(?:where.*userId|where.*ownerId|auth|permission))/gi
],
contextPatterns: [
/delete|remove|destroy/gi
],
excludePatterns: [
/test|spec|example|demo/gi
],
severity: 'critical',
confidence: 0.9,
fileTypes: ['js', 'ts', 'jsx', 'tsx', 'py', 'php', 'java'],
cwe: 'CWE-862',
owasp: 'A01:2021 – Broken Access Control',
impact: 'Unauthorized deletion of resources, data loss, privilege escalation',
remediation: {
description: 'Add proper authorization checks before DELETE operations',
effort: 'medium',
codeExample: `// Before (AI-generated):
await prisma.resource.delete({ where: { id } });
// After (secure):
if (!user.isAdmin && resource.ownerId !== user.id) {
throw new Error('Unauthorized');
}
await prisma.resource.delete({ where: { id } });`
}
},
{
id: 'missing-auth-check-admin',
name: 'Missing Authorization Check on Admin Routes',
category: 'Broken Access Control',
description: 'Admin endpoints without proper role verification',
aiContext: 'AI creates admin functionality but doesnt implement role checking logic',
patterns: [
/\/admin\/[^'"\s]*['"]?\s*,?\s*(?:async\s+)?\([^)]*\)\s*(?:=>|{)(?![\s\S]{0,300}(?:isAdmin|role.*admin|checkAdmin|requireAdmin|adminOnly))/gi,
/app\.(get|post|put|delete)\s*\(\s*['"][^'"]*admin[^'"]*['"](?![\s\S]{0,200}(?:isAdmin|role.*admin|middleware.*admin))/gi,
/router\.(get|post|put|delete)\s*\(\s*['"][^'"]*admin[^'"]*['"](?![\s\S]{0,200}(?:isAdmin|role.*admin|middleware.*admin))/gi
],
severity: 'critical',
confidence: 0.85,
fileTypes: ['js', 'ts', 'jsx', 'tsx', 'py', 'php'],
cwe: 'CWE-862',
owasp: 'A01:2021 – Broken Access Control',
impact: 'Complete administrative access bypass, system compromise',
remediation: {
description: 'Implement role-based access control for admin routes',
effort: 'medium',
codeExample: `// Add authorization middleware:
app.post('/admin/users', requireAdmin, async (req, res) => {
// Admin logic here
});`
}
},
{
id: 'direct-db-input',
name: 'Direct Database Query with User Input',
category: 'Injection Flaws',
description: 'User input directly concatenated into database queries',
aiContext: 'AI generates functional database queries but often uses string concatenation instead of parameterized queries',
patterns: [
/(?:query|execute|prepare)\s*\(\s*["`'][^"`']*\$\{[^}]*\}[^"`']*["`']/gi,
/(?:query|execute|prepare)\s*\(\s*["`'][^"`']*\+[^"`']*["`']/gi,
/(?:SELECT|INSERT|UPDATE|DELETE)[^;]*\+\s*(?:req\.|request\.|params\.|body\.|query\.)/gi,
/(?:SELECT|INSERT|UPDATE|DELETE)[^;]*\$\{[^}]*(?:req\.|request\.|params\.|body\.|query\.)/gi,
/db\.query\s*\([^)]*\+[^)]*req\./gi
],
contextPatterns: [
/query|sql|database|db/gi
],
severity: 'critical',
confidence: 0.95,
fileTypes: ['js', 'ts', 'py', 'php', 'java', 'cs'],
cwe: 'CWE-89',
owasp: 'A03:2021 – Injection',
impact: 'Complete database compromise, data theft, data manipulation',
remediation: {
description: 'Use parameterized queries or prepared statements',
effort: 'medium',
codeExample: `// Instead of:
const query = \`SELECT * FROM users WHERE id = \${userId}\`;
// Use:
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [userId]);`
}
},
{
id: 'unsanitized-csv-processing',
name: 'Unsanitized CSV Processing',
category: 'Injection Flaws',
description: 'CSV data processed without validation, leading to CSV injection',
aiContext: 'AI generates CSV parsing logic focusing on functionality, not security validation',
patterns: [
/parseCSV\s*\([^)]*\)(?![\s\S]{0,200}(?:sanitize|validate|escape|clean))/gi,
/csv\.parse\s*\([^)]*\)(?![\s\S]{0,200}(?:sanitize|validate|escape))/gi,
/\.split\s*\(\s*['"],['"]\s*\)(?![\s\S]{0,100}(?:sanitize|validate|escape))/gi,
/Papa\.parse\s*\([^)]*\)(?![\s\S]{0,200}(?:sanitize|validate|transform))/gi
],
contextPatterns: [
/csv|comma|separated|parse/gi
],
severity: 'high',
confidence: 0.8,
fileTypes: ['js', 'ts', 'py', 'php'],
cwe: 'CWE-1236',
owasp: 'A03:2021 – Injection',
impact: 'CSV injection, formula injection in spreadsheet applications',
remediation: {
description: 'Validate and sanitize CSV data before processing',
effort: 'low',
codeExample: `// Sanitize CSV cells to prevent formula injection
const sanitizeCSVCell = (cell) => {
if (typeof cell === 'string' && /^[=+@-]/.test(cell)) {
return "'" + cell; // Prefix with single quote
}
return cell;
};`
}
},
{
id: 'hardcoded-secrets-examples',
name: 'Hardcoded Secrets from AI Examples',
category: 'Sensitive Data Exposure',
description: 'API keys, tokens, or secrets hardcoded from AI-generated examples',
aiContext: 'Developers include example secrets in AI prompts, and AI incorporates them into generated code',
patterns: [
/(?:api[_-]?key|apikey|secret|token|password)\s*[:=]\s*["`'](?:sk_|pk_|test_|demo_|example_|your_|my_|sample_)[^"`']+["`']/gi,
/(?:jwt[_-]?secret|signing[_-]?key)\s*[:=]\s*["`'](?:your|my|demo|test|example|secret)[^"`']*["`']/gi,
/(?:database[_-]?url|db[_-]?url)\s*[:=]\s*["`'](?:mongodb|postgresql|mysql).*(?:localhost|example\.com|test\.db)[^"`']*["`']/gi,
/process\.env\.\w+\s*\|\|\s*["`'][^"`']+["`']/gi // Fallback values that might be secrets
],
contextPatterns: [
/key|secret|token|password|api/gi
],
excludePatterns: [
/process\.env\.\w+/gi // Exclude when properly using env vars
],
severity: 'critical',
confidence: 0.9,
fileTypes: ['js', 'ts', 'py', 'php', 'java', 'cs', 'go'],
cwe: 'CWE-798',
owasp: 'A02:2021 – Cryptographic Failures',
impact: 'Complete account compromise, API abuse, unauthorized access',
remediation: {
description: 'Replace hardcoded secrets with environment variables',
effort: 'low',
codeExample: `// Instead of:
const apiKey = "sk_live_example123456";
// Use:
const apiKey = process.env.STRIPE_API_KEY;
if (!apiKey) throw new Error('Missing API key');`
}
},
{
id: 'detailed-error-exposure',
name: 'Detailed Error Information Exposure',
category: 'Sensitive Data Exposure',
description: 'Detailed error messages exposed to users revealing internal information',
aiContext: 'AI generates comprehensive error handling but exposes internal details for debugging',
patterns: [
/console\.error\s*\([^)]*error(?:\.stack|\.message)?[^)]*\)/gi,
/res\.(?:status|send|json)\s*\([^)]*error(?:\.stack|\.message|\.toString\(\))[^)]*\)/gi,
/throw\s+new\s+Error\s*\([^)]*\$\{[^}]*error[^}]*\}/gi,
/console\.log\s*\([^)]*error[^)]*\)/gi,
/logger\.error\s*\([^)]*error\.stack[^)]*\)/gi
],
contextPatterns: [
/error|catch|exception/gi
],
excludePatterns: [
/development|dev|debug/gi
],
severity: 'medium',
confidence: 0.7,
fileTypes: ['js', 'ts', 'py', 'php', 'java'],
cwe: 'CWE-209',
owasp: 'A09:2021 – Security Logging and Monitoring Failures',
impact: 'Information leakage, system reconnaissance for attackers',
remediation: {
description: 'Log detailed errors server-side, return generic messages to users',
effort: 'low',
codeExample: `// Instead of:
catch (error) {
res.status(500).json({ error: error.message });
}
// Use:
catch (error) {
logger.error('Operation failed:', error);
res.status(500).json({ error: 'Internal server error' });
}`
}
},
{
id: 'weak-crypto-ai-suggestion',
name: 'Weak Cryptographic Algorithm from AI',
category: 'Insecure Design',
description: 'Use of weak cryptographic algorithms suggested by AI',
aiContext: 'AI may suggest older cryptographic methods from its training data without considering current security standards',
patterns: [
/crypto\.createHash\s*\(\s*["`'](?:md5|sha1)["`']\s*\)/gi,
/hashlib\.(?:md5|sha1)\s*\(\s*\)/gi,
/MessageDigest\.getInstance\s*\(\s*["`'](?:MD5|SHA-1|SHA1)["`']\s*\)/gi,
/hash\s*\(\s*["`'](?:md5|sha1)["`']/gi,
/\.digest\s*\(\s*["`'](?:md5|sha1)["`']\s*\)/gi
],
contextPatterns: [
/hash|crypto|digest|password/gi
],
excludePatterns: [
/etag|checksum|legacy|compatibility/gi // Exclude non-security uses
],
severity: 'medium',
confidence: 0.8,
fileTypes: ['js', 'ts', 'py', 'java', 'cs', 'go'],
cwe: 'CWE-327',
owasp: 'A02:2021 – Cryptographic Failures',
impact: 'Cryptographic vulnerabilities, hash collisions, data compromise',
remediation: {
description: 'Use strong, modern cryptographic algorithms',
effort: 'low',
codeExample: `// Instead of:
crypto.createHash('md5').update(password).digest('hex');
// Use:
bcrypt.hash(password, 12); // For passwords
// or
crypto.createHash('sha256').update(data).digest('hex'); // For data`
}
},
{
id: 'unvalidated-redirect',
name: 'Unvalidated Redirect from AI',
category: 'Broken Access Control',
description: 'Redirect functionality without URL validation',
aiContext: 'AI generates redirect logic but doesnt include URL validation to prevent open redirects',
patterns: [
/res\.redirect\s*\([^)]*req\.(?:query|body|params)\.[^)]*\)/gi,
/response\.redirect\s*\([^)]*request\.[^)]*\)/gi,
/window\.location\s*=\s*[^;]*req\./gi,
/location\.href\s*=\s*[^;]*params\./gi
],
contextPatterns: [
/redirect|location|href/gi
],
severity: 'medium',
confidence: 0.8,
fileTypes: ['js', 'ts', 'py', 'php'],
cwe: 'CWE-601',
owasp: 'A01:2021 – Broken Access Control',
impact: 'Phishing attacks, malicious redirects',
remediation: {
description: 'Validate redirect URLs against a whitelist',
effort: 'low',
codeExample: `// Validate redirect URL
const allowedDomains = ['example.com', 'app.example.com'];
const redirectUrl = new URL(req.query.redirect);
if (!allowedDomains.includes(redirectUrl.hostname)) {
throw new Error('Invalid redirect URL');
}`
}
},
{
id: 'missing-input-validation',
name: 'Missing Input Validation on AI-Generated Endpoints',
category: 'Injection Flaws',
description: 'API endpoints without proper input validation',
aiContext: 'AI focuses on functional implementation but often skips input validation and sanitization',
patterns: [
/app\.(post|put|patch)\s*\([^)]*\)\s*,?\s*(?:async\s+)?\([^)]*\)\s*(?:=>|{)(?![\s\S]{0,300}(?:validate|sanitize|check|joi\.|yup\.|zod\.))/gi,
/router\.(post|put|patch)\s*\([^)]*\)\s*,?\s*(?:async\s+)?\([^)]*\)\s*(?:=>|{)(?![\s\S]{0,300}(?:validate|sanitize|check))/gi,
/req\.body(?![\s\S]{0,100}(?:validate|sanitize|check|trim|escape))/gi,
/request\.json\(\)(?![\s\S]{0,100}(?:validate|sanitize|parse|schema))/gi
],
contextPatterns: [
/req\.body|request\.json|form|input/gi
],
excludePatterns: [
/get|delete/gi // Exclude GET/DELETE methods
],
severity: 'high',
confidence: 0.75,
fileTypes: ['js', 'ts', 'py', 'php'],
cwe: 'CWE-20',
owasp: 'A03:2021 – Injection',
impact: 'Data corruption, injection attacks, application errors',
remediation: {
description: 'Add comprehensive input validation',
effort: 'medium',
codeExample: `// Add validation middleware
const { body, validationResult } = require('express-validator');
app.post('/users', [
body('email').isEmail().normalizeEmail(),
body('password').isLength({ min: 8 }),
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Process validated input
});`
}
}
];
class AIVulnerabilityDetector {
detectAIVulnerabilities(content, filename) {
const fileExtension = filename.split('.').pop()?.toLowerCase();
if (!fileExtension)
return [];
const results = [];
for (const pattern of exports.aiVulnerabilityPatterns) {
if (!pattern.fileTypes.includes(fileExtension))
continue;
const matches = [];
for (const regex of pattern.patterns) {
let match;
while ((match = regex.exec(content)) !== null) {
const context = this.getMatchContext(content, match.index || 0);
const confidence = this.calculateConfidence(pattern, match, context, filename);
// Higher threshold for AI-specific patterns
if (confidence < 0.6)
continue;
matches.push({
match,
confidence,
context
});
if (!regex.global)
break;
}
regex.lastIndex = 0;
}
if (matches.length > 0) {
results.push({ pattern, matches });
}
}
return results;
}
getMatchContext(content, index, contextSize = 200) {
const start = Math.max(0, index - contextSize);
const end = Math.min(content.length, index + contextSize);
return content.substring(start, end);
}
calculateConfidence(pattern, match, context, filename) {
let confidence = pattern.confidence;
// File type adjustments
if (filename.includes('test') || filename.includes('spec') || filename.includes('mock')) {
confidence *= 0.5;
}
if (filename.includes('example') || filename.includes('demo') || filename.includes('sample')) {
confidence *= 0.4;
}
// Route/API file boost
if (filename.includes('route') || filename.includes('api') || filename.includes('endpoint')) {
confidence *= 1.2;
}
// Context pattern matching
if (pattern.contextPatterns) {
let hasContext = false;
for (const contextPattern of pattern.contextPatterns) {
if (contextPattern.test(context)) {
hasContext = true;
confidence *= 1.15;
break;
}
}
if (!hasContext) {
confidence *= 0.8;
}
}
// Exclude pattern matching
if (pattern.excludePatterns) {
for (const excludePattern of pattern.excludePatterns) {
if (excludePattern.test(match[0]) || excludePattern.test(context)) {
confidence *= 0.4;
break;
}
}
}
// AI-specific indicators
const aiIndicators = [
/\/\/ generated by|auto-generated|ai-generated/gi,
/\/\/ example|\/\/ todo|\/\/ fixme/gi,
/copilot|chatgpt|claude|assistant/gi
];
for (const aiIndicator of aiIndicators) {
if (aiIndicator.test(context)) {
confidence *= 1.3; // Boost confidence for AI-generated code markers
break;
}
}
return Math.min(1.0, Math.max(0.0, confidence));
}
}
exports.AIVulnerabilityDetector = AIVulnerabilityDetector;
//# sourceMappingURL=ai-vulnerability-detector.js.map