OWASP Top 10:2025 Technical Verification Standard
WebOTG Hub v4.2
WebOTG-LOG-001 • Audit Logging & SIEM Alerting Guide

A09:2025 — Security Logging & Alerting Failures

Without logging and alerting, breaches cannot be detected. Insufficient logging, detection, monitoring, and active incident response allow attackers to sustain persistence, pivot to deeper systems, and manipulate or exfiltrate data undetected.

OWASP Standard
A09:2025
Primary CWEs
CWE-778, CWE-117, CWE-532
Risk Severity
High (CVSS 7.2)
Verification Target
Audit Trails, SIEM, Sanitization

01 Logging Flaws & Detection Blindspots

Applications suffer from logging and monitoring failures under several critical conditions:

  • Unlogged Auditable Events: Failed login attempts, password changes, high-value financial transactions, and privilege grants not recorded in persistent audit stores.
  • Log Injection (CWE-117): Logging unescaped user input containing carriage return/line feed (CRLF) characters, enabling attackers to forge log entries or corrupt log parsers.
  • PII / Secret Exposure in Logs (CWE-532): Writing credit card numbers, passwords, API keys, or session tokens into application log files.
  • Absence of Real-Time Alerting: Security events logged locally but never ingested by a SIEM or triggering incident response alerts.

02 Vulnerability Demonstration: Log Injection

Vulnerable Implementation: Unsanitized String Logging

vulnerable_logger.phpPHP
// VULNERABLE: Direct concatenation of user input into raw flat-file log
function logLoginAttempt($username) {
    // If username contains "\n2026-08-31 INFO [Auth] Admin logged in", an attacker fakes log lines
    $logLine = date('Y-m-d H:i:s') . " [WARN] Failed login for user: " . $username . "\n";
    file_put_contents('/var/log/app/auth.log', $logLine, FILE_APPEND);
}

03 Audit & Static Code Analysis Rules

Anti-Pattern Grep / AST Pattern Remediation
Raw file log writes file_put_contents\(.*log|error_log\(.*\$_(GET|POST) Use Structured Logger (Monolog / Winston)
Secret Logging log.*(password|secret|token|card_num) Context Redaction & Token Masking

04 Structured JSON Logging & Centralized Ingestion

Standardized Structured JSON Security Logger

secure_logger.phpPHP 8+
class SecurityAuditLogger {
    private string $logPath;

    public function recordSecurityEvent(string $eventType, int $userId, array $context = []): void {
        // Redact any sensitive field keys automatically
        $redactedContext = $this->redactSensitiveKeys($context);

        $payload = [
            '@timestamp' => gmdate('Y-m-d\TH:i:s\Z'),
            'event'      => [
                'category' => 'authentication',
                'action'   => $eventType,
                'outcome'  => $context['outcome'] ?? 'unknown'
            ],
            'user'       => [
                'id' => $userId,
            ],
            'client'     => [
                'ip' => $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'
            ],
            'context'    => $redactedContext
        ];

        // Output as single-line JSON to prevent CRLF injection
        $line = json_encode($payload, JSON_UNESCAPED_SLASHES) . "\n";
        file_put_contents('/var/log/app/security_audit.json', $line, FILE_APPEND | LOCK_EX);
    }

    private function redactSensitiveKeys(array $data): array {
        $sensitive = ['password', 'token', 'cvv', 'card', 'secret'];
        foreach ($data as $k => $v) {
            if (in_array(strtolower($k), $sensitive, true)) {
                $data[$k] = '[REDACTED]';
            }
        }
        return $data;
    }
}

05 Verification & Compliance Checklist

Logging Control Standard Status
Event Coverage All auth failures, access denials, and privilege changes logged. Enforced
JSON Format 100% of audit logs output formatted JSON to prevent CRLF forging. Enforced
Centralized SIEM Logs shipped to centralized OpenSearch/Elasticsearch with real-time alerting. Enforced