@syntropysoft/praetorian
Version:
Praetorian CLI – A universal multi-environment configuration validator for DevSecOps teams. Validate, compare, and secure YAML/ENV files with ease.
317 lines • 11.6 kB
JavaScript
;
/**
* Vulnerability Scanner - Functional Programming
*
* Single Responsibility: Scan for security vulnerabilities only
* Pure functions, no state, no side effects
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.getVulnerabilitySeverity = exports.detectXSS = exports.detectSQLInjection = exports.detectWeakCredentials = exports.detectInsecureProtocols = exports.detectWeakEncryption = exports.scanVulnerabilities = void 0;
/**
* Pure function to scan for vulnerabilities
*/
const scanVulnerabilities = (content, rules, context) => {
// Guard clause: no content
if (!content || content.trim().length === 0) {
return [];
}
// Guard clause: no rules
if (!rules || rules.length === 0) {
return [];
}
return rules
.filter(rule => rule.enabled)
.flatMap(rule => scanVulnerabilitiesWithRule(content, rule, context));
};
exports.scanVulnerabilities = scanVulnerabilities;
/**
* Pure function to scan vulnerabilities with a specific rule
*/
const scanVulnerabilitiesWithRule = (content, rule, context) => {
// Guard clause: invalid rule
if (!rule || !rule.pattern) {
return [];
}
const matches = findVulnerabilityMatches(content, rule.pattern);
return matches.map(match => createVulnerabilityResult(match, rule, content));
};
/**
* Pure function to find vulnerability matches
*/
const findVulnerabilityMatches = (content, pattern) => {
const matches = [];
let match;
// Reset regex lastIndex to ensure global search works
pattern.lastIndex = 0;
while ((match = pattern.exec(content)) !== null) {
matches.push({
value: match[0],
index: match.index
});
// Prevent infinite loop on zero-length matches
if (match.index === pattern.lastIndex) {
pattern.lastIndex++;
}
}
return matches;
};
/**
* Pure function to create vulnerability result
*/
const createVulnerabilityResult = (match, rule, content) => {
const { lineNumber, columnNumber } = getLineAndColumn(content, match.index);
return {
type: rule.category,
cve: rule.cve,
cvssScore: rule.cvssScore,
description: rule.description,
remediation: rule.remediation,
references: rule.references,
lineNumber,
columnNumber
};
};
/**
* Pure function to get line and column from index
*/
const getLineAndColumn = (content, index) => {
const beforeMatch = content.substring(0, index);
const lineNumber = (beforeMatch.match(/\n/g) || []).length + 1;
const lastNewline = beforeMatch.lastIndexOf('\n');
const columnNumber = index - lastNewline;
return { lineNumber, columnNumber };
};
/**
* Pure function to detect weak encryption
*/
const detectWeakEncryption = (content) => {
// Guard clause: no content
if (!content || content.trim().length === 0) {
return [];
}
const weakEncryptionPatterns = [
{
pattern: /MD5\s*\(/gi,
type: 'encryption',
description: 'MD5 hash function detected - cryptographically broken',
remediation: 'Use SHA-256 or stronger hash functions',
cve: 'CVE-2004-2761'
},
{
pattern: /SHA1\s*\(/gi,
type: 'encryption',
description: 'SHA-1 hash function detected - cryptographically weak',
remediation: 'Use SHA-256 or stronger hash functions',
cve: 'CVE-2005-4900'
},
{
pattern: /DES\s*\(/gi,
type: 'encryption',
description: 'DES encryption detected - cryptographically weak',
remediation: 'Use AES-256 or stronger encryption',
cve: 'CVE-1999-0017'
},
{
pattern: /RC4\s*\(/gi,
type: 'encryption',
description: 'RC4 encryption detected - cryptographically weak',
remediation: 'Use AES-256 or stronger encryption',
cve: 'CVE-2015-2808'
}
];
return weakEncryptionPatterns.flatMap(weakPattern => findVulnerabilityMatches(content, weakPattern.pattern).map(match => ({
type: weakPattern.type,
cve: weakPattern.cve,
description: weakPattern.description,
remediation: weakPattern.remediation,
lineNumber: getLineAndColumn(content, match.index).lineNumber,
columnNumber: getLineAndColumn(content, match.index).columnNumber
})));
};
exports.detectWeakEncryption = detectWeakEncryption;
/**
* Pure function to detect insecure protocols
*/
const detectInsecureProtocols = (content) => {
// Guard clause: no content
if (!content || content.trim().length === 0) {
return [];
}
const insecureProtocolPatterns = [
{
pattern: /http:\/\//gi,
type: 'protocol',
description: 'HTTP protocol detected - data transmitted in plain text',
remediation: 'Use HTTPS for all communications',
cve: 'CVE-2014-3566'
},
{
pattern: /ftp:\/\//gi,
type: 'protocol',
description: 'FTP protocol detected - credentials transmitted in plain text',
remediation: 'Use SFTP or FTPS for secure file transfer',
cve: 'CVE-1999-0017'
},
{
pattern: /telnet:\/\//gi,
type: 'protocol',
description: 'Telnet protocol detected - credentials transmitted in plain text',
remediation: 'Use SSH for secure remote access',
cve: 'CVE-1999-0017'
}
];
return insecureProtocolPatterns.flatMap(protocolPattern => findVulnerabilityMatches(content, protocolPattern.pattern).map(match => ({
type: protocolPattern.type,
cve: protocolPattern.cve,
description: protocolPattern.description,
remediation: protocolPattern.remediation,
lineNumber: getLineAndColumn(content, match.index).lineNumber,
columnNumber: getLineAndColumn(content, match.index).columnNumber
})));
};
exports.detectInsecureProtocols = detectInsecureProtocols;
/**
* Pure function to detect weak credentials
*/
const detectWeakCredentials = (content) => {
// Guard clause: no content
if (!content || content.trim().length === 0) {
return [];
}
const weakCredentialPatterns = [
{
pattern: /password\s*[:=]\s*["']?admin["']?/gi,
type: 'credential',
description: 'Default admin password detected',
remediation: 'Use strong, unique passwords',
cve: 'CVE-2019-11043'
},
{
pattern: /password\s*[:=]\s*["']?password["']?/gi,
type: 'credential',
description: 'Weak password detected',
remediation: 'Use strong, unique passwords',
cve: 'CVE-2019-11043'
},
{
pattern: /password\s*[:=]\s*["']?123456["']?/gi,
type: 'credential',
description: 'Weak numeric password detected',
remediation: 'Use strong, unique passwords',
cve: 'CVE-2019-11043'
},
{
pattern: /password\s*[:=]\s*["']?[a-zA-Z0-9]{1,6}["']?/gi,
type: 'credential',
description: 'Short password detected',
remediation: 'Use passwords with at least 8 characters',
cve: 'CVE-2019-11043'
}
];
return weakCredentialPatterns.flatMap(credPattern => findVulnerabilityMatches(content, credPattern.pattern).map(match => ({
type: credPattern.type,
cve: credPattern.cve,
description: credPattern.description,
remediation: credPattern.remediation,
lineNumber: getLineAndColumn(content, match.index).lineNumber,
columnNumber: getLineAndColumn(content, match.index).columnNumber
})));
};
exports.detectWeakCredentials = detectWeakCredentials;
/**
* Pure function to detect SQL injection vulnerabilities
*/
const detectSQLInjection = (content) => {
// Guard clause: no content
if (!content || content.trim().length === 0) {
return [];
}
const sqlInjectionPatterns = [
{
pattern: /SELECT\s+.*\s+FROM\s+.*\s+WHERE\s+.*\$\{/gi,
type: 'injection',
description: 'Potential SQL injection vulnerability - string interpolation in WHERE clause',
remediation: 'Use parameterized queries or prepared statements',
cve: 'CVE-2019-5418'
},
{
pattern: /INSERT\s+INTO\s+.*\s+VALUES\s+.*\$\{/gi,
type: 'injection',
description: 'Potential SQL injection vulnerability - string interpolation in INSERT',
remediation: 'Use parameterized queries or prepared statements',
cve: 'CVE-2019-5418'
},
{
pattern: /UPDATE\s+.*\s+SET\s+.*\s+WHERE\s+.*\$\{/gi,
type: 'injection',
description: 'Potential SQL injection vulnerability - string interpolation in UPDATE',
remediation: 'Use parameterized queries or prepared statements',
cve: 'CVE-2019-5418'
}
];
return sqlInjectionPatterns.flatMap(sqlPattern => findVulnerabilityMatches(content, sqlPattern.pattern).map(match => ({
type: sqlPattern.type,
cve: sqlPattern.cve,
description: sqlPattern.description,
remediation: sqlPattern.remediation,
lineNumber: getLineAndColumn(content, match.index).lineNumber,
columnNumber: getLineAndColumn(content, match.index).columnNumber
})));
};
exports.detectSQLInjection = detectSQLInjection;
/**
* Pure function to detect XSS vulnerabilities
*/
const detectXSS = (content) => {
// Guard clause: no content
if (!content || content.trim().length === 0) {
return [];
}
const xssPatterns = [
{
pattern: /innerHTML\s*=\s*.*\$\{/gi,
type: 'xss',
description: 'Potential XSS vulnerability - innerHTML with string interpolation',
remediation: 'Use textContent or sanitize HTML content',
cve: 'CVE-2019-5418'
},
{
pattern: /document\.write\s*\(.*\$\{/gi,
type: 'xss',
description: 'Potential XSS vulnerability - document.write with string interpolation',
remediation: 'Use DOM manipulation methods or sanitize content',
cve: 'CVE-2019-5418'
}
];
return xssPatterns.flatMap(xssPattern => findVulnerabilityMatches(content, xssPattern.pattern).map(match => ({
type: xssPattern.type,
cve: xssPattern.cve,
description: xssPattern.description,
remediation: xssPattern.remediation,
lineNumber: getLineAndColumn(content, match.index).lineNumber,
columnNumber: getLineAndColumn(content, match.index).columnNumber
})));
};
exports.detectXSS = detectXSS;
/**
* Pure function to get vulnerability severity
*/
const getVulnerabilitySeverity = (cve, cvssScore) => {
// Guard clause: no CVE or CVSS score
if (!cve && !cvssScore) {
return 'medium';
}
if (cvssScore !== undefined) {
if (cvssScore >= 9.0)
return 'critical';
if (cvssScore >= 7.0)
return 'high';
if (cvssScore >= 4.0)
return 'medium';
return 'low';
}
// Default based on CVE presence
return cve ? 'high' : 'medium';
};
exports.getVulnerabilitySeverity = getVulnerabilitySeverity;
//# sourceMappingURL=VulnerabilityScanner.js.map