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 |