Logging Failures
Scannednpx machina-cli add skill allsmog/vuln-scout/logging-failures --openclawLogging & Alerting Failures (OWASP A09)
Purpose
Provide detection patterns for logging vulnerabilities including log injection, insufficient logging of security events, secrets in logs, and log tampering vulnerabilities.
OWASP 2025 Mapping
Category: A09 - Security Logging & Alerting Failures
CWEs:
- CWE-117: Improper Output Neutralization for Logs
- CWE-223: Omission of Security-Relevant Information
- CWE-532: Insertion of Sensitive Information into Log File
- CWE-778: Insufficient Logging
When to Use
Activate this skill when:
- Reviewing logging implementations
- Checking for log injection vulnerabilities
- Auditing security event logging
- Looking for secrets exposed in logs
- Verifying audit trail completeness
Log Injection (CWE-117)
Overview
Log injection occurs when user-controlled input is written to logs without sanitization, allowing attackers to inject fake log entries or manipulate log output.
Detection Patterns
Python
# String concatenation in logs
grep -rniE "logging\.(info|debug|error|warn).*\+|logger\.(info|debug|error|warn).*\+" --include="*.py"
# f-string/format in logs with user input
grep -rniE "logging\.(info|debug|error|warn).*f['\"]|logger\..*\.format\(" --include="*.py"
Vulnerable:
# VULNERABLE: User input directly in log
logger.info(f"User login: {request.form['username']}") # Can inject newlines
Secure:
# SAFE: Structured logging
logger.info("User login", extra={"username": sanitize(username)})
Java
# String concatenation in logs
grep -rniE "log\.(info|debug|error|warn).*\+|logger\.(info|debug|error|warn).*\+" --include="*.java"
# Format with user input
grep -rniE "String\.format.*log|log.*String\.format" --include="*.java"
Vulnerable:
// VULNERABLE: Direct concatenation
logger.info("User login: " + username); // Can inject newlines
Secure:
// SAFE: Parameterized logging
logger.info("User login: {}", sanitize(username));
Go
# Printf-style logging with user input
grep -rniE "log\.Printf|log\.Print.*\+" --include="*.go"
# Zap/logrus with user input
grep -rniE "zap\.String.*request|logrus\.WithField.*request" --include="*.go"
Vulnerable:
// VULNERABLE: Direct formatting
log.Printf("User login: %s", userInput) // Can inject newlines
Secure:
// SAFE: Structured logging
logger.Info("user login", zap.String("username", sanitize(username)))
TypeScript
# Console/logger with concatenation
grep -rniE "console\.(log|info|error|warn).*\+|logger\.(log|info|error|warn).*\+" --include="*.ts"
PHP
# error_log with user input
grep -rniE "error_log.*\$_|syslog.*\$_|log.*\$_(GET|POST|REQUEST)" --include="*.php"
Log Injection Payloads
# Inject fake log entry
username: legitimate_user\n[ERROR] Admin password changed by attacker
# Inject multiple lines
input: line1\n[INFO] Fake entry\n[DEBUG] More fake entries
# ANSI escape codes (terminal injection)
input: \x1b[2J\x1b[1;1H # Clear terminal
Insufficient Logging (CWE-778)
Overview
Missing logs for security-critical events prevents detection of attacks and incident response.
Events That MUST Be Logged
| Event Category | Specific Events |
|---|---|
| Authentication | Login success/failure, logout, password change |
| Authorization | Access denied, privilege escalation attempts |
| Input Validation | Rejected/suspicious input |
| Session | Session creation, destruction, timeout |
| Data Access | Sensitive data read/write/delete |
| Configuration | Settings changes, feature toggles |
| Errors | Exceptions, failures (without stack traces) |
Detection Patterns
# Find auth functions without logging
grep -rniE "def (login|authenticate|authorize|check_permission)" --include="*.py" -A 10 | grep -v "log\."
# Find exception handlers without logging
grep -rniE "except.*:|catch\s*\(" --include="*.py" --include="*.java" -A 5 | grep -v "log\|logger"
# Find permission checks without logging
grep -rniE "has_permission|is_admin|check_role" --include="*.go" --include="*.py" --include="*.java" -A 5 | grep -v "log"
What to Check
# Authentication logging
grep -rniE "login|authenticate|logout" --include="*.go" --include="*.py" --include="*.java" --include="*.ts" --include="*.php" | xargs -I {} sh -c 'grep -l "log" {} || echo "MISSING: {}"'
# Failed access logging
grep -rniE "forbidden|unauthorized|access.*denied" --include="*.go" --include="*.py" --include="*.java" --include="*.ts" --include="*.php"
# Data modification logging
grep -rniE "delete|update|insert" --include="*.go" --include="*.py" --include="*.java" --include="*.ts" --include="*.php" | xargs -I {} sh -c 'grep -l "log\|audit" {} || echo "MISSING: {}"'
Secrets in Logs (CWE-532)
Overview
Logging sensitive data (passwords, tokens, API keys) exposes them to anyone with log access.
Detection Patterns
# Password in logs
grep -rniE "log.*(password|passwd|pwd|secret|token|api_key|apikey|credential)" --include="*.go" --include="*.py" --include="*.java" --include="*.ts" --include="*.php"
# Request body logging (may contain secrets)
grep -rniE "log.*request\.body|log.*req\.body|log.*getBody" --include="*.go" --include="*.py" --include="*.java" --include="*.ts" --include="*.php"
# Full object logging
grep -rniE "log.*user\)|log.*%v.*user|log.*JSON\.stringify" --include="*.go" --include="*.py" --include="*.java" --include="*.ts" --include="*.php"
Sensitive Fields to Never Log
password,passwd,pwdtoken,access_token,refresh_tokenapi_key,apikey,secret_keycredit_card,ccn,cvvssn,social_securityprivate_key,secret- Authorization headers
- Session IDs
Secure Pattern - Field Redaction
# Python - Redact sensitive fields
SENSITIVE_FIELDS = ['password', 'token', 'api_key', 'secret']
def redact_sensitive(data: dict) -> dict:
return {k: '***REDACTED***' if k.lower() in SENSITIVE_FIELDS else v
for k, v in data.items()}
logger.info("User data", extra=redact_sensitive(user_data))
// Go - Redact sensitive fields
func redactSensitive(data map[string]interface{}) map[string]interface{} {
sensitive := []string{"password", "token", "api_key"}
for _, key := range sensitive {
if _, exists := data[key]; exists {
data[key] = "***REDACTED***"
}
}
return data
}
Log Tampering
Overview
If logs can be modified or deleted, attackers can cover their tracks.
Detection Patterns
# Predictable log file paths
grep -rniE "logfile\s*=|LOG_FILE\s*=|log_path\s*=" --include="*.go" --include="*.py" --include="*.java" --include="*.ts" --include="*.php" --include="*.env"
# User-controlled log paths
grep -rniE "log.*request\.(path|param|query)" --include="*.go" --include="*.py" --include="*.java" --include="*.ts" --include="*.php"
# Log rotation without integrity
grep -rniE "RotatingFileHandler|logrotate|rotate.*log" --include="*.go" --include="*.py" --include="*.java" --include="*.conf"
Secure Patterns
- Write logs to append-only storage
- Use centralized logging (SIEM)
- Implement log integrity verification (signing)
- Restrict log file permissions
- Use remote logging to prevent local tampering
Missing Alerting
Overview
Logs without alerts allow attacks to go unnoticed.
Events That Should Alert
| Event | Alert Priority |
|---|---|
| Multiple failed logins | HIGH |
| Admin actions | MEDIUM |
| Privilege escalation | CRITICAL |
| Sensitive data access | HIGH |
| Configuration changes | MEDIUM |
| Error rate spike | HIGH |
| Unusual access patterns | MEDIUM |
Detection Patterns
# Check for alerting configuration
grep -rniE "alert|notify|pagerduty|slack.*webhook|email.*notify" --include="*.go" --include="*.py" --include="*.java" --include="*.ts" --include="*.yaml" --include="*.json"
# Check for threshold-based alerts
grep -rniE "threshold|rate_limit|max_attempts|lockout" --include="*.go" --include="*.py" --include="*.java" --include="*.ts" --include="*.php"
Language-Specific Secure Logging
Python (structlog)
import structlog
logger = structlog.get_logger()
# Structured with automatic sanitization
logger.info(
"user_login",
username=sanitize(username),
ip_address=request.remote_addr,
success=True
)
Java (SLF4J + Logback)
// Use MDC for structured context
MDC.put("userId", sanitize(userId));
MDC.put("action", "login");
logger.info("User authentication successful");
MDC.clear();
Go (Zap)
logger.Info("user authentication",
zap.String("user_id", sanitize(userID)),
zap.String("action", "login"),
zap.Bool("success", true),
)
TypeScript (Winston)
logger.info('user authentication', {
userId: sanitize(userId),
action: 'login',
success: true,
timestamp: new Date().toISOString()
});
Log Format Requirements
A secure log entry should include:
| Field | Purpose |
|---|---|
| Timestamp | When (ISO 8601) |
| Level | Severity (INFO, WARN, ERROR) |
| Source | Where (service, file, function) |
| User | Who (user ID, not PII) |
| Action | What happened |
| Resource | What was accessed |
| Outcome | Success/failure |
| Request ID | Correlation |
| IP Address | Origin |
Example Secure Log Format
{
"timestamp": "2025-01-15T10:30:00Z",
"level": "INFO",
"service": "auth-service",
"event": "user_login",
"user_id": "usr_12345",
"action": "authenticate",
"outcome": "success",
"request_id": "req_abc123",
"ip_address": "192.168.1.1",
"user_agent": "Mozilla/5.0..."
}
Verification Checklist
- Log injection prevented (sanitized input)
- Authentication events logged
- Authorization failures logged
- Data access logged
- Sensitive data redacted
- Logs written to secure location
- Log integrity protected
- Alerting configured for critical events
- Log retention policy defined
CWE References
| CWE | Name | Example |
|---|---|---|
| CWE-117 | Log Injection | Newlines in log messages |
| CWE-223 | Omission of Info | Missing auth failure logs |
| CWE-532 | Secrets in Logs | Passwords logged |
| CWE-778 | Insufficient Logging | No audit trail |
Source
git clone https://github.com/allsmog/vuln-scout/blob/main/whitebox-pentest/skills/logging-failures/SKILL.mdView on GitHub Overview
This skill helps detect log injection, insufficient logging of security events, and secrets in logs during whitebox pentesting. It aligns with OWASP A09 and CWE-117, CWE-223, CWE-532, and CWE-778, and provides practical detection patterns and concrete examples across languages.
How This Skill Works
It analyzes code for unsanitized user input written to logs, provides language-specific detection patterns and commands, and contrasts vulnerable versus secure logging patterns. It also highlights which security events should be logged to maintain a complete audit trail.
When to Use It
- Reviewing logging implementations for potential log injection and output neutralization issues
- Auditing security event logging to ensure traceability and completeness
- Searching for secrets or sensitive data exposed in logs
- Verifying audit trails for authentication, authorization, session, and data access events
- Assessing risk of log tampering and insufficient logging during pentesting
Quick Start
- Step 1: Identify inputs and events that are logged, focusing on authentication, authorization, session, and data access
- Step 2: Apply language-specific safe logging patterns (structured logging, redaction, and sanitization)
- Step 3: Run the provided detection commands and run an audit to confirm log integrity and coverage of critical events
Best Practices
- Sanitize user input before writing to logs
- Use structured logging with redacted or sanitized fields
- Avoid logging secrets; redact or encrypt sensitive data
- Prefer parameterized or structured logging instead of string concatenation
- Regularly test logs for completeness and integrity, including tamper-evidence and retention controls
Example Use Cases
- Python vulnerable: direct user input appears in logs via f-string-style logging
- Python secure: use structured logging and log extra sanitized fields
- Java vulnerable: log calls concatenate strings with user input
- Java secure: use parameterized logging with sanitized input
- Go vulnerable: direct formatting of user input in logs vs Go-style structured logging