bugnitor-security-scanner
Version:
AI-Era Security Scanner: Intelligent automated security review agent specializing in AI-generated vulnerability patterns
315 lines (314 loc) • 11.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.EnhancedSecretDetector = exports.enhancedSecretPatterns = void 0;
exports.enhancedSecretPatterns = [
{
id: 'database-url',
name: 'Database Connection String',
patterns: [
/(postgresql|mysql|mongodb|redis|sqlite):\/\/[^\s"'`;<>{}|\[\]\\^]+/gi,
/(postgres|mysql|mongo|redis):\/\/[^\s"'`;<>{}|\[\]\\^]+/gi,
/(?:database_url|db_url|connection_string)\s*[:=]\s*["']([^"']+)["']/gi
],
contextPatterns: [
/(?:database|db|connection|url)/gi
],
excludePatterns: [
/localhost|127\.0\.0\.1|example\.com|test\.db|mock/gi
],
confidence: 0.9,
description: 'Database connection string with embedded credentials',
severity: 'critical',
cwe: 'CWE-798',
owasp: 'A02:2021 – Cryptographic Failures',
examples: [
'postgresql://username:password@localhost:5432/database',
'mongodb://user:pass@mongo.example.com:27017/mydb'
],
remediation: {
description: 'Use environment variables or secure configuration management',
effort: 'low',
codeExample: `// Instead of:
const dbUrl = "postgresql://user:pass@localhost:5432/db";
// Use:
const dbUrl = process.env.DATABASE_URL;`
}
},
{
id: 'aws-credentials',
name: 'AWS Credentials',
patterns: [
/AKIA[0-9A-Z]{16}/g,
/(?:aws[_-]?access[_-]?key[_-]?id)\s*[:=]\s*["']?([A-Z0-9]{20})["']?/gi,
/(?:aws[_-]?secret[_-]?access[_-]?key)\s*[:=]\s*["']?([A-Za-z0-9/+=]{40})["']?/gi
],
contextPatterns: [
/aws|amazon|s3|ec2|lambda/gi
],
confidence: 0.95,
description: 'AWS access credentials detected',
severity: 'critical',
cwe: 'CWE-798',
owasp: 'A02:2021 – Cryptographic Failures',
examples: [
'AKIAIOSFODNN7EXAMPLE',
'aws_access_key_id = AKIAIOSFODNN7EXAMPLE'
],
remediation: {
description: 'Use AWS IAM roles or environment variables',
effort: 'medium',
codeExample: `// Use AWS SDK with IAM roles or environment variables
const aws = require('aws-sdk');
aws.config.update({ region: 'us-east-1' }); // Credentials from environment`
}
},
{
id: 'jwt-secret',
name: 'JWT Secret Key',
patterns: [
/(?:jwt[_-]?secret|token[_-]?secret|signing[_-]?key)\s*[:=]\s*["']([^"']{8,})["']/gi,
/jwt\.sign\s*\([^,]+,\s*["']([^"']{8,})["']/gi
],
contextPatterns: [
/jwt|jsonwebtoken|token|signing/gi
],
confidence: 0.85,
description: 'JWT signing secret detected',
severity: 'high',
cwe: 'CWE-798',
owasp: 'A02:2021 – Cryptographic Failures',
examples: [
'jwt_secret = "my-super-secret-key"',
'jwt.sign(payload, "hardcoded-secret")'
],
remediation: {
description: 'Use environment variables for JWT secrets',
effort: 'low',
codeExample: `// Use environment variable
const token = jwt.sign(payload, process.env.JWT_SECRET);`
}
},
{
id: 'api-keys',
name: 'API Keys',
patterns: [
/(?:api[_-]?key|apikey)\s*[:=]\s*["']([A-Za-z0-9_-]{16,})["']/gi,
/(?:secret[_-]?key|secretkey)\s*[:=]\s*["']([A-Za-z0-9_-]{16,})["']/gi,
/(?:access[_-]?token|accesstoken)\s*[:=]\s*["']([A-Za-z0-9_.-]{16,})["']/gi
],
contextPatterns: [
/api|key|token|secret/gi
],
excludePatterns: [
/test|example|demo|placeholder|your-api-key|xxx/gi
],
confidence: 0.8,
description: 'Generic API key or secret detected',
severity: 'high',
cwe: 'CWE-798',
owasp: 'A02:2021 – Cryptographic Failures',
examples: [
'api_key = "sk_live_abcdef123456"',
'const apiKey = "your-secret-api-key-here";'
],
remediation: {
description: 'Store API keys in environment variables or secure vault',
effort: 'low',
codeExample: `// Use environment variable
const apiKey = process.env.API_KEY;`
}
},
{
id: 'private-keys',
name: 'Private Key',
patterns: [
/-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----[\s\S]*?-----END\s+(?:RSA\s+)?PRIVATE\s+KEY-----/gi,
/-----BEGIN\s+OPENSSH\s+PRIVATE\s+KEY-----[\s\S]*?-----END\s+OPENSSH\s+PRIVATE\s+KEY-----/gi
],
confidence: 0.95,
description: 'Private key detected in source code',
severity: 'critical',
cwe: 'CWE-798',
owasp: 'A02:2021 – Cryptographic Failures',
examples: [
'-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAK...'
],
remediation: {
description: 'Never store private keys in source code. Use secure key management.',
effort: 'high',
codeExample: `// Load from secure file system or key management service
const privateKey = fs.readFileSync(process.env.PRIVATE_KEY_PATH);`
}
},
{
id: 'password-fields',
name: 'Hardcoded Password',
patterns: [
/(?:password|pwd|pass)\s*[:=]\s*["']([^"']{4,})["']/gi,
/(?:user|username)\s*[:=]\s*["'][^"']+["']\s*[,;]\s*(?:password|pwd|pass)\s*[:=]\s*["']([^"']{4,})["']/gi
],
contextPatterns: [
/password|credentials|auth|login/gi
],
excludePatterns: [
/\*+|password|123|test|demo|example/gi
],
confidence: 0.7,
description: 'Hardcoded password detected',
severity: 'high',
cwe: 'CWE-798',
owasp: 'A07:2021 – Identification and Authentication Failures',
examples: [
'password: "admin123"',
'const pwd = "mySecretPassword";'
],
remediation: {
description: 'Use environment variables or secure credential storage',
effort: 'low',
codeExample: `// Use environment variable
const password = process.env.DB_PASSWORD;`
}
},
{
id: 'github-tokens',
name: 'GitHub Token',
patterns: [
/ghp_[A-Za-z0-9]{36}/g,
/gho_[A-Za-z0-9]{36}/g,
/ghu_[A-Za-z0-9]{36}/g,
/ghs_[A-Za-z0-9]{36}/g,
/ghr_[A-Za-z0-9]{36}/g
],
confidence: 0.95,
description: 'GitHub personal access token detected',
severity: 'critical',
cwe: 'CWE-798',
owasp: 'A02:2021 – Cryptographic Failures',
examples: [
'ghp_1234567890abcdef1234567890abcdef123456'
],
remediation: {
description: 'Revoke token immediately and use GitHub secrets in workflows',
effort: 'low',
codeExample: `# In GitHub Actions
env:
GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}`
}
},
{
id: 'slack-tokens',
name: 'Slack Token',
patterns: [
/xox[baprs]-[0-9a-zA-Z]{10,48}/g,
/(?:slack[_-]?token|slack[_-]?webhook)\s*[:=]\s*["']([^"']+)["']/gi
],
confidence: 0.9,
description: 'Slack API token or webhook URL detected',
severity: 'high',
cwe: 'CWE-798',
owasp: 'A02:2021 – Cryptographic Failures',
examples: [
'xoxb-1234567890-1234567890-abcdef123456',
'slack_token = "xoxp-1234567890-abcdef"'
],
remediation: {
description: 'Use environment variables for Slack tokens',
effort: 'low'
}
}
];
class EnhancedSecretDetector {
detectSecrets(content, filename) {
const results = [];
for (const pattern of exports.enhancedSecretPatterns) {
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);
// Skip low confidence matches
if (confidence < 0.4)
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 = 100) {
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('.env') || filename.includes('config')) {
confidence *= 1.2;
}
if (filename.includes('test') || filename.includes('spec') || filename.includes('mock')) {
confidence *= 0.6;
}
if (filename.includes('example') || filename.includes('demo') || filename.includes('sample')) {
confidence *= 0.5;
}
// Context pattern matching
if (pattern.contextPatterns) {
let hasContext = false;
for (const contextPattern of pattern.contextPatterns) {
if (contextPattern.test(context)) {
hasContext = true;
confidence *= 1.1;
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.3;
break;
}
}
}
// Length-based confidence for generic patterns
const matchLength = match[0].length;
if (matchLength < 8) {
confidence *= 0.7;
}
else if (matchLength > 32) {
confidence *= 1.1;
}
// Check for common placeholder patterns
const placeholderPatterns = [
/^[x]+$/i,
/^[0]+$/i,
/^(test|example|placeholder|your[-_])/i,
/^[a-z]{1,3}$/i
];
for (const placeholderPattern of placeholderPatterns) {
if (placeholderPattern.test(match[0])) {
confidence *= 0.2;
break;
}
}
return Math.min(1.0, Math.max(0.0, confidence));
}
}
exports.EnhancedSecretDetector = EnhancedSecretDetector;
//# sourceMappingURL=enhanced-secrets.js.map