Skip to content
Back to skills

Logging Failures

ASecurity

This skill should be used when the user asks about "logging failures", "log injection", "insufficient logging", "audit logging", "security logging", "CWE-117", or needs to find logging-related vulnerabilities during whitebox security review.

  • 24 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 26, 2026
developmenttypescriptpythongojavaphpbashgitapisecurity

Works with

  • terminal
  • api

Security analysis

A100/100

Scanned May 27, 2026

npx -y skills add allsmog/vuln-scout --skill logging-failures --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Logging Failures?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Logging Failures
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/allsmog-logging-failures/badge)](https://www.skillsdirectory.com/skills/allsmog-logging-failures)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: Logging Failures
description: This skill should be used when the user asks about "logging failures", "log injection", "insufficient logging", "audit logging", "security logging", "CWE-117", or needs to find logging-related vulnerabilities during whitebox security review.
version: 1.0.0
---

# Logging & 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 Top 10 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

```bash
# 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**:
```python
# VULNERABLE: User input directly in log
logger.info(f"User login: {request.form['username']}")  # Can inject newlines
```

**Secure**:
```python
# SAFE: Structured logging
logger.info("User login", extra={"username": sanitize(username)})
```

#### Java

```bash
# 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**:
```java
// VULNERABLE: Direct concatenation
logger.info("User login: " + username);  // Can inject newlines
```

**Secure**:
```java
// SAFE: Parameterized logging
logger.info("User login: {}", sanitize(username));
```

#### Go

```bash
# 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**:
```go
// VULNERABLE: Direct formatting
log.Printf("User login: %s", userInput)  // Can inject newlines
```

**Secure**:
```go
// SAFE: Structured logging
logger.Info("user login", zap.String("username", sanitize(username)))
```

#### TypeScript

```bash
# Console/logger with concatenation
grep -rniE "console\.(log|info|error|warn).*\+|logger\.(log|info|error|warn).*\+" --include="*.ts"
```

#### PHP

```bash
# 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

```bash
# 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

```bash
# 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

```bash
# 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`, `pwd`
- `token`, `access_token`, `refresh_token`
- `api_key`, `apikey`, `secret_key`
- `credit_card`, `ccn`, `cvv`
- `ssn`, `social_security`
- `private_key`, `secret`
- Authorization headers
- Session IDs

### Secure Pattern - Field Redaction

```python
# 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
// 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

```bash
# 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

```bash
# 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)

```python
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)

```java
// Use MDC for structured context
MDC.put("userId", sanitize(userId));
MDC.put("action", "login");
logger.info("User authentication successful");
MDC.clear();
```

### Go (Zap)

```go
logger.Info("user authentication",
    zap.String("user_id", sanitize(userID)),
    zap.String("action", "login"),
    zap.Bool("success", true),
)
```

### TypeScript (Winston)

```typescript
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

```json
{
  "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 |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.