Logging and Detection Engineering

By Davy Rogers

Most logs tell you what happened. Good logs tell you who did it and whether it was malicious.

Debug logs: what happened. Security logs: who, why, whether malicious.

Security-useful logs

  1. Who - user, API key, IP
  2. What - action (login, download, permission change)
  3. Where - service, endpoint
  4. When - UTC, milliseconds
  5. Outcome - success/failure
  6. Context - request ID, tenant
{
  "timestamp": "2025-03-15T14:23:01.042Z",
  "event": "auth.login.success",
  "actor": { "userId": "u_8f3k2", "ip": "203.0.113.45" },
  "service": "auth-api",
  "traceId": "abc-123-def"
}

Event naming

Consistent, hierarchical: auth.login.failure, authz.permission.changed, resource.file.uploaded.

What to log

Always: Auth events, authz events, data access, config changes, rate limit triggers.

Never: Passwords, tokens, API keys, full card numbers, session token values.

Detection rules

name: Brute force
query: auth.login.failure | count by actor.ip | where count > 10
timeframe: 5m

Patterns:

  • Threshold: Failed logins > 5 in 2m
  • Anomaly: Login from unusual country
  • Sequence: Failed login → success → permission change
  • Absence: No backup in 24h

Map to MITRE ATT&CK: T1110 (Brute Force), T1078 (Valid Accounts), T1098 (Account Manipulation).

Implementation

// Pino
const logger = pino({
  redact: ['req.headers.authorization']
});

logger.info({ event: 'auth.login.success', actor: { userId, ip } });

Pipeline

App → Shipper → Aggregator → Detection → Alerts

Use Sigma rules for vendor-agnostic detection.

The takeaway

Structured logs. Consistent event names. Actor context. Never log creds. Map detection rules to ATT&CK. Test rules like code.

Want a professional to look at it?Get an AppSec Health Check.