Some checks failed
HVAC Plugin CI/CD Pipeline / Code Quality & Standards (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Unit Tests (push) Has been cancelled
Security Monitoring & Compliance / Secrets & Credential Scan (push) Has been cancelled
Security Monitoring & Compliance / WordPress Security Analysis (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Security Analysis (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Integration Tests (push) Has been cancelled
Security Monitoring & Compliance / Dependency Vulnerability Scan (push) Has been cancelled
Security Monitoring & Compliance / Static Code Security Analysis (push) Has been cancelled
Security Monitoring & Compliance / Security Compliance Validation (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Deploy to Production (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Notification (push) Has been cancelled
Security Monitoring & Compliance / Security Summary Report (push) Has been cancelled
Security Monitoring & Compliance / Security Team Notification (push) Has been cancelled
- Deploy 6 simultaneous WordPress specialized agents using sequential thinking and Zen MCP - Resolve all critical issues: permissions, jQuery dependencies, CDN mapping, security vulnerabilities - Implement bulletproof jQuery loading system with WordPress hook timing fixes - Create professional MapGeo Safety system with CDN health monitoring and fallback UI - Fix privilege escalation vulnerability with capability-based authorization - Add complete announcement admin system with modal forms and AJAX handling - Enhance import/export functionality (54 trainers successfully exported) - Achieve 100% operational master trainer functionality verified via MCP Playwright E2E testing 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1024 lines
No EOL
41 KiB
JavaScript
1024 lines
No EOL
41 KiB
JavaScript
/**
|
|
* HVAC Community Events - AJAX Security Comprehensive Test Suite
|
|
*
|
|
* Tests for AJAX endpoint security including:
|
|
* - Nonce verification on all AJAX endpoints
|
|
* - Rate limiting implementation
|
|
* - Input sanitization and validation
|
|
* - Authorization checks and access control
|
|
* - CSRF protection mechanisms
|
|
* - Error handling and information disclosure
|
|
*
|
|
* AJAX SECURITY AREAS TESTED:
|
|
* 1. Nonce verification and CSRF protection
|
|
* 2. Rate limiting and brute force protection
|
|
* 3. Input sanitization and SQL injection prevention
|
|
* 4. Authorization and access control
|
|
* 5. Error handling and information disclosure
|
|
* 6. Session management and authentication
|
|
*
|
|
* @package HVAC_Community_Events
|
|
* @since 2.0.0
|
|
*/
|
|
|
|
const { test, expect } = require('@playwright/test');
|
|
const crypto = require('crypto');
|
|
|
|
// AJAX Security test configuration
|
|
const AJAX_SECURITY_CONFIG = {
|
|
BASE_URL: process.env.BASE_URL || 'http://localhost:8080',
|
|
AJAX_ENDPOINTS: {
|
|
// WordPress core AJAX endpoints
|
|
ADMIN_AJAX: '/wp-admin/admin-ajax.php',
|
|
REST_API: '/wp-json/',
|
|
|
|
// Plugin-specific AJAX endpoints (discovered dynamically)
|
|
PLUGIN_ENDPOINTS: [
|
|
'/wp-json/hvac/v1/',
|
|
'/wp-admin/admin-ajax.php?action=hvac_',
|
|
]
|
|
},
|
|
|
|
// Test payloads for various attack vectors
|
|
ATTACK_PAYLOADS: {
|
|
// SQL Injection payloads
|
|
SQL_INJECTION: [
|
|
"' OR 1=1 --",
|
|
"'; DROP TABLE wp_users; --",
|
|
"' UNION SELECT * FROM wp_options --",
|
|
"%27%20OR%201=1%20--",
|
|
"1' UNION SELECT user_pass FROM wp_users WHERE user_login='admin'--"
|
|
],
|
|
|
|
// XSS payloads
|
|
XSS_INJECTION: [
|
|
"<script>alert('XSS')</script>",
|
|
"javascript:alert('XSS')",
|
|
"<img src=x onerror=alert('XSS')>",
|
|
"<svg onload=alert('XSS')>",
|
|
"');alert('XSS');//"
|
|
],
|
|
|
|
// Command injection payloads
|
|
COMMAND_INJECTION: [
|
|
"; cat /etc/passwd",
|
|
"| cat /etc/passwd",
|
|
"&& cat /etc/passwd",
|
|
"`cat /etc/passwd`",
|
|
"$(cat /etc/passwd)"
|
|
],
|
|
|
|
// Path traversal payloads
|
|
PATH_TRAVERSAL: [
|
|
"../../../etc/passwd",
|
|
"..\\..\\..\\windows\\system32\\drivers\\etc\\hosts",
|
|
"%2e%2e%2f%2e%2e%2f%2e%2e%2fwp-config.php",
|
|
"....//....//....//etc/passwd"
|
|
],
|
|
|
|
// CSRF payloads
|
|
CSRF_ATTACKS: [
|
|
{ nonce: '', description: 'empty nonce' },
|
|
{ nonce: 'invalid_nonce_12345', description: 'invalid nonce' },
|
|
{ nonce: 'a'.repeat(100), description: 'oversized nonce' },
|
|
{ nonce: '<script>alert("xss")</script>', description: 'xss in nonce' }
|
|
]
|
|
},
|
|
|
|
// Rate limiting configuration
|
|
RATE_LIMIT_CONFIG: {
|
|
MAX_REQUESTS: 10,
|
|
TIME_WINDOW: 60, // seconds
|
|
RAPID_FIRE_COUNT: 20,
|
|
RAPID_FIRE_INTERVAL: 100 // milliseconds
|
|
},
|
|
|
|
// Authentication test data
|
|
TEST_USERS: {
|
|
VALID: {
|
|
username: 'test_trainer',
|
|
password: 'test_password_123!'
|
|
},
|
|
INVALID: {
|
|
username: 'invalid_user',
|
|
password: 'wrong_password'
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* AJAX Security Testing Framework
|
|
*/
|
|
class AJAXSecurityTestFramework {
|
|
constructor(page) {
|
|
this.page = page;
|
|
this.securityEvents = [];
|
|
this.requestLogs = [];
|
|
this.rateLimitTests = [];
|
|
this.discoveredEndpoints = [];
|
|
}
|
|
|
|
/**
|
|
* Enable AJAX security monitoring
|
|
*/
|
|
async enableSecurityMonitoring() {
|
|
// Monitor all AJAX requests
|
|
this.page.on('request', (request) => {
|
|
const isAjax = request.url().includes('admin-ajax.php') ||
|
|
request.url().includes('/wp-json/') ||
|
|
request.method() === 'POST' ||
|
|
request.headers()['x-requested-with'] === 'XMLHttpRequest';
|
|
|
|
if (isAjax) {
|
|
this.requestLogs.push({
|
|
url: request.url(),
|
|
method: request.method(),
|
|
headers: request.headers(),
|
|
timestamp: new Date().toISOString(),
|
|
postData: request.postData()
|
|
});
|
|
}
|
|
});
|
|
|
|
// Monitor responses for security issues
|
|
this.page.on('response', async (response) => {
|
|
if (response.request().url().includes('admin-ajax.php') ||
|
|
response.request().url().includes('/wp-json/')) {
|
|
|
|
const responseText = await response.text().catch(() => '');
|
|
|
|
// Check for information disclosure
|
|
if (this.containsInformationDisclosure(responseText)) {
|
|
this.securityEvents.push({
|
|
type: 'information_disclosure',
|
|
url: response.url(),
|
|
status: response.status(),
|
|
disclosure: this.extractDisclosedInfo(responseText),
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
}
|
|
|
|
// Check for error messages that reveal system info
|
|
if (this.containsSystemInfo(responseText)) {
|
|
this.securityEvents.push({
|
|
type: 'system_info_disclosure',
|
|
url: response.url(),
|
|
info: this.extractSystemInfo(responseText),
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
// Monitor console errors that might indicate security issues
|
|
this.page.on('console', (message) => {
|
|
if (message.type() === 'error' && this.isSecurityRelevantError(message.text())) {
|
|
this.securityEvents.push({
|
|
type: 'console_error',
|
|
message: message.text(),
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Discover AJAX endpoints by analyzing page JavaScript
|
|
*/
|
|
async discoverAjaxEndpoints() {
|
|
console.log('🔍 Discovering AJAX endpoints...');
|
|
|
|
// Navigate to plugin pages to discover endpoints
|
|
const pluginPages = [
|
|
'/trainer/dashboard/',
|
|
'/master-trainer/master-dashboard/',
|
|
'/trainer/profile/',
|
|
'/community-login/'
|
|
];
|
|
|
|
for (const pagePath of pluginPages) {
|
|
try {
|
|
const response = await this.page.goto(`${AJAX_SECURITY_CONFIG.BASE_URL}${pagePath}`, {
|
|
timeout: 10000,
|
|
waitUntil: 'domcontentloaded'
|
|
});
|
|
|
|
if (response && response.status() === 200) {
|
|
// Extract AJAX endpoints from page scripts
|
|
const endpoints = await this.page.evaluate(() => {
|
|
const scripts = Array.from(document.querySelectorAll('script'));
|
|
const endpoints = new Set();
|
|
|
|
scripts.forEach(script => {
|
|
const content = script.textContent || script.innerHTML || '';
|
|
|
|
// Look for AJAX URLs
|
|
const ajaxMatches = content.match(/ajax_url['"]*\s*[:=]\s*['"]([^'"]+)['"]/g);
|
|
if (ajaxMatches) {
|
|
ajaxMatches.forEach(match => {
|
|
const url = match.match(/['"]([^'"]+)['"]/);
|
|
if (url && url[1]) endpoints.add(url[1]);
|
|
});
|
|
}
|
|
|
|
// Look for REST API URLs
|
|
const restMatches = content.match(/wp-json\/[^'">\s]+/g);
|
|
if (restMatches) {
|
|
restMatches.forEach(match => endpoints.add('/' + match));
|
|
}
|
|
|
|
// Look for action parameters
|
|
const actionMatches = content.match(/action['"]*\s*[:=]\s*['"]([^'"]+)['"]/g);
|
|
if (actionMatches) {
|
|
actionMatches.forEach(match => {
|
|
const action = match.match(/['"]([^'"]+)['"]/);
|
|
if (action && action[1]) {
|
|
endpoints.add(`/wp-admin/admin-ajax.php?action=${action[1]}`);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
return Array.from(endpoints);
|
|
});
|
|
|
|
this.discoveredEndpoints = [...this.discoveredEndpoints, ...endpoints];
|
|
}
|
|
} catch (error) {
|
|
console.log(`⚠️ Could not scan ${pagePath}: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
// Remove duplicates
|
|
this.discoveredEndpoints = [...new Set(this.discoveredEndpoints)];
|
|
console.log(`📊 Discovered ${this.discoveredEndpoints.length} AJAX endpoints`);
|
|
this.discoveredEndpoints.forEach(endpoint => console.log(` • ${endpoint}`));
|
|
}
|
|
|
|
/**
|
|
* Test AJAX endpoint for nonce validation
|
|
*/
|
|
async testNonceValidation(endpoint, action = 'test_action') {
|
|
console.log(`🔒 Testing nonce validation on: ${endpoint}`);
|
|
|
|
const testResults = [];
|
|
|
|
for (const csrfAttack of AJAX_SECURITY_CONFIG.ATTACK_PAYLOADS.CSRF_ATTACKS) {
|
|
try {
|
|
const response = await this.page.request.post(endpoint, {
|
|
data: {
|
|
action: action,
|
|
_wpnonce: csrfAttack.nonce,
|
|
test_data: 'security_test'
|
|
},
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
'X-Requested-With': 'XMLHttpRequest'
|
|
}
|
|
});
|
|
|
|
const responseText = await response.text();
|
|
const isBlocked = response.status() === 403 ||
|
|
response.status() === 401 ||
|
|
responseText.includes('nonce') ||
|
|
responseText.includes('security') ||
|
|
responseText.includes('permission');
|
|
|
|
testResults.push({
|
|
attack: csrfAttack.description,
|
|
nonce: csrfAttack.nonce,
|
|
status: response.status(),
|
|
blocked: isBlocked,
|
|
response: responseText.substring(0, 200)
|
|
});
|
|
|
|
} catch (error) {
|
|
testResults.push({
|
|
attack: csrfAttack.description,
|
|
error: error.message,
|
|
blocked: true
|
|
});
|
|
}
|
|
}
|
|
|
|
return testResults;
|
|
}
|
|
|
|
/**
|
|
* Test rate limiting on AJAX endpoint
|
|
*/
|
|
async testRateLimiting(endpoint, action = 'test_action') {
|
|
console.log(`⏱️ Testing rate limiting on: ${endpoint}`);
|
|
|
|
const startTime = Date.now();
|
|
const requests = [];
|
|
let rateLimitTriggered = false;
|
|
let firstBlockedRequest = null;
|
|
|
|
// Rapid fire requests
|
|
for (let i = 0; i < AJAX_SECURITY_CONFIG.RATE_LIMIT_CONFIG.RAPID_FIRE_COUNT; i++) {
|
|
try {
|
|
const requestStart = Date.now();
|
|
const response = await this.page.request.post(endpoint, {
|
|
data: {
|
|
action: action,
|
|
test_iteration: i,
|
|
test_data: 'rate_limit_test'
|
|
},
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
'X-Requested-With': 'XMLHttpRequest'
|
|
},
|
|
timeout: 10000
|
|
});
|
|
|
|
const requestTime = Date.now() - requestStart;
|
|
|
|
requests.push({
|
|
iteration: i,
|
|
status: response.status(),
|
|
responseTime: requestTime,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
|
|
// Check if request was rate limited
|
|
if (response.status() === 429 || requestTime > 5000) {
|
|
if (!rateLimitTriggered) {
|
|
rateLimitTriggered = true;
|
|
firstBlockedRequest = i;
|
|
console.log(`🛡️ Rate limiting triggered at request ${i}`);
|
|
}
|
|
}
|
|
|
|
} catch (error) {
|
|
requests.push({
|
|
iteration: i,
|
|
error: error.message,
|
|
blocked: true,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
|
|
if (!rateLimitTriggered && error.message.includes('timeout')) {
|
|
rateLimitTriggered = true;
|
|
firstBlockedRequest = i;
|
|
}
|
|
}
|
|
|
|
// Small delay between requests
|
|
await this.page.waitForTimeout(AJAX_SECURITY_CONFIG.RATE_LIMIT_CONFIG.RAPID_FIRE_INTERVAL);
|
|
}
|
|
|
|
const totalTime = Date.now() - startTime;
|
|
|
|
return {
|
|
totalRequests: requests.length,
|
|
totalTime,
|
|
rateLimitTriggered,
|
|
firstBlockedRequest,
|
|
averageResponseTime: requests
|
|
.filter(r => r.responseTime)
|
|
.reduce((sum, r) => sum + r.responseTime, 0) / requests.length,
|
|
requests: requests.slice(0, 5) // Only return first 5 for brevity
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Test input sanitization with various attack payloads
|
|
*/
|
|
async testInputSanitization(endpoint, action = 'test_action') {
|
|
console.log(`🧼 Testing input sanitization on: ${endpoint}`);
|
|
|
|
const testResults = [];
|
|
const allPayloads = [
|
|
...AJAX_SECURITY_CONFIG.ATTACK_PAYLOADS.SQL_INJECTION.map(p => ({ type: 'sql_injection', payload: p })),
|
|
...AJAX_SECURITY_CONFIG.ATTACK_PAYLOADS.XSS_INJECTION.map(p => ({ type: 'xss_injection', payload: p })),
|
|
...AJAX_SECURITY_CONFIG.ATTACK_PAYLOADS.COMMAND_INJECTION.map(p => ({ type: 'command_injection', payload: p })),
|
|
...AJAX_SECURITY_CONFIG.ATTACK_PAYLOADS.PATH_TRAVERSAL.map(p => ({ type: 'path_traversal', payload: p }))
|
|
];
|
|
|
|
for (const attackTest of allPayloads) {
|
|
try {
|
|
const response = await this.page.request.post(endpoint, {
|
|
data: {
|
|
action: action,
|
|
test_input: attackTest.payload,
|
|
user_data: attackTest.payload,
|
|
search_query: attackTest.payload
|
|
},
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
'X-Requested-With': 'XMLHttpRequest'
|
|
}
|
|
});
|
|
|
|
const responseText = await response.text();
|
|
|
|
// Check if attack was successful (BAD)
|
|
const attackSuccessful = this.checkForAttackSuccess(attackTest.type, attackTest.payload, responseText);
|
|
|
|
// Check if input was properly sanitized (GOOD)
|
|
const inputSanitized = !responseText.includes(attackTest.payload) ||
|
|
response.status() === 400 ||
|
|
response.status() === 403;
|
|
|
|
testResults.push({
|
|
attackType: attackTest.type,
|
|
payload: attackTest.payload.substring(0, 50),
|
|
status: response.status(),
|
|
attackSuccessful,
|
|
inputSanitized,
|
|
responseLength: responseText.length,
|
|
containsPayload: responseText.includes(attackTest.payload)
|
|
});
|
|
|
|
} catch (error) {
|
|
testResults.push({
|
|
attackType: attackTest.type,
|
|
payload: attackTest.payload.substring(0, 50),
|
|
error: error.message,
|
|
blocked: true
|
|
});
|
|
}
|
|
}
|
|
|
|
return testResults;
|
|
}
|
|
|
|
/**
|
|
* Check if an attack was successful based on response
|
|
*/
|
|
checkForAttackSuccess(attackType, payload, response) {
|
|
switch (attackType) {
|
|
case 'sql_injection':
|
|
return response.includes('mysql') ||
|
|
response.includes('sql error') ||
|
|
response.includes('database error') ||
|
|
response.includes('wp_users') ||
|
|
response.includes('user_pass');
|
|
|
|
case 'xss_injection':
|
|
return response.includes('<script>') ||
|
|
response.includes('javascript:') ||
|
|
response.includes('<img') ||
|
|
response.includes('<svg');
|
|
|
|
case 'command_injection':
|
|
return response.includes('root:x:') ||
|
|
response.includes('/bin/bash') ||
|
|
response.includes('Windows') ||
|
|
response.includes('System32');
|
|
|
|
case 'path_traversal':
|
|
return response.includes('root:x:') ||
|
|
response.includes('DB_PASSWORD') ||
|
|
response.includes('wp-config.php') ||
|
|
response.includes('hosts file');
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper methods for security analysis
|
|
*/
|
|
containsInformationDisclosure(responseText) {
|
|
const disclosurePatterns = [
|
|
/error.*line.*file/i,
|
|
/mysql.*error/i,
|
|
/fatal error/i,
|
|
/stack trace/i,
|
|
/wp-config\.php/i,
|
|
/database.*password/i
|
|
];
|
|
|
|
return disclosurePatterns.some(pattern => pattern.test(responseText));
|
|
}
|
|
|
|
containsSystemInfo(responseText) {
|
|
const systemInfoPatterns = [
|
|
/php.*version/i,
|
|
/mysql.*version/i,
|
|
/wordpress.*version/i,
|
|
/server.*apache|nginx/i,
|
|
/linux.*ubuntu|centos/i
|
|
];
|
|
|
|
return systemInfoPatterns.some(pattern => pattern.test(responseText));
|
|
}
|
|
|
|
isSecurityRelevantError(errorText) {
|
|
const securityErrorPatterns = [
|
|
/csrf/i,
|
|
/nonce/i,
|
|
/unauthorized/i,
|
|
/permission.*denied/i,
|
|
/access.*denied/i,
|
|
/security.*error/i
|
|
];
|
|
|
|
return securityErrorPatterns.some(pattern => pattern.test(errorText));
|
|
}
|
|
|
|
extractDisclosedInfo(responseText) {
|
|
// Extract specific pieces of disclosed information
|
|
const info = [];
|
|
|
|
if (responseText.includes('Fatal error')) {
|
|
const errorMatch = responseText.match(/Fatal error:([^<\n]+)/);
|
|
if (errorMatch) info.push(`Fatal Error: ${errorMatch[1].trim()}`);
|
|
}
|
|
|
|
if (responseText.includes('MySQL')) {
|
|
const mysqlMatch = responseText.match(/MySQL.*error[^<\n]+/i);
|
|
if (mysqlMatch) info.push(`MySQL: ${mysqlMatch[0].trim()}`);
|
|
}
|
|
|
|
return info;
|
|
}
|
|
|
|
extractSystemInfo(responseText) {
|
|
// Extract system information from response
|
|
const info = [];
|
|
|
|
const versionMatch = responseText.match(/version\s+[\d.]+/i);
|
|
if (versionMatch) info.push(versionMatch[0]);
|
|
|
|
const serverMatch = responseText.match(/(apache|nginx)\/[\d.]+/i);
|
|
if (serverMatch) info.push(serverMatch[0]);
|
|
|
|
return info;
|
|
}
|
|
|
|
/**
|
|
* Get security test report
|
|
*/
|
|
getSecurityReport() {
|
|
return {
|
|
discoveredEndpoints: this.discoveredEndpoints,
|
|
securityEvents: this.securityEvents,
|
|
requestLogs: this.requestLogs.slice(0, 10), // Limit for brevity
|
|
totalRequests: this.requestLogs.length,
|
|
vulnerabilities: this.securityEvents.length,
|
|
endpointCount: this.discoveredEndpoints.length
|
|
};
|
|
}
|
|
}
|
|
|
|
// ==============================================================================
|
|
// AJAX ENDPOINT DISCOVERY TESTS
|
|
// ==============================================================================
|
|
|
|
test.describe('AJAX Endpoint Discovery', () => {
|
|
|
|
test('Discover and catalog AJAX endpoints', async ({ page }) => {
|
|
console.log('🔍 Discovering AJAX endpoints across plugin pages...');
|
|
|
|
const securityFramework = new AJAXSecurityTestFramework(page);
|
|
await securityFramework.enableSecurityMonitoring();
|
|
|
|
// Discover endpoints
|
|
await securityFramework.discoverAjaxEndpoints();
|
|
|
|
const report = securityFramework.getSecurityReport();
|
|
|
|
// Verify endpoints were discovered
|
|
expect(report.endpointCount).toBeGreaterThan(0);
|
|
|
|
console.log(`✅ Discovered ${report.endpointCount} AJAX endpoints`);
|
|
|
|
// Document common WordPress AJAX patterns
|
|
const hasAdminAjax = report.discoveredEndpoints.some(e => e.includes('admin-ajax.php'));
|
|
const hasRestAPI = report.discoveredEndpoints.some(e => e.includes('wp-json'));
|
|
|
|
if (hasAdminAjax) {
|
|
console.log('✅ WordPress admin-ajax.php endpoints found');
|
|
}
|
|
if (hasRestAPI) {
|
|
console.log('✅ WordPress REST API endpoints found');
|
|
}
|
|
|
|
// Generate endpoint security assessment
|
|
console.log('📊 AJAX Endpoint Security Assessment:');
|
|
report.discoveredEndpoints.forEach(endpoint => {
|
|
console.log(` 📍 ${endpoint}`);
|
|
});
|
|
});
|
|
});
|
|
|
|
// ==============================================================================
|
|
// NONCE VALIDATION AND CSRF PROTECTION TESTS
|
|
// ==============================================================================
|
|
|
|
test.describe('Nonce Validation and CSRF Protection', () => {
|
|
|
|
test('Test nonce validation on admin-ajax.php', async ({ page }) => {
|
|
console.log('🔒 Testing nonce validation on WordPress admin-ajax.php...');
|
|
|
|
const securityFramework = new AJAXSecurityTestFramework(page);
|
|
await securityFramework.enableSecurityMonitoring();
|
|
|
|
const endpoint = `${AJAX_SECURITY_CONFIG.BASE_URL}/wp-admin/admin-ajax.php`;
|
|
const nonceResults = await securityFramework.testNonceValidation(endpoint, 'test_hvac_action');
|
|
|
|
console.log('📊 Nonce Validation Results:');
|
|
nonceResults.forEach(result => {
|
|
const status = result.blocked ? '✅ BLOCKED' : '❌ ALLOWED';
|
|
console.log(` ${status} ${result.attack}: HTTP ${result.status || 'ERROR'}`);
|
|
});
|
|
|
|
// At least some CSRF attacks should be blocked
|
|
const blockedAttacks = nonceResults.filter(r => r.blocked).length;
|
|
const totalAttacks = nonceResults.length;
|
|
|
|
console.log(`🛡️ CSRF Protection: ${blockedAttacks}/${totalAttacks} attacks blocked`);
|
|
|
|
if (blockedAttacks === 0) {
|
|
console.log('⚠️ WARNING: No CSRF attacks were blocked - potential vulnerability');
|
|
}
|
|
});
|
|
|
|
test('Test CSRF protection across discovered endpoints', async ({ page }) => {
|
|
console.log('🔒 Testing CSRF protection across discovered endpoints...');
|
|
|
|
const securityFramework = new AJAXSecurityTestFramework(page);
|
|
await securityFramework.enableSecurityMonitoring();
|
|
|
|
// Discover endpoints first
|
|
await securityFramework.discoverAjaxEndpoints();
|
|
const report = securityFramework.getSecurityReport();
|
|
|
|
// Test top 3 discovered endpoints
|
|
const endpointsToTest = report.discoveredEndpoints.slice(0, 3);
|
|
|
|
for (const endpoint of endpointsToTest) {
|
|
if (endpoint.includes('admin-ajax.php')) {
|
|
console.log(`🔍 Testing CSRF protection: ${endpoint}`);
|
|
const results = await securityFramework.testNonceValidation(
|
|
`${AJAX_SECURITY_CONFIG.BASE_URL}${endpoint}`,
|
|
'hvac_test_action'
|
|
);
|
|
|
|
const blocked = results.filter(r => r.blocked).length;
|
|
console.log(` 📊 ${blocked}/${results.length} CSRF attacks blocked`);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// ==============================================================================
|
|
// RATE LIMITING AND BRUTE FORCE PROTECTION TESTS
|
|
// ==============================================================================
|
|
|
|
test.describe('Rate Limiting and Brute Force Protection', () => {
|
|
|
|
test('Test rate limiting on admin-ajax.php', async ({ page }) => {
|
|
console.log('⏱️ Testing rate limiting on admin-ajax.php...');
|
|
|
|
const securityFramework = new AJAXSecurityTestFramework(page);
|
|
await securityFramework.enableSecurityMonitoring();
|
|
|
|
const endpoint = `${AJAX_SECURITY_CONFIG.BASE_URL}/wp-admin/admin-ajax.php`;
|
|
const rateLimitResults = await securityFramework.testRateLimiting(endpoint, 'hvac_test_action');
|
|
|
|
console.log('📊 Rate Limiting Results:');
|
|
console.log(` 📈 Total requests: ${rateLimitResults.totalRequests}`);
|
|
console.log(` ⏱️ Total time: ${Math.round(rateLimitResults.totalTime / 1000)}s`);
|
|
console.log(` 📊 Average response time: ${Math.round(rateLimitResults.averageResponseTime || 0)}ms`);
|
|
|
|
if (rateLimitResults.rateLimitTriggered) {
|
|
console.log(` 🛡️ Rate limiting triggered at request ${rateLimitResults.firstBlockedRequest}`);
|
|
console.log('✅ Rate limiting protection is active');
|
|
} else {
|
|
console.log('⚠️ No rate limiting detected - potential vulnerability');
|
|
console.log('💡 Consider implementing rate limiting for AJAX endpoints');
|
|
}
|
|
});
|
|
|
|
test('Test brute force protection patterns', async ({ page }) => {
|
|
console.log('🔒 Testing brute force protection patterns...');
|
|
|
|
const securityFramework = new AJAXSecurityTestFramework(page);
|
|
await securityFramework.enableSecurityMonitoring();
|
|
|
|
// Test login-related AJAX endpoints with multiple failed attempts
|
|
const loginTests = [
|
|
{ action: 'login', data: { username: 'admin', password: 'wrong1' } },
|
|
{ action: 'login', data: { username: 'admin', password: 'wrong2' } },
|
|
{ action: 'login', data: { username: 'admin', password: 'wrong3' } },
|
|
{ action: 'login', data: { username: 'admin', password: 'wrong4' } },
|
|
{ action: 'login', data: { username: 'admin', password: 'wrong5' } }
|
|
];
|
|
|
|
let bruteForceBlocked = false;
|
|
let attemptCount = 0;
|
|
|
|
for (const loginTest of loginTests) {
|
|
attemptCount++;
|
|
try {
|
|
const response = await page.request.post(
|
|
`${AJAX_SECURITY_CONFIG.BASE_URL}/wp-admin/admin-ajax.php`,
|
|
{
|
|
data: {
|
|
action: loginTest.action,
|
|
username: loginTest.data.username,
|
|
password: loginTest.data.password
|
|
}
|
|
}
|
|
);
|
|
|
|
const responseText = await response.text();
|
|
|
|
// Check for brute force protection indicators
|
|
if (response.status() === 429 ||
|
|
responseText.includes('too many attempts') ||
|
|
responseText.includes('rate limit') ||
|
|
responseText.includes('blocked')) {
|
|
bruteForceBlocked = true;
|
|
console.log(`🛡️ Brute force protection triggered at attempt ${attemptCount}`);
|
|
break;
|
|
}
|
|
|
|
console.log(` 📍 Attempt ${attemptCount}: HTTP ${response.status()}`);
|
|
|
|
} catch (error) {
|
|
if (error.message.includes('timeout')) {
|
|
bruteForceBlocked = true;
|
|
console.log(`🛡️ Request timeout at attempt ${attemptCount} (possible rate limiting)`);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Delay between attempts
|
|
await page.waitForTimeout(1000);
|
|
}
|
|
|
|
if (bruteForceBlocked) {
|
|
console.log('✅ Brute force protection is active');
|
|
} else {
|
|
console.log('⚠️ No brute force protection detected');
|
|
}
|
|
});
|
|
});
|
|
|
|
// ==============================================================================
|
|
// INPUT SANITIZATION TESTS
|
|
// ==============================================================================
|
|
|
|
test.describe('Input Sanitization and Injection Prevention', () => {
|
|
|
|
test('Test SQL injection prevention on AJAX endpoints', async ({ page }) => {
|
|
console.log('💉 Testing SQL injection prevention...');
|
|
|
|
const securityFramework = new AJAXSecurityTestFramework(page);
|
|
await securityFramework.enableSecurityMonitoring();
|
|
|
|
const endpoint = `${AJAX_SECURITY_CONFIG.BASE_URL}/wp-admin/admin-ajax.php`;
|
|
const sanitizationResults = await securityFramework.testInputSanitization(endpoint, 'hvac_search');
|
|
|
|
console.log('📊 Input Sanitization Results:');
|
|
|
|
const sqlInjectionTests = sanitizationResults.filter(r => r.attackType === 'sql_injection');
|
|
const successfulSQLAttacks = sqlInjectionTests.filter(r => r.attackSuccessful);
|
|
|
|
console.log(` 💉 SQL Injection: ${successfulSQLAttacks.length}/${sqlInjectionTests.length} successful attacks`);
|
|
|
|
if (successfulSQLAttacks.length > 0) {
|
|
console.log('🚨 CRITICAL: SQL injection vulnerabilities detected!');
|
|
successfulSQLAttacks.forEach(attack => {
|
|
console.log(` ❌ ${attack.payload}`);
|
|
});
|
|
} else {
|
|
console.log('✅ SQL injection protection is effective');
|
|
}
|
|
|
|
// Test other injection types
|
|
const xssTests = sanitizationResults.filter(r => r.attackType === 'xss_injection');
|
|
const successfulXSSAttacks = xssTests.filter(r => r.attackSuccessful);
|
|
|
|
console.log(` 🔓 XSS Injection: ${successfulXSSAttacks.length}/${xssTests.length} successful attacks`);
|
|
|
|
if (successfulXSSAttacks.length > 0) {
|
|
console.log('🚨 WARNING: XSS vulnerabilities detected!');
|
|
} else {
|
|
console.log('✅ XSS protection is effective');
|
|
}
|
|
});
|
|
|
|
test('Test command injection prevention', async ({ page }) => {
|
|
console.log('💻 Testing command injection prevention...');
|
|
|
|
const securityFramework = new AJAXSecurityTestFramework(page);
|
|
await securityFramework.enableSecurityMonitoring();
|
|
|
|
const endpoint = `${AJAX_SECURITY_CONFIG.BASE_URL}/wp-admin/admin-ajax.php`;
|
|
const sanitizationResults = await securityFramework.testInputSanitization(endpoint, 'hvac_file_operation');
|
|
|
|
const commandTests = sanitizationResults.filter(r => r.attackType === 'command_injection');
|
|
const successfulCommandAttacks = commandTests.filter(r => r.attackSuccessful);
|
|
|
|
console.log('📊 Command Injection Results:');
|
|
console.log(` 💻 Command Injection: ${successfulCommandAttacks.length}/${commandTests.length} successful attacks`);
|
|
|
|
if (successfulCommandAttacks.length > 0) {
|
|
console.log('🚨 CRITICAL: Command injection vulnerabilities detected!');
|
|
successfulCommandAttacks.forEach(attack => {
|
|
console.log(` ❌ ${attack.payload}`);
|
|
});
|
|
} else {
|
|
console.log('✅ Command injection protection is effective');
|
|
}
|
|
});
|
|
|
|
test('Test path traversal prevention', async ({ page }) => {
|
|
console.log('📁 Testing path traversal prevention...');
|
|
|
|
const securityFramework = new AJAXSecurityTestFramework(page);
|
|
await securityFramework.enableSecurityMonitoring();
|
|
|
|
const endpoint = `${AJAX_SECURITY_CONFIG.BASE_URL}/wp-admin/admin-ajax.php`;
|
|
const sanitizationResults = await securityFramework.testInputSanitization(endpoint, 'hvac_file_access');
|
|
|
|
const pathTests = sanitizationResults.filter(r => r.attackType === 'path_traversal');
|
|
const successfulPathAttacks = pathTests.filter(r => r.attackSuccessful);
|
|
|
|
console.log('📊 Path Traversal Results:');
|
|
console.log(` 📁 Path Traversal: ${successfulPathAttacks.length}/${pathTests.length} successful attacks`);
|
|
|
|
if (successfulPathAttacks.length > 0) {
|
|
console.log('🚨 CRITICAL: Path traversal vulnerabilities detected!');
|
|
successfulPathAttacks.forEach(attack => {
|
|
console.log(` ❌ ${attack.payload}`);
|
|
});
|
|
} else {
|
|
console.log('✅ Path traversal protection is effective');
|
|
}
|
|
});
|
|
});
|
|
|
|
// ==============================================================================
|
|
// ERROR HANDLING AND INFORMATION DISCLOSURE TESTS
|
|
// ==============================================================================
|
|
|
|
test.describe('Error Handling and Information Disclosure', () => {
|
|
|
|
test('Test error message information disclosure', async ({ page }) => {
|
|
console.log('📋 Testing error message information disclosure...');
|
|
|
|
const securityFramework = new AJAXSecurityTestFramework(page);
|
|
await securityFramework.enableSecurityMonitoring();
|
|
|
|
// Test various error conditions
|
|
const errorTests = [
|
|
{ action: 'nonexistent_action', data: {} },
|
|
{ action: 'hvac_invalid', data: { invalid_param: 'test' } },
|
|
{ action: 'hvac_test', data: { malformed_data: '{invalid_json' } }
|
|
];
|
|
|
|
for (const errorTest of errorTests) {
|
|
try {
|
|
await page.request.post(
|
|
`${AJAX_SECURITY_CONFIG.BASE_URL}/wp-admin/admin-ajax.php`,
|
|
{
|
|
data: errorTest.data
|
|
}
|
|
);
|
|
} catch (error) {
|
|
// Expected to fail, we're testing error handling
|
|
}
|
|
}
|
|
|
|
const report = securityFramework.getSecurityReport();
|
|
|
|
console.log('📊 Information Disclosure Analysis:');
|
|
console.log(` 📋 Total security events: ${report.securityEvents.length}`);
|
|
|
|
const disclosureEvents = report.securityEvents.filter(e => e.type === 'information_disclosure');
|
|
const systemInfoEvents = report.securityEvents.filter(e => e.type === 'system_info_disclosure');
|
|
|
|
console.log(` 🔓 Information disclosure events: ${disclosureEvents.length}`);
|
|
console.log(` 💻 System info disclosure events: ${systemInfoEvents.length}`);
|
|
|
|
if (disclosureEvents.length > 0) {
|
|
console.log('⚠️ Information disclosure detected:');
|
|
disclosureEvents.forEach(event => {
|
|
console.log(` 📋 ${event.disclosure.join(', ')}`);
|
|
});
|
|
}
|
|
|
|
if (systemInfoEvents.length > 0) {
|
|
console.log('⚠️ System information disclosure detected:');
|
|
systemInfoEvents.forEach(event => {
|
|
console.log(` 💻 ${event.info.join(', ')}`);
|
|
});
|
|
}
|
|
|
|
if (disclosureEvents.length === 0 && systemInfoEvents.length === 0) {
|
|
console.log('✅ No information disclosure detected');
|
|
}
|
|
});
|
|
});
|
|
|
|
// ==============================================================================
|
|
// COMPREHENSIVE AJAX SECURITY ASSESSMENT
|
|
// ==============================================================================
|
|
|
|
test.describe('Comprehensive AJAX Security Assessment', () => {
|
|
|
|
test('Generate comprehensive AJAX security report', async ({ page }) => {
|
|
console.log('📊 Generating comprehensive AJAX security assessment...');
|
|
|
|
const securityFramework = new AJAXSecurityTestFramework(page);
|
|
await securityFramework.enableSecurityMonitoring();
|
|
|
|
// Perform comprehensive security testing
|
|
await securityFramework.discoverAjaxEndpoints();
|
|
|
|
const endpoint = `${AJAX_SECURITY_CONFIG.BASE_URL}/wp-admin/admin-ajax.php`;
|
|
|
|
// Test all security aspects
|
|
const nonceResults = await securityFramework.testNonceValidation(endpoint);
|
|
const rateLimitResults = await securityFramework.testRateLimiting(endpoint);
|
|
const sanitizationResults = await securityFramework.testInputSanitization(endpoint);
|
|
|
|
// Generate final security report
|
|
const report = securityFramework.getSecurityReport();
|
|
|
|
console.log('🔐 COMPREHENSIVE AJAX SECURITY REPORT');
|
|
console.log('═'.repeat(50));
|
|
console.log(`📍 Endpoints discovered: ${report.endpointCount}`);
|
|
console.log(`📊 Total requests made: ${report.totalRequests}`);
|
|
console.log(`🚨 Security events detected: ${report.vulnerabilities}`);
|
|
console.log('');
|
|
|
|
// Nonce/CSRF Protection Analysis
|
|
const csrfBlocked = nonceResults.filter(r => r.blocked).length;
|
|
const csrfTotal = nonceResults.length;
|
|
const csrfScore = Math.round((csrfBlocked / csrfTotal) * 100);
|
|
console.log(`🔒 CSRF Protection: ${csrfScore}% (${csrfBlocked}/${csrfTotal})`);
|
|
|
|
// Rate Limiting Analysis
|
|
const rateLimitActive = rateLimitResults.rateLimitTriggered;
|
|
console.log(`⏱️ Rate Limiting: ${rateLimitActive ? 'ACTIVE' : 'INACTIVE'}`);
|
|
|
|
// Input Sanitization Analysis
|
|
const totalInjectionTests = sanitizationResults.length;
|
|
const successfulAttacks = sanitizationResults.filter(r => r.attackSuccessful).length;
|
|
const sanitizationScore = Math.round(((totalInjectionTests - successfulAttacks) / totalInjectionTests) * 100);
|
|
console.log(`🧼 Input Sanitization: ${sanitizationScore}% (${totalInjectionTests - successfulAttacks}/${totalInjectionTests})`);
|
|
|
|
// Overall Security Score
|
|
const overallScore = Math.round((csrfScore + (rateLimitActive ? 100 : 0) + sanitizationScore) / 3);
|
|
console.log('');
|
|
console.log(`🎯 OVERALL AJAX SECURITY SCORE: ${overallScore}%`);
|
|
|
|
if (overallScore >= 80) {
|
|
console.log('✅ AJAX security is GOOD');
|
|
} else if (overallScore >= 60) {
|
|
console.log('⚠️ AJAX security needs IMPROVEMENT');
|
|
} else {
|
|
console.log('🚨 AJAX security is POOR - immediate attention required');
|
|
}
|
|
|
|
console.log('');
|
|
console.log('🔧 SECURITY RECOMMENDATIONS:');
|
|
if (csrfScore < 80) {
|
|
console.log(' • Implement proper nonce validation on all AJAX endpoints');
|
|
}
|
|
if (!rateLimitActive) {
|
|
console.log(' • Add rate limiting to prevent brute force attacks');
|
|
}
|
|
if (sanitizationScore < 90) {
|
|
console.log(' • Improve input sanitization and validation');
|
|
}
|
|
if (report.vulnerabilities > 0) {
|
|
console.log(' • Review and fix information disclosure issues');
|
|
}
|
|
|
|
// Assertions for test validation
|
|
expect(report.endpointCount).toBeGreaterThan(0);
|
|
expect(nonceResults.length).toBeGreaterThan(0);
|
|
expect(sanitizationResults.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
console.log('🔐 HVAC AJAX Security Test Suite Loaded');
|
|
console.log('📊 Test Coverage:');
|
|
console.log(' ✅ AJAX endpoint discovery');
|
|
console.log(' ✅ Nonce validation and CSRF protection');
|
|
console.log(' ✅ Rate limiting and brute force protection');
|
|
console.log(' ✅ Input sanitization and injection prevention');
|
|
console.log(' ✅ Error handling and information disclosure');
|
|
console.log(' ✅ Comprehensive security assessment');
|
|
console.log('');
|
|
console.log('🚨 SECURITY VECTORS TESTED:');
|
|
console.log(' 💉 SQL Injection attacks');
|
|
console.log(' 🔓 XSS (Cross-Site Scripting) attacks');
|
|
console.log(' 💻 Command injection attacks');
|
|
console.log(' 📁 Path traversal attacks');
|
|
console.log(' 🔒 CSRF (Cross-Site Request Forgery) attacks');
|
|
console.log(' ⏱️ Rate limiting and brute force');
|
|
console.log(' 📋 Information disclosure');
|
|
console.log('');
|
|
console.log('⚠️ NOTE: Some tests require WordPress site to be accessible');
|
|
console.log('🔧 RECOMMENDATION: Run against staging environment first'); |