UNPKG

@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
"use strict"; 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