@casoon/auditmysite
Version:
A comprehensive command-line tool for automated accessibility, security, performance, and SEO testing using Playwright and pa11y, based on sitemap URLs
257 lines • 13.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.VulnerabilityTest = void 0;
const base_test_1 = require("../base-test");
class VulnerabilityTest extends base_test_1.BaseAccessibilityTest {
constructor() {
super(...arguments);
this.name = 'Vulnerability Scan Test';
this.description = 'Scans for common web vulnerabilities and security weaknesses';
this.category = 'security';
this.priority = 'critical';
this.standards = ['OWASP Top 10', 'Security Best Practices', 'Vulnerability Assessment'];
}
async run(context) {
const { page, url } = context;
try {
await page.goto(url, { waitUntil: 'networkidle' });
const issues = [];
const warnings = [];
const details = {};
// Perform vulnerability analysis
const vulnerabilityAnalysis = await this.performVulnerabilityScan(page, url);
details.vulnerabilityAnalysis = vulnerabilityAnalysis;
// Check for XSS vulnerabilities
if (vulnerabilityAnalysis.xssVulnerabilities.length > 0) {
issues.push(`XSS vulnerabilities detected: ${vulnerabilityAnalysis.xssVulnerabilities.length} potential issues`);
details.xssVulnerabilities = vulnerabilityAnalysis.xssVulnerabilities;
}
// Check for injection vulnerabilities
if (vulnerabilityAnalysis.injectionVulnerabilities.length > 0) {
issues.push(`Injection vulnerabilities detected: ${vulnerabilityAnalysis.injectionVulnerabilities.length} potential issues`);
details.injectionVulnerabilities = vulnerabilityAnalysis.injectionVulnerabilities;
}
// Check for information disclosure
if (vulnerabilityAnalysis.infoDisclosure.length > 0) {
issues.push(`Information disclosure detected: ${vulnerabilityAnalysis.infoDisclosure.length} potential issues`);
details.infoDisclosure = vulnerabilityAnalysis.infoDisclosure;
}
// Check for sensitive data exposure
if (vulnerabilityAnalysis.sensitiveDataExposure.length > 0) {
issues.push(`Sensitive data exposure detected: ${vulnerabilityAnalysis.sensitiveDataExposure.length} potential issues`);
details.sensitiveDataExposure = vulnerabilityAnalysis.sensitiveDataExposure;
}
// Check for broken authentication
if (vulnerabilityAnalysis.brokenAuth.length > 0) {
issues.push(`Broken authentication detected: ${vulnerabilityAnalysis.brokenAuth.length} potential issues`);
details.brokenAuth = vulnerabilityAnalysis.brokenAuth;
}
// Check for security misconfigurations
if (vulnerabilityAnalysis.securityMisconfig.length > 0) {
warnings.push(`Security misconfigurations detected: ${vulnerabilityAnalysis.securityMisconfig.length} potential issues`);
details.securityMisconfig = vulnerabilityAnalysis.securityMisconfig;
}
// Check for outdated components
if (vulnerabilityAnalysis.outdatedComponents.length > 0) {
warnings.push(`Outdated components detected: ${vulnerabilityAnalysis.outdatedComponents.length} potential issues`);
details.outdatedComponents = vulnerabilityAnalysis.outdatedComponents;
}
// Check for insufficient logging
if (vulnerabilityAnalysis.insufficientLogging.length > 0) {
warnings.push(`Insufficient logging detected: ${vulnerabilityAnalysis.insufficientLogging.length} potential issues`);
details.insufficientLogging = vulnerabilityAnalysis.insufficientLogging;
}
// Calculate vulnerability score
const totalVulnerabilities = vulnerabilityAnalysis.xssVulnerabilities.length +
vulnerabilityAnalysis.injectionVulnerabilities.length +
vulnerabilityAnalysis.infoDisclosure.length +
vulnerabilityAnalysis.sensitiveDataExposure.length +
vulnerabilityAnalysis.brokenAuth.length;
const totalWarnings = vulnerabilityAnalysis.securityMisconfig.length +
vulnerabilityAnalysis.outdatedComponents.length +
vulnerabilityAnalysis.insufficientLogging.length;
const vulnerabilityScore = Math.max(0, 100 - (totalVulnerabilities * 10) - (totalWarnings * 5));
details.vulnerabilityScore = vulnerabilityScore;
details.totalVulnerabilities = totalVulnerabilities;
details.totalWarnings = totalWarnings;
return this.createResult(totalVulnerabilities === 0, totalVulnerabilities + totalWarnings, issues, warnings, details);
}
catch (error) {
return this.createErrorResult(`Vulnerability Test failed: ${error}`);
}
}
async performVulnerabilityScan(page, url) {
const analysis = {
xssVulnerabilities: [],
injectionVulnerabilities: [],
infoDisclosure: [],
sensitiveDataExposure: [],
brokenAuth: [],
securityMisconfig: [],
outdatedComponents: [],
insufficientLogging: []
};
// Perform page analysis
const pageAnalysis = await page.evaluate(() => {
const result = {
forms: [],
inputs: [],
scripts: [],
comments: [],
errorMessages: [],
versionInfo: [],
sensitiveData: []
};
// Analyze forms for injection vulnerabilities
const forms = document.querySelectorAll('form');
forms.forEach((form, index) => {
const formData = {
action: form.getAttribute('action') || '',
method: form.getAttribute('method') || 'GET',
inputs: []
};
const inputs = form.querySelectorAll('input, textarea, select');
inputs.forEach(input => {
const inputData = {
type: input.getAttribute('type') || 'text',
name: input.getAttribute('name') || '',
id: input.getAttribute('id') || '',
placeholder: input.getAttribute('placeholder') || '',
value: input.getAttribute('value') || ''
};
formData.inputs.push(inputData);
});
result.forms.push(formData);
});
// Analyze all inputs
const allInputs = document.querySelectorAll('input, textarea, select');
allInputs.forEach(input => {
const inputData = {
type: input.getAttribute('type') || 'text',
name: input.getAttribute('name') || '',
id: input.getAttribute('id') || '',
placeholder: input.getAttribute('placeholder') || '',
value: input.getAttribute('value') || '',
autocomplete: input.getAttribute('autocomplete') || ''
};
result.inputs.push(inputData);
});
// Analyze scripts for version information
const scripts = document.querySelectorAll('script[src]');
scripts.forEach(script => {
const src = script.getAttribute('src') || '';
if (src.includes('jquery') || src.includes('bootstrap') || src.includes('angular') || src.includes('react')) {
result.scripts.push(src);
}
});
// Extract comments that might contain sensitive information
const walker = document.createTreeWalker(document, NodeFilter.SHOW_COMMENT, null);
let comment;
while (comment = walker.nextNode()) {
const commentText = comment.textContent || '';
if (commentText.includes('TODO') || commentText.includes('FIXME') ||
commentText.includes('password') || commentText.includes('secret') ||
commentText.includes('api') || commentText.includes('key')) {
result.comments.push(commentText);
}
}
// Look for error messages
const errorElements = document.querySelectorAll('.error, .alert, .warning, [class*="error"], [class*="alert"]');
errorElements.forEach(element => {
const text = element.textContent || '';
if (text.includes('error') || text.includes('exception') || text.includes('stack trace')) {
result.errorMessages.push(text);
}
});
// Look for version information in meta tags
const metaTags = document.querySelectorAll('meta');
metaTags.forEach(meta => {
const name = meta.getAttribute('name') || '';
const content = meta.getAttribute('content') || '';
if (name.includes('version') || name.includes('generator') || content.includes('version')) {
result.versionInfo.push(`${name}: ${content}`);
}
});
// Look for sensitive data patterns
const bodyText = document.body.textContent || '';
const sensitivePatterns = [
/password\s*[:=]\s*\w+/gi,
/api[_-]?key\s*[:=]\s*\w+/gi,
/secret\s*[:=]\s*\w+/gi,
/token\s*[:=]\s*\w+/gi,
/\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/g, // Credit card pattern
/\b\d{3}-\d{2}-\d{4}\b/g // SSN pattern
];
sensitivePatterns.forEach(pattern => {
const matches = bodyText.match(pattern);
if (matches) {
result.sensitiveData.push(...matches);
}
});
return result;
});
// Analyze XSS vulnerabilities
pageAnalysis.inputs.forEach((input) => {
if (input.type === 'text' || input.type === 'textarea') {
if (!input.name.includes('csrf') && !input.name.includes('token')) {
analysis.xssVulnerabilities.push(`Potential XSS in input: ${input.name || input.id}`);
}
}
});
// Check for reflected XSS in URL parameters
const urlParams = new URL(url).searchParams;
urlParams.forEach((value, key) => {
if (value.includes('<script>') || value.includes('javascript:') || value.includes('onerror=')) {
analysis.xssVulnerabilities.push(`Potential reflected XSS in URL parameter: ${key}`);
}
});
// Analyze injection vulnerabilities
pageAnalysis.forms.forEach((form) => {
if (form.method === 'GET') {
analysis.injectionVulnerabilities.push(`Form uses GET method: ${form.action}`);
}
form.inputs.forEach((input) => {
if (input.type === 'text' && (input.name.includes('sql') || input.name.includes('query'))) {
analysis.injectionVulnerabilities.push(`Potential SQL injection in input: ${input.name}`);
}
});
});
// Check for information disclosure
if (pageAnalysis.comments.length > 0) {
analysis.infoDisclosure.push(`${pageAnalysis.comments.length} comments with potentially sensitive information`);
}
if (pageAnalysis.errorMessages.length > 0) {
analysis.infoDisclosure.push(`${pageAnalysis.errorMessages.length} error messages that might reveal system information`);
}
if (pageAnalysis.versionInfo.length > 0) {
analysis.infoDisclosure.push(`${pageAnalysis.versionInfo.length} version information exposed`);
}
// Check for sensitive data exposure
if (pageAnalysis.sensitiveData.length > 0) {
analysis.sensitiveDataExposure.push(`${pageAnalysis.sensitiveData.length} sensitive data patterns found`);
}
// Check for broken authentication
pageAnalysis.inputs.forEach((input) => {
if (input.type === 'password' && input.autocomplete === 'on') {
analysis.brokenAuth.push(`Password field with autocomplete enabled: ${input.name}`);
}
});
// Check for security misconfigurations
if (pageAnalysis.scripts.length > 0) {
analysis.securityMisconfig.push(`${pageAnalysis.scripts.length} external scripts loaded (potential security risk)`);
}
// Check for outdated components
pageAnalysis.scripts.forEach((script) => {
if (script.includes('jquery') && !script.includes('jquery-3.') && !script.includes('jquery-2.')) {
analysis.outdatedComponents.push('Potentially outdated jQuery version');
}
});
// Check for insufficient logging
if (pageAnalysis.errorMessages.length === 0) {
analysis.insufficientLogging.push('No error messages found (might indicate insufficient error logging)');
}
return analysis;
}
}
exports.VulnerabilityTest = VulnerabilityTest;
//# sourceMappingURL=vulnerability-test.js.map