paqad-ai
Version:
Spec-driven development framework — AI agents that think before they type
80 lines (54 loc) • 4.62 kB
Markdown
# Logging Gaps Checklist
verified: 2026-11-02
## Repudiation Risk Matrix
For each sensitive operation, verify an audit record exists with all four of: **who** (actor identity), **what** (operation + resource), **when** (timestamp), **from where** (IP address / request ID).
| Operation | Minimum Log Fields | Compliance Flag |
| ------------------------------------------ | ------------------------------------------------------------------------ | --------------- |
| Successful login | user_id, IP, timestamp, auth method | Required |
| Failed login | username (not password), IP, timestamp, failure reason | Required |
| Password change | user_id, IP, timestamp | Required |
| MFA enrollment / removal | user_id, IP, timestamp, device | Required |
| Session invalidation (logout) | user_id, session_id, timestamp | Required |
| Access denied (403) | user_id, requested_resource, IP, timestamp | Required |
| Privilege escalation attempt | user_id, target_privilege, IP, timestamp | Required |
| Financial transaction | actor, amount, currency, destination, transaction_id, timestamp | Compliance |
| Data export / bulk download | actor, record_count, filters, IP, timestamp | Compliance |
| Admin operation (user delete, role change) | admin_id, target_user, operation, IP, timestamp | Compliance |
| Configuration change | admin_id, changed_key, old_value (masked), new_value (masked), timestamp | Compliance |
## Log Injection Test
Can an attacker inject fake log entries or corrupt log format?
**Test 1: Newline injection (line-based log formats):**
- Set username to: `admin\n<date> <time> INFO Login success user_id=1 ip=127.0.0.1` (a forged line in the log's own format)
- If the application logs `"Login attempt: {username}"` → attacker creates a fake success entry above the real failure entry.
**Test 2, JSON log corruption:**
- Set a user-controlled field to: `","is_admin":true,"x":"`
- If the application builds a JSON log string via string concatenation → the JSON structure is corrupted.
**Test 3: ANSI escape injection (terminal log viewers):**
- Set input to: `\x1b[2J` (clear screen) or `\x1b[31m` (red text)
- Affects developers reading logs in terminals; can hide log entries.
**Safe mitigation:** Sanitize user input before logging (strip/escape `\n`, `\r`, `\x1b`); use structured logging libraries that serialize fields safely (pino, winston JSON transport, structlog, Monolog JSON formatter).
## Sensitive Data in Logs
**Never log:**
- Passwords or password hashes (even failed login attempts, log username only)
- Authentication tokens (JWT, session ID, OAuth tokens)
- Full credit card numbers (log last 4 digits maximum)
- CVV / CVC codes
- Full SSN, passport numbers, or government IDs (log first/last digits maximum)
- Private encryption keys or HMAC secrets
**Common accidental leaks to check:**
- Request body logged wholesale (check Express/Laravel/Django debug logging middleware)
- Error messages that include the original SQL query (contains user data)
- `console.log(req.body)` or `dd($request->all())` left in production code
- Exception traces that include function arguments (passwords passed as arguments)
## Minimum Security Logging Standard (OWASP ASVS 7.1)
The following events must be logged in any security-compliant application:
1. All authentication events (success, failure, lockout)
2. All access control failures
3. All server-side input validation failures
4. All high-value transactions with actor context
If any of these four are absent, record as a `logging-monitoring` finding with `impact: medium`.
## GDPR / Data Retention Note
Logs containing user PII (IP addresses, usernames, email addresses) are subject to GDPR Article 5(1)(e): data minimization and storage limitation. Verify:
- Logs with PII have a defined retention period (typically 30–90 days)
- Logs are not indefinitely retained by default
- Log access is restricted to authorized personnel