/**
* AI-Powered Security Scanner
* Provides intelligent vulnerability detection and automated remediation
*/
import * as fs from "fs/promises";
import * as path from "path";
import { SecurityUtils } from "./SecurityConfig.js";
import { SecurityValidationError } from "./InputValidator.js";
import { LoggerFactory } from "@/utils/logger.js";
export interface SecurityVulnerability {
id: string;
severity: "critical" | "high" | "medium" | "low";
type: string;
description: string;
location: {
file?: string;
line?: number;
column?: number;
context?: string;
};
remediation: {
suggested: string;
automated: boolean;
confidence: number;
};
metadata: {
cweId?: string;
cvssScore?: number;
exploitability: "high" | "medium" | "low";
detected: Date;
};
}
export interface SecurityScanResult {
scanId: string;
timestamp: Date;
duration: number;
vulnerabilities: SecurityVulnerability[];
summary: {
total: number;
critical: number;
high: number;
medium: number;
low: number;
};
remediationAvailable: number;
compliance: {
owasp: boolean;
cwe: boolean;
gdpr: boolean;
};
}
export interface RemediationResult {
vulnerabilityId: string;
success: boolean;
action: string;
details: string;
timestamp: Date;
}
/**
* AI-powered security analysis patterns
*/
const SECURITY_PATTERNS = {
// SQL Injection patterns
sqlInjection: [
/['";\-]|\/\*|\*\/|--/g, // Match quotes, double hyphens, semicolons, and SQL comments
/(union|select|insert|update|delete|drop|create|alter)\s+/gi,
/\b(or|and)\s+['"]?\d+['"]?\s*=\s*['"]?\d+['"]?/gi,
/\b(char|ascii|substring|length|concat)\s*\(/gi,
],
// XSS patterns
xss: [
/<script/gi, // Detect script tag start
/<\/script/gi, // Detect script tag end
/javascript\s*:/gi,
/on\w+\s*=\s*['"][^'"]*['"]?/gi,
/eval\s*\(/gi,
/expression\s*\(/gi,
/<iframe[^>]*>/gi,
],
// Path Traversal
pathTraversal: [/\.\.[\/\\]/g, /[\/\\]\.\.$/g, /%2e%2e/gi, /%252e%252e/gi, /\x2e\x2e/g],
// Command Injection
commandInjection: [/[;&|`$]/g, /\b(rm|cat|ls|ps|kill|sudo|su)\s/gi, /\$\([^)]*\)/g, /`[^`]*`/g],
// Credential Exposure
credentials: [
/password\s*[:=]\s*['"][^'"]{8,}/gi,
/api[_-]?key\s*[:=]\s*['"][^'"]{16,}/gi,
/token\s*[:=]\s*['"][^'"]{20,}/gi,
/secret\s*[:=]\s*['"][^'"]{16,}/gi,
/private[_-]?key/gi,
],
// LDAP Injection
ldapInjection: [/[()&|!]/g, /\*[^*]*\*/g, /\\\d{2}/g],
// NoSQL Injection
nosqlInjection: [/\$where/gi, /\$ne/gi, /\$gt/gi, /\$regex/gi, /\$exists/gi],
// CSRF vulnerabilities
csrf: [/GET\s+.*(?:delete|remove|update|create)/gi, /action\s*=\s*['"][^'"]*(?:delete|admin|config)/gi],
// Information Disclosure
infoDisclosure: [/error\s*[:=]\s*true/gi, /debug\s*[:=]\s*true/gi, /trace\s*[:=]\s*true/gi, /stack\s*trace/gi],
};
/**
* AI Security Scanner with machine learning capabilities
*/
export class AISecurityScanner {
private readonly logger = LoggerFactory.security();
private vulnerabilities: SecurityVulnerability[] = [];
private scanHistory: SecurityScanResult[] = [];
private remediationHistory: RemediationResult[] = [];
/**
* Perform comprehensive security scan
*/
async performScan(
options: {
targets?: string[];
depth?: "shallow" | "deep" | "comprehensive";
includeFileSystem?: boolean;
includeRuntime?: boolean;
} = {},
): Promise<SecurityScanResult> {
const scanId = SecurityUtils.generateSecureToken(16);
const startTime = Date.now();
this.logger.info("Starting AI-powered security scan", { scanId });
try {
this.vulnerabilities = [];
// Perform different types of scans
await this.scanCodebase(options.targets);
if (options.includeRuntime) {
await this.scanRuntimeEnvironment();
}
if (options.includeFileSystem) {
await this.scanFileSystem();
}
await this.scanConfigurations();
await this.scanDependencies();
await this.performAIAnalysis();
const duration = Date.now() - startTime;
const result = this.generateScanResult(scanId, duration);
this.scanHistory.push(result);
this.logger.info("Security scan completed", {
scanId,
vulnerabilities: result.summary.total,
duration,
critical: result.summary.critical,
high: result.summary.high,
medium: result.summary.medium,
low: result.summary.low,
});
return result;
} catch (_error) {
this.logger.error("Security scan failed", { scanId, _error: String(_error) });
throw new SecurityValidationError("Security scan failed", [{ message: String(_error) }]);
}
}
/**
* Scan codebase for vulnerabilities
*/
private async scanCodebase(targets?: string[]): Promise<void> {
const defaultTargets = ["src/", "tests/", "scripts/"];
const scanTargets = targets || defaultTargets;
for (const target of scanTargets) {
await this.scanDirectory(target);
}
}
/**
* Recursively scan directory for security issues
*/
private async scanDirectory(dirPath: string): Promise<void> {
try {
const entries = await fs.readdir(dirPath, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dirPath, entry.name);
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
await this.scanDirectory(fullPath);
} else if (entry.isFile() && this.shouldScanFile(entry.name)) {
await this.scanFile(fullPath);
}
}
} catch (_error) {
// Directory might not exist or be accessible
this.logger.warn("Cannot scan directory", { dirPath, _error: String(_error) });
}
}
/**
* Check if file should be scanned
*/
private shouldScanFile(filename: string): boolean {
const scanExtensions = [".ts", ".js", ".json", ".yml", ".yaml", ".env", ".config"];
const ext = path.extname(filename).toLowerCase();
return scanExtensions.includes(ext) || filename.startsWith(".");
}
/**
* Scan individual file for vulnerabilities
*/
private async scanFile(filePath: string): Promise<void> {
try {
const content = await fs.readFile(filePath, "utf-8");
const lines = content.split("\n");
// Scan for different vulnerability types
this.scanForSQLInjection(filePath, content, lines);
this.scanForXSS(filePath, content, lines);
this.scanForPathTraversal(filePath, content, lines);
this.scanForCommandInjection(filePath, content, lines);
this.scanForCredentialExposure(filePath, content, lines);
this.scanForLDAPInjection(filePath, content, lines);
this.scanForNoSQLInjection(filePath, content, lines);
this.scanForCSRF(filePath, content, lines);
this.scanForInfoDisclosure(filePath, content, lines);
this.scanForInsecureConfiguration(filePath, content, lines);
} catch (_error) {
this.logger.warn("Cannot scan file", { filePath, _error: String(_error) });
}
}
/**
* Scan for SQL injection vulnerabilities
*/
private scanForSQLInjection(filePath: string, content: string, lines: string[]): void {
SECURITY_PATTERNS.sqlInjection.forEach((pattern, index) => {
const matches = Array.from(content.matchAll(pattern));
matches.forEach((match) => {
const lineNumber = this.getLineNumber(content, match.index || 0);
this.addVulnerability({
id: `sql-${Date.now()}-${index}`,
severity: "high",
type: "SQL Injection",
description: `Potential SQL injection vulnerability detected: ${match[0]}`,
location: {
file: filePath,
line: lineNumber,
context: lines[lineNumber - 1]?.trim(),
},
remediation: {
suggested: "Use parameterized queries or prepared statements",
automated: true,
confidence: 0.8,
},
metadata: {
cweId: "CWE-89",
cvssScore: 8.1,
exploitability: "high",
detected: new Date(),
},
});
});
});
}
/**
* Scan for XSS vulnerabilities
*/
private scanForXSS(filePath: string, content: string, lines: string[]): void {
SECURITY_PATTERNS.xss.forEach((pattern, index) => {
const matches = Array.from(content.matchAll(pattern));
matches.forEach((match) => {
const lineNumber = this.getLineNumber(content, match.index || 0);
this.addVulnerability({
id: `xss-${Date.now()}-${index}`,
severity: "high",
type: "Cross-Site Scripting (XSS)",
description: `Potential XSS vulnerability detected: ${match[0]}`,
location: {
file: filePath,
line: lineNumber,
context: lines[lineNumber - 1]?.trim(),
},
remediation: {
suggested: "Sanitize user input and encode output",
automated: true,
confidence: 0.7,
},
metadata: {
cweId: "CWE-79",
cvssScore: 7.5,
exploitability: "medium",
detected: new Date(),
},
});
});
});
}
/**
* Scan for path traversal vulnerabilities
*/
private scanForPathTraversal(filePath: string, content: string, lines: string[]): void {
SECURITY_PATTERNS.pathTraversal.forEach((pattern, index) => {
const matches = Array.from(content.matchAll(pattern));
matches.forEach((match) => {
const lineNumber = this.getLineNumber(content, match.index || 0);
this.addVulnerability({
id: `path-${Date.now()}-${index}`,
severity: "medium",
type: "Path Traversal",
description: `Potential path traversal vulnerability detected: ${match[0]}`,
location: {
file: filePath,
line: lineNumber,
context: lines[lineNumber - 1]?.trim(),
},
remediation: {
suggested: "Validate and sanitize file paths",
automated: true,
confidence: 0.9,
},
metadata: {
cweId: "CWE-22",
cvssScore: 6.5,
exploitability: "medium",
detected: new Date(),
},
});
});
});
}
/**
* Scan for command injection vulnerabilities
*/
private scanForCommandInjection(filePath: string, content: string, lines: string[]): void {
SECURITY_PATTERNS.commandInjection.forEach((pattern, index) => {
const matches = Array.from(content.matchAll(pattern));
matches.forEach((match) => {
const lineNumber = this.getLineNumber(content, match.index || 0);
this.addVulnerability({
id: `cmd-${Date.now()}-${index}`,
severity: "critical",
type: "Command Injection",
description: `Potential command injection vulnerability detected: ${match[0]}`,
location: {
file: filePath,
line: lineNumber,
context: lines[lineNumber - 1]?.trim(),
},
remediation: {
suggested: "Use safe APIs and validate input",
automated: false,
confidence: 0.6,
},
metadata: {
cweId: "CWE-78",
cvssScore: 9.0,
exploitability: "high",
detected: new Date(),
},
});
});
});
}
/**
* Scan for credential exposure
*/
private scanForCredentialExposure(filePath: string, content: string, lines: string[]): void {
SECURITY_PATTERNS.credentials.forEach((pattern, index) => {
const matches = Array.from(content.matchAll(pattern));
matches.forEach((match) => {
const lineNumber = this.getLineNumber(content, match.index || 0);
this.addVulnerability({
id: `cred-${Date.now()}-${index}`,
severity: "critical",
type: "Credential Exposure",
description: `Potential hardcoded credential detected`,
location: {
file: filePath,
line: lineNumber,
context: "[REDACTED FOR SECURITY]",
},
remediation: {
suggested: "Move credentials to environment variables or secure vault",
automated: true,
confidence: 0.85,
},
metadata: {
cweId: "CWE-798",
cvssScore: 9.8,
exploitability: "high",
detected: new Date(),
},
});
});
});
}
/**
* Scan for LDAP injection vulnerabilities
*/
private scanForLDAPInjection(filePath: string, content: string, lines: string[]): void {
SECURITY_PATTERNS.ldapInjection.forEach((pattern, index) => {
const matches = Array.from(content.matchAll(pattern));
matches.forEach((match) => {
const lineNumber = this.getLineNumber(content, match.index || 0);
this.addVulnerability({
id: `ldap-${Date.now()}-${index}`,
severity: "medium",
type: "LDAP Injection",
description: `Potential LDAP injection vulnerability detected: ${match[0]}`,
location: {
file: filePath,
line: lineNumber,
context: lines[lineNumber - 1]?.trim(),
},
remediation: {
suggested: "Escape LDAP special characters",
automated: true,
confidence: 0.7,
},
metadata: {
cweId: "CWE-90",
cvssScore: 6.8,
exploitability: "medium",
detected: new Date(),
},
});
});
});
}
/**
* Scan for NoSQL injection vulnerabilities
*/
private scanForNoSQLInjection(filePath: string, content: string, lines: string[]): void {
SECURITY_PATTERNS.nosqlInjection.forEach((pattern, index) => {
const matches = Array.from(content.matchAll(pattern));
matches.forEach((match) => {
const lineNumber = this.getLineNumber(content, match.index || 0);
this.addVulnerability({
id: `nosql-${Date.now()}-${index}`,
severity: "high",
type: "NoSQL Injection",
description: `Potential NoSQL injection vulnerability detected: ${match[0]}`,
location: {
file: filePath,
line: lineNumber,
context: lines[lineNumber - 1]?.trim(),
},
remediation: {
suggested: "Validate and sanitize NoSQL queries",
automated: true,
confidence: 0.75,
},
metadata: {
cweId: "CWE-943",
cvssScore: 7.8,
exploitability: "medium",
detected: new Date(),
},
});
});
});
}
/**
* Scan for CSRF vulnerabilities
*/
private scanForCSRF(filePath: string, content: string, lines: string[]): void {
SECURITY_PATTERNS.csrf.forEach((pattern, index) => {
const matches = Array.from(content.matchAll(pattern));
matches.forEach((match) => {
const lineNumber = this.getLineNumber(content, match.index || 0);
this.addVulnerability({
id: `csrf-${Date.now()}-${index}`,
severity: "medium",
type: "Cross-Site Request Forgery (CSRF)",
description: `Potential CSRF vulnerability detected: ${match[0]}`,
location: {
file: filePath,
line: lineNumber,
context: lines[lineNumber - 1]?.trim(),
},
remediation: {
suggested: "Implement CSRF tokens and verify HTTP methods",
automated: false,
confidence: 0.6,
},
metadata: {
cweId: "CWE-352",
cvssScore: 6.5,
exploitability: "medium",
detected: new Date(),
},
});
});
});
}
/**
* Scan for information disclosure vulnerabilities
*/
private scanForInfoDisclosure(filePath: string, content: string, lines: string[]): void {
SECURITY_PATTERNS.infoDisclosure.forEach((pattern, index) => {
const matches = Array.from(content.matchAll(pattern));
matches.forEach((match) => {
const lineNumber = this.getLineNumber(content, match.index || 0);
this.addVulnerability({
id: `info-${Date.now()}-${index}`,
severity: "low",
type: "Information Disclosure",
description: `Potential information disclosure detected: ${match[0]}`,
location: {
file: filePath,
line: lineNumber,
context: lines[lineNumber - 1]?.trim(),
},
remediation: {
suggested: "Disable debug information in production",
automated: true,
confidence: 0.8,
},
metadata: {
cweId: "CWE-200",
cvssScore: 4.3,
exploitability: "low",
detected: new Date(),
},
});
});
});
}
/**
* Scan for insecure configuration
*/
private scanForInsecureConfiguration(filePath: string, content: string, lines: string[]): void {
const insecurePatterns = [
{ pattern: /ssl\s*[:=]\s*false/gi, desc: "SSL disabled" },
{ pattern: /verify\s*[:=]\s*false/gi, desc: "Certificate verification disabled" },
{ pattern: /secure\s*[:=]\s*false/gi, desc: "Insecure configuration" },
{ pattern: /http:\/\//gi, desc: "HTTP instead of HTTPS" },
];
insecurePatterns.forEach((item, index) => {
const matches = Array.from(content.matchAll(item.pattern));
matches.forEach((match) => {
const lineNumber = this.getLineNumber(content, match.index || 0);
this.addVulnerability({
id: `config-${Date.now()}-${index}`,
severity: "medium",
type: "Insecure Configuration",
description: `${item.desc}: ${match[0]}`,
location: {
file: filePath,
line: lineNumber,
context: lines[lineNumber - 1]?.trim(),
},
remediation: {
suggested: "Enable secure configuration options",
automated: true,
confidence: 0.9,
},
metadata: {
cweId: "CWE-16",
cvssScore: 5.0,
exploitability: "medium",
detected: new Date(),
},
});
});
});
}
/**
* Scan runtime environment for security issues
*/
private async scanRuntimeEnvironment(): Promise<void> {
// Check environment variables for exposed secrets
for (const [key, value] of Object.entries(process.env)) {
if (this.containsSensitiveData(key, value || "")) {
this.addVulnerability({
id: `env-${Date.now()}-${key}`,
severity: "high",
type: "Environment Variable Exposure",
description: `Sensitive data in environment variable: ${key}`,
location: {
context: "Runtime Environment",
},
remediation: {
suggested: "Use secure secret management",
automated: false,
confidence: 0.9,
},
metadata: {
cweId: "CWE-200",
cvssScore: 7.5,
exploitability: "medium",
detected: new Date(),
},
});
}
}
}
/**
* Scan file system for security issues
*/
private async scanFileSystem(): Promise<void> {
const sensitiveFiles = [
".env",
".env.local",
".env.production",
"config.json",
"secrets.json",
"private.key",
"id_rsa",
];
for (const fileName of sensitiveFiles) {
try {
await fs.access(fileName);
this.addVulnerability({
id: `fs-${Date.now()}-${fileName}`,
severity: "medium",
type: "Sensitive File Exposure",
description: `Sensitive file found: ${fileName}`,
location: {
file: fileName,
},
remediation: {
suggested: "Ensure file permissions are restrictive and file is in .gitignore",
automated: true,
confidence: 0.8,
},
metadata: {
cweId: "CWE-200",
cvssScore: 6.0,
exploitability: "low",
detected: new Date(),
},
});
} catch {
// File doesn't exist, which is good
}
}
}
/**
* Scan configurations for security issues
*/
private async scanConfigurations(): Promise<void> {
// This would scan various config files for insecure settings
this.logger.debug("Scanning configurations for security issues");
}
/**
* Scan dependencies for known vulnerabilities
*/
private async scanDependencies(): Promise<void> {
// This would integrate with npm audit or similar tools
this.logger.debug("Scanning dependencies for vulnerabilities");
}
/**
* Perform AI-powered analysis for complex patterns
*/
private async performAIAnalysis(): Promise<void> {
// Advanced AI analysis would go here
this.logger.debug("Performing AI-powered security analysis");
}
/**
* Add vulnerability to the list
*/
private addVulnerability(vulnerability: SecurityVulnerability): void {
this.vulnerabilities.push(vulnerability);
}
/**
* Get line number from string index
*/
private getLineNumber(content: string, index: number): number {
return content.substring(0, index).split("\n").length;
}
/**
* Check if string contains sensitive data
*/
private containsSensitiveData(key: string, value: string): boolean {
const sensitiveKeys = ["password", "secret", "key", "token", "auth"];
const keyLower = key.toLowerCase();
return (
sensitiveKeys.some((sensitive) => keyLower.includes(sensitive)) &&
value.length > 8 &&
!/^(true|false|null|undefined|\d+)$/i.test(value)
);
}
/**
* Generate scan result summary
*/
private generateScanResult(scanId: string, duration: number): SecurityScanResult {
const summary = this.vulnerabilities.reduce(
(acc, vuln) => {
acc.total++;
acc[vuln.severity]++;
return acc;
},
{ total: 0, critical: 0, high: 0, medium: 0, low: 0 },
);
const remediationAvailable = this.vulnerabilities.filter((v) => v.remediation.automated).length;
return {
scanId,
timestamp: new Date(),
duration,
vulnerabilities: [...this.vulnerabilities],
summary,
remediationAvailable,
compliance: {
owasp: summary.critical === 0 && summary.high < 3,
cwe: summary.total < 10,
gdpr: this.vulnerabilities.filter((v) => v.type.includes("Disclosure")).length === 0,
},
};
}
/**
* Get scan history
*/
getScanHistory(): SecurityScanResult[] {
return [...this.scanHistory];
}
/**
* Get latest scan result
*/
getLatestScan(): SecurityScanResult | null {
return this.scanHistory.length > 0 ? this.scanHistory[this.scanHistory.length - 1] : null;
}
/**
* Clear scan history
*/
clearHistory(): void {
this.scanHistory = [];
this.remediationHistory = [];
}
}