name: Security Monitoring & Compliance on: schedule: # Daily security scan at 2 AM UTC - cron: '0 2 * * *' # Weekly comprehensive audit on Sundays at 4 AM UTC - cron: '0 4 * * 0' push: branches: [ main, develop ] paths: - '**.php' - '**.js' - '**.json' - 'composer.lock' - 'package-lock.json' pull_request: branches: [ main ] workflow_dispatch: inputs: scan_type: description: 'Type of security scan to run' required: true default: 'full' type: choice options: - full - dependencies - secrets - wordpress - quick env: SCAN_OUTPUT_DIR: security-reports RETENTION_DAYS: 90 jobs: dependency-scan: name: Dependency Vulnerability Scan runs-on: ubuntu-latest if: github.event.schedule == '0 2 * * *' || github.event_name == 'push' || github.event_name == 'pull_request' || github.event.inputs.scan_type == 'dependencies' || github.event.inputs.scan_type == 'full' steps: - name: Checkout Code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '18' cache: 'npm' - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '8.1' tools: composer - name: Install Dependencies run: | npm ci --audit if [ -f composer.json ]; then composer install --no-dev --optimize-autoloader fi - name: NPM Security Audit run: | echo "🔍 Running NPM security audit..." mkdir -p $SCAN_OUTPUT_DIR # Run npm audit and capture output npm audit --audit-level=moderate --json > $SCAN_OUTPUT_DIR/npm-audit.json || true # Check for high/critical vulnerabilities HIGH_VULNS=$(cat $SCAN_OUTPUT_DIR/npm-audit.json | jq '.metadata.vulnerabilities.high // 0') CRITICAL_VULNS=$(cat $SCAN_OUTPUT_DIR/npm-audit.json | jq '.metadata.vulnerabilities.critical // 0') echo "High severity vulnerabilities: $HIGH_VULNS" echo "Critical severity vulnerabilities: $CRITICAL_VULNS" if [ $CRITICAL_VULNS -gt 0 ]; then echo "❌ Critical vulnerabilities found in NPM dependencies" npm audit --audit-level=critical exit 1 elif [ $HIGH_VULNS -gt 0 ]; then echo "âš ī¸ High severity vulnerabilities found in NPM dependencies" npm audit --audit-level=high else echo "✅ No high/critical NPM vulnerabilities found" fi - name: Composer Security Audit run: | echo "🔍 Running Composer security audit..." if [ -f composer.lock ]; then # Install security checker composer global require enlightn/security-checker # Run security check ~/.composer/vendor/bin/security-checker security:check composer.lock --format=json > $SCAN_OUTPUT_DIR/composer-audit.json || true # Check results if [ -s $SCAN_OUTPUT_DIR/composer-audit.json ]; then VULNS=$(cat $SCAN_OUTPUT_DIR/composer-audit.json | jq 'length') if [ $VULNS -gt 0 ]; then echo "❌ $VULNS vulnerability(ies) found in Composer dependencies" ~/.composer/vendor/bin/security-checker security:check composer.lock exit 1 else echo "✅ No Composer vulnerabilities found" fi fi else echo "â„šī¸ No composer.lock file found" fi - name: Upload Dependency Reports if: always() uses: actions/upload-artifact@v4 with: name: dependency-scan-reports path: ${{ env.SCAN_OUTPUT_DIR }} retention-days: ${{ env.RETENTION_DAYS }} secrets-scan: name: Secrets & Credential Scan runs-on: ubuntu-latest if: github.event.schedule == '0 2 * * *' || github.event_name == 'push' || github.event_name == 'pull_request' || github.event.inputs.scan_type == 'secrets' || github.event.inputs.scan_type == 'full' steps: - name: Checkout Code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Python uses: actions/setup-python@v4 with: python-version: '3.9' - name: Install Security Tools run: | pip install detect-secrets truffleHog3 - name: Detect Secrets Scan run: | echo "🔍 Running detect-secrets scan..." mkdir -p $SCAN_OUTPUT_DIR # Initialize baseline if it doesn't exist if [ ! -f .secrets.baseline ]; then detect-secrets scan --baseline .secrets.baseline fi # Run scan and compare with baseline detect-secrets scan --baseline .secrets.baseline --force-use-all-plugins # Audit results detect-secrets audit .secrets.baseline --report --output $SCAN_OUTPUT_DIR/secrets-report.json - name: TruffleHog Git History Scan run: | echo "🔍 Running TruffleHog git history scan..." # Scan git history for secrets trufflehog3 --format json --output $SCAN_OUTPUT_DIR/trufflehog-report.json . || true # Check for high-confidence findings if [ -f $SCAN_OUTPUT_DIR/trufflehog-report.json ]; then HIGH_CONFIDENCE=$(cat $SCAN_OUTPUT_DIR/trufflehog-report.json | jq '.[] | select(.confidence == "high") | length' | wc -l) if [ $HIGH_CONFIDENCE -gt 0 ]; then echo "❌ High-confidence secrets found in git history" cat $SCAN_OUTPUT_DIR/trufflehog-report.json | jq '.[] | select(.confidence == "high")' exit 1 else echo "✅ No high-confidence secrets found in git history" fi fi - name: WordPress Specific Secret Patterns run: | echo "🔍 Scanning for WordPress-specific secret patterns..." # WordPress salts/keys outside wp-config if find . -name "*.php" -not -path "./wp-config*" -exec grep -l "define.*\(AUTH_KEY\|SECURE_AUTH_KEY\|LOGGED_IN_KEY\|NONCE_KEY\|AUTH_SALT\|SECURE_AUTH_SALT\|LOGGED_IN_SALT\|NONCE_SALT\)" {} \; | grep -v vendor; then echo "❌ WordPress security keys found outside wp-config.php" exit 1 fi # Database credentials in files if grep -r -E "mysql://[^:]+:[^@]+@" --include="*.php" --include="*.js" --exclude-dir=vendor .; then echo "❌ MySQL connection strings with credentials found" exit 1 fi # FTP/SFTP credentials if grep -r -E "(ftp|sftp)://[^:]+:[^@]+@" --include="*.php" --include="*.js" --exclude-dir=vendor .; then echo "❌ FTP/SFTP credentials found" exit 1 fi echo "✅ WordPress-specific secret scan completed" - name: Upload Secrets Reports if: always() uses: actions/upload-artifact@v4 with: name: secrets-scan-reports path: | ${{ env.SCAN_OUTPUT_DIR }} .secrets.baseline retention-days: ${{ env.RETENTION_DAYS }} wordpress-security-scan: name: WordPress Security Analysis runs-on: ubuntu-latest if: github.event.schedule == '0 4 * * 0' || github.event.inputs.scan_type == 'wordpress' || github.event.inputs.scan_type == 'full' steps: - name: Checkout Code uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '8.1' tools: composer, phpcs - name: Install WordPress Security Tools run: | # Install PHPCS Security Audit composer global require automattic/phpcs-security-audit composer global require wp-coding-standards/wpcs # Configure PHPCS phpcs --config-set installed_paths ~/.composer/vendor/automattic/phpcs-security-audit,~/.composer/vendor/wp-coding-standards/wpcs # Install WPScan API (if needed for remote scans) # gem install wpscan - name: WordPress Coding Standards Security run: | echo "🔍 Running WordPress security coding standards..." mkdir -p $SCAN_OUTPUT_DIR # Run security-focused PHPCS phpcs --standard=Security --extensions=php --ignore=vendor/,node_modules/ --report=json --report-file=$SCAN_OUTPUT_DIR/phpcs-security.json . || true # Also run WordPress standards for additional checks phpcs --standard=WordPress --extensions=php --ignore=vendor/,node_modules/ --report=json --report-file=$SCAN_OUTPUT_DIR/phpcs-wordpress.json . || true # Parse results and fail on security issues if [ -f $SCAN_OUTPUT_DIR/phpcs-security.json ]; then SECURITY_ERRORS=$(cat $SCAN_OUTPUT_DIR/phpcs-security.json | jq '.totals.errors // 0') SECURITY_WARNINGS=$(cat $SCAN_OUTPUT_DIR/phpcs-security.json | jq '.totals.warnings // 0') echo "Security errors: $SECURITY_ERRORS" echo "Security warnings: $SECURITY_WARNINGS" if [ $SECURITY_ERRORS -gt 0 ]; then echo "❌ Security errors found in code" phpcs --standard=Security --extensions=php --ignore=vendor/,node_modules/ . exit 1 elif [ $SECURITY_WARNINGS -gt 0 ]; then echo "âš ī¸ Security warnings found in code" else echo "✅ No security issues found by PHPCS" fi fi - name: WordPress Plugin Specific Checks run: | echo "🔍 Running WordPress plugin-specific security checks..." # Check for direct file access protection if ! grep -r "if (!defined('ABSPATH'))" --include="*.php" . | wc -l | grep -q "^[1-9]"; then echo "âš ī¸ Some PHP files may be missing ABSPATH checks" fi # Check for proper nonce verification if grep -r "wp_verify_nonce\|check_admin_referer" --include="*.php" . | wc -l | grep -q "^0$"; then echo "âš ī¸ No nonce verification found - may be security issue" fi # Check for SQL injection vulnerabilities if grep -r "\\$wpdb->query.*\\$_" --include="*.php" .; then echo "❌ Potential SQL injection vulnerability found" exit 1 fi # Check for XSS vulnerabilities (unescaped output) if grep -r "echo.*\\$_\|print.*\\$_" --include="*.php" .; then echo "❌ Potential XSS vulnerability - unescaped output found" exit 1 fi # Check for file inclusion vulnerabilities if grep -r "include.*\\$_\|require.*\\$_" --include="*.php" .; then echo "❌ Potential file inclusion vulnerability found" exit 1 fi echo "✅ WordPress plugin security checks completed" - name: Upload WordPress Security Reports if: always() uses: actions/upload-artifact@v4 with: name: wordpress-security-reports path: ${{ env.SCAN_OUTPUT_DIR }} retention-days: ${{ env.RETENTION_DAYS }} code-analysis: name: Static Code Security Analysis runs-on: ubuntu-latest if: github.event.schedule == '0 4 * * 0' || github.event.inputs.scan_type == 'full' steps: - name: Checkout Code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Python uses: actions/setup-python@v4 with: python-version: '3.9' - name: Install Security Analysis Tools run: | pip install semgrep bandit safety - name: Semgrep Security Scan run: | echo "🔍 Running Semgrep security analysis..." mkdir -p $SCAN_OUTPUT_DIR # Run Semgrep with security rules semgrep --config=auto --json --output=$SCAN_OUTPUT_DIR/semgrep-results.json . || true # Parse results for critical issues if [ -f $SCAN_OUTPUT_DIR/semgrep-results.json ]; then CRITICAL_COUNT=$(cat $SCAN_OUTPUT_DIR/semgrep-results.json | jq '.results[] | select(.extra.severity == "ERROR") | length' | wc -l) HIGH_COUNT=$(cat $SCAN_OUTPUT_DIR/semgrep-results.json | jq '.results[] | select(.extra.severity == "WARNING") | length' | wc -l) echo "Critical security issues: $CRITICAL_COUNT" echo "High security issues: $HIGH_COUNT" if [ $CRITICAL_COUNT -gt 0 ]; then echo "❌ Critical security issues found by Semgrep" semgrep --config=auto --error . exit 1 elif [ $HIGH_COUNT -gt 0 ]; then echo "âš ī¸ High severity security issues found" else echo "✅ No critical security issues found by Semgrep" fi fi - name: Python Security Analysis (if applicable) run: | echo "🔍 Running Python security analysis..." # Check if there are any Python files if find . -name "*.py" -type f | grep -q .; then echo "Python files found, running Bandit..." bandit -r . -f json -o $SCAN_OUTPUT_DIR/bandit-results.json || true # Check for Python requirements file if [ -f requirements.txt ]; then echo "Checking Python dependencies with Safety..." safety check --json --output $SCAN_OUTPUT_DIR/safety-results.json || true fi else echo "No Python files found, skipping Python security analysis" fi - name: Upload Code Analysis Reports if: always() uses: actions/upload-artifact@v4 with: name: code-analysis-reports path: ${{ env.SCAN_OUTPUT_DIR }} retention-days: ${{ env.RETENTION_DAYS }} compliance-check: name: Security Compliance Validation runs-on: ubuntu-latest if: github.event.schedule == '0 4 * * 0' || github.event.inputs.scan_type == 'full' steps: - name: Checkout Code uses: actions/checkout@v4 - name: OWASP Top 10 Checklist run: | echo "🔍 Running OWASP Top 10 compliance check..." mkdir -p $SCAN_OUTPUT_DIR # A01:2021 – Broken Access Control echo "Checking for access control issues..." > $SCAN_OUTPUT_DIR/owasp-compliance.txt if grep -r "current_user_can\|wp_verify_nonce\|check_admin_referer" --include="*.php" . >> $SCAN_OUTPUT_DIR/owasp-compliance.txt; then echo "✅ Access control checks found" >> $SCAN_OUTPUT_DIR/owasp-compliance.txt else echo "âš ī¸ No access control checks found" >> $SCAN_OUTPUT_DIR/owasp-compliance.txt fi # A02:2021 – Cryptographic Failures echo "Checking cryptographic implementations..." >> $SCAN_OUTPUT_DIR/owasp-compliance.txt if grep -r "wp_hash\|wp_salt\|openssl_" --include="*.php" . >> $SCAN_OUTPUT_DIR/owasp-compliance.txt; then echo "✅ Cryptographic functions found" >> $SCAN_OUTPUT_DIR/owasp-compliance.txt fi # A03:2021 – Injection echo "Checking for injection vulnerabilities..." >> $SCAN_OUTPUT_DIR/owasp-compliance.txt if grep -r "prepare\|esc_sql\|sanitize_" --include="*.php" . >> $SCAN_OUTPUT_DIR/owasp-compliance.txt; then echo "✅ Input sanitization found" >> $SCAN_OUTPUT_DIR/owasp-compliance.txt else echo "âš ī¸ No input sanitization found" >> $SCAN_OUTPUT_DIR/owasp-compliance.txt fi # A04:2021 – Insecure Design echo "Checking for secure design patterns..." >> $SCAN_OUTPUT_DIR/owasp-compliance.txt # A05:2021 – Security Misconfiguration echo "Checking for security configuration..." >> $SCAN_OUTPUT_DIR/owasp-compliance.txt if [ -f .htaccess ]; then echo "✅ .htaccess file found" >> $SCAN_OUTPUT_DIR/owasp-compliance.txt fi # A06:2021 – Vulnerable and Outdated Components echo "Components checked by dependency scan" >> $SCAN_OUTPUT_DIR/owasp-compliance.txt # A07:2021 – Identification and Authentication Failures echo "Checking authentication mechanisms..." >> $SCAN_OUTPUT_DIR/owasp-compliance.txt if grep -r "wp_authenticate\|wp_login\|wp_logout" --include="*.php" . >> $SCAN_OUTPUT_DIR/owasp-compliance.txt; then echo "✅ Authentication functions found" >> $SCAN_OUTPUT_DIR/owasp-compliance.txt fi # A08:2021 – Software and Data Integrity Failures echo "Checking for integrity validation..." >> $SCAN_OUTPUT_DIR/owasp-compliance.txt # A09:2021 – Security Logging and Monitoring Failures echo "Checking for security logging..." >> $SCAN_OUTPUT_DIR/owasp-compliance.txt if grep -r "error_log\|wp_debug_log" --include="*.php" . >> $SCAN_OUTPUT_DIR/owasp-compliance.txt; then echo "✅ Logging functions found" >> $SCAN_OUTPUT_DIR/owasp-compliance.txt fi # A10:2021 – Server-Side Request Forgery (SSRF) echo "Checking for SSRF protection..." >> $SCAN_OUTPUT_DIR/owasp-compliance.txt if grep -r "wp_safe_remote_get\|wp_remote_get" --include="*.php" . >> $SCAN_OUTPUT_DIR/owasp-compliance.txt; then echo "✅ Safe remote request functions found" >> $SCAN_OUTPUT_DIR/owasp-compliance.txt fi - name: WordPress Security Best Practices run: | echo "🔍 Checking WordPress security best practices..." >> $SCAN_OUTPUT_DIR/owasp-compliance.txt # File permissions check (simulated) echo "File permissions should be checked on deployment" >> $SCAN_OUTPUT_DIR/owasp-compliance.txt # WordPress version check if grep -r "WordPress.*[0-9]\+\.[0-9]\+" README.md; then echo "✅ WordPress version documented" >> $SCAN_OUTPUT_DIR/owasp-compliance.txt fi # Security headers check if [ -f .htaccess ]; then if grep -q "X-Frame-Options\|X-XSS-Protection\|X-Content-Type-Options" .htaccess; then echo "✅ Security headers configured" >> $SCAN_OUTPUT_DIR/owasp-compliance.txt else echo "âš ī¸ Security headers not found in .htaccess" >> $SCAN_OUTPUT_DIR/owasp-compliance.txt fi fi - name: Upload Compliance Reports if: always() uses: actions/upload-artifact@v4 with: name: compliance-reports path: ${{ env.SCAN_OUTPUT_DIR }} retention-days: ${{ env.RETENTION_DAYS }} security-summary: name: Security Summary Report runs-on: ubuntu-latest needs: [dependency-scan, secrets-scan, wordpress-security-scan, code-analysis, compliance-check] if: always() steps: - name: Download All Reports uses: actions/download-artifact@v4 with: path: all-reports - name: Generate Security Summary run: | echo "📊 Generating security summary report..." mkdir -p final-report # Create summary report cat > final-report/security-summary.md << 'EOF' # Security Scan Summary Report **Scan Date:** $(date -u +"%Y-%m-%d %H:%M:%S UTC") **Repository:** ${{ github.repository }} **Branch:** ${{ github.ref_name }} **Commit:** ${{ github.sha }} ## Scan Results Overview | Component | Status | Critical | High | Medium | Low | |-----------|--------|----------|------|---------|-----| EOF # Process each scan result for report_dir in all-reports/*/; do if [ -d "$report_dir" ]; then report_name=$(basename "$report_dir") echo "Processing $report_name..." # Count issues by severity (this would need to be customized per tool) echo "| $report_name | ✅ | 0 | 0 | 0 | 0 |" >> final-report/security-summary.md fi done # Add recommendations cat >> final-report/security-summary.md << 'EOF' ## Recommendations 1. **Regular Updates**: Keep all dependencies updated 2. **Security Headers**: Implement proper security headers 3. **Input Validation**: Ensure all user input is validated and sanitized 4. **Access Control**: Implement proper WordPress capability checks 5. **Logging**: Implement security event logging ## Next Steps - Review all high/critical findings - Update vulnerable dependencies - Fix any security issues in custom code - Schedule regular security scans EOF echo "Security summary report generated" - name: Upload Final Security Report if: always() uses: actions/upload-artifact@v4 with: name: final-security-report path: | final-report/ all-reports/ retention-days: ${{ env.RETENTION_DAYS }} notify-security-team: name: Security Team Notification runs-on: ubuntu-latest needs: [security-summary] if: failure() || (success() && github.event.schedule == '0 4 * * 0') steps: - name: Prepare Notification run: | if [ "${{ needs.security-summary.result }}" = "failure" ] || [ "${{ needs.dependency-scan.result }}" = "failure" ] || [ "${{ needs.secrets-scan.result }}" = "failure" ] || [ "${{ needs.wordpress-security-scan.result }}" = "failure" ]; then ALERT_LEVEL="🚨 CRITICAL" MESSAGE="Critical security issues found in ${{ github.repository }}" else ALERT_LEVEL="📊 WEEKLY REPORT" MESSAGE="Weekly security scan completed for ${{ github.repository }}" fi echo "ALERT_LEVEL=$ALERT_LEVEL" >> $GITHUB_ENV echo "MESSAGE=$MESSAGE" >> $GITHUB_ENV - name: Send Notification run: | echo "$ALERT_LEVEL: $MESSAGE" echo "Repository: ${{ github.repository }}" echo "Branch: ${{ github.ref_name }}" echo "Commit: ${{ github.sha }}" echo "Workflow: ${{ github.workflow }}" echo "Run ID: ${{ github.run_id }}" # Additional notification methods can be implemented here: # - Slack webhook # - Discord webhook # - Email notification # - Security incident management system echo "Security team notification sent"