From vuln-scout
Detects logging failures including log injection (CWE-117), insufficient logging, secrets in logs, and audit trail issues in Python, Java, Go, TypeScript, and PHP during whitebox pentesting.
How this skill is triggered — by the user, by Claude, or both
Slash command
/vuln-scout:logging-failuresThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Provide detection patterns for logging vulnerabilities including log injection, insufficient logging of security events, secrets in logs, and log tampering vulnerabilities.
Provide detection patterns for logging vulnerabilities including log injection, insufficient logging of security events, secrets in logs, and log tampering vulnerabilities.
Category: A09 - Security Logging & Alerting Failures
CWEs:
Activate this skill when:
Log injection occurs when user-controlled input is written to logs without sanitization, allowing attackers to inject fake log entries or manipulate log output.
# 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)})
# 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));
# 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)))
# Console/logger with concatenation
grep -rniE "console\.(log|info|error|warn).*\+|logger\.(log|info|error|warn).*\+" --include="*.ts"
# error_log with user input
grep -rniE "error_log.*\$_|syslog.*\$_|log.*\$_(GET|POST|REQUEST)" --include="*.php"
# 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
Missing logs for security-critical events prevents detection of attacks and incident response.
| 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) |
# 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"
# 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: {}"'
Logging sensitive data (passwords, tokens, API keys) exposes them to anyone with log access.
# 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"
password, passwd, pwdtoken, access_token, refresh_tokenapi_key, apikey, secret_keycredit_card, ccn, cvvssn, social_securityprivate_key, secret# 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
}
If logs can be modified or deleted, attackers can cover their tracks.
# 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"
Logs without alerts allow attacks to go unnoticed.
| 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 |
# 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"
import structlog
logger = structlog.get_logger()
# Structured with automatic sanitization
logger.info(
"user_login",
username=sanitize(username),
ip_address=request.remote_addr,
success=True
)
// Use MDC for structured context
MDC.put("userId", sanitize(userId));
MDC.put("action", "login");
logger.info("User authentication successful");
MDC.clear();
logger.Info("user authentication",
zap.String("user_id", sanitize(userID)),
zap.String("action", "login"),
zap.Bool("success", true),
)
logger.info('user authentication', {
userId: sanitize(userId),
action: 'login',
success: true,
timestamp: new Date().toISOString()
});
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 |
{
"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..."
}
| 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 |
npx claudepluginhub allsmog/vuln-scout --plugin whitebox-pentestDetects missing security event logs, logged secrets, and CRLF log injection. Apply when writing logging code, audit trails, error handlers, or authentication event recording.
Analyzes PHP code for OWASP A09:2021 logging failures: log injection, PII/sensitive data exposure, missing audit trails for security events like password resets.
Guides structured security logging for auth flows, admin actions, and access denials to enable detection, forensics, and incident response.