API access audit-logged
Why it matters
Audit logs are the difference between detecting a breach in hours and discovering it months later during an external notification. CWE-778 (Insufficient Logging) and OWASP API Security Top 10 2023 API9 (Improper Inventory Management / Insufficient Logging & Monitoring) both flag missing logs as an incident response failure, not just a monitoring gap. OWASP A09 2021 (Security Logging and Monitoring Failures) is one of the top-10 precisely because log absence is correlated with breach longevity. SOC 2 CC7.2, PCI DSS Requirement 10, and HIPAA audit controls all require API access to be logged with user, resource, and outcome. Logs with passwords or tokens embedded become a secondary breach surface — redact before writing.
Severity rationale
Info severity because missing audit logs don't enable attacks directly, but they prevent detection and forensic reconstruction when other controls fail.
Remediation
Add a structured logging middleware that writes one JSON line per request with user, endpoint, method, status, and duration. Redact sensitive fields before writing — never log Authorization headers, request bodies containing passwords, or PII.
// src/middleware.ts
export function middleware(req: NextRequest) {
const start = Date.now()
const res = NextResponse.next()
res.headers.set('x-request-start', String(start)) // pass to route for duration calc
return res
}
// src/lib/audit-log.ts
export function logApiAccess({
userId, method, path, statusCode, durationMs
}: AuditEntry) {
const entry = {
timestamp: new Date().toISOString(),
userId: userId ?? 'anonymous',
method, path, statusCode, durationMs
// DO NOT include: headers, body, tokens, passwords
}
// Write to structured log sink (stdout for Vercel/CloudWatch pickup)
console.log(JSON.stringify(entry))
}
Ship logs to a persistent sink (CloudWatch, Datadog, Logtail) — in-memory logs are lost on restart.
Detection
-
ID:
audit-logging -
Severity:
info -
What to look for: Enumerate every relevant item. Check whether API requests are being logged with user ID, endpoint, timestamp, and response code. Verify that sensitive data (passwords, tokens, PII) are redacted from logs.
-
Pass criteria: At least 1 of the following conditions is met. API requests are logged with user, endpoint, timestamp, and response code. Sensitive data is redacted. Logs are persistent and can be queried for security audits.
-
Fail criteria: No logging of API requests, or logs include sensitive information like passwords or full request/response bodies.
-
Skip (N/A) when: The API is internal-only and audit logging is not required.
-
Detail on fail:
"No API request logging configured"or"Request logs include full request bodies with sensitive data"or"Logs stored in memory and cleared on restart — not persistent" -
Remediation: Implement structured audit logging:
const auditLog = (req, res, next) => { const startTime = Date.now() res.on('finish', () => { const duration = Date.now() - startTime const logEntry = { timestamp: new Date().toISOString(), userId: req.user?.id || 'anonymous', method: req.method, endpoint: req.path, statusCode: res.statusCode, duration } console.log(JSON.stringify(logEntry)) // Store in persistent logging service (e.g., CloudWatch, ELK Stack) }) next() } app.use(auditLog)
External references
- cwe · CWE-778 — Insufficient Logging
- cwe · CWE-532 — Insertion of Sensitive Information into Log File
- owasp:2021 · A09 — Security Logging and Monitoring Failures
- owasp:2023 · API9 — Improper Inventory Management
Taxons
History
- 2026-04-18·v1.0.0·Initial import from api-security·automated