SecLab
Logging, Error Handling & ResponseconceptDifficulty 2/520 min

What to log, and what never to log

Objective: After this lesson you can say, for any event, which fields a log line must carry and which it must never carry.

V16A09:2025info-disclosure
Step 1 of 4 · read6 min

Logs exist to answer a question at 2am

The question that decides what to log is not "is this useful" but "at 2am, during an incident, what question do I need to answer?"

Those three questions, and they determine the mandatory fields:

The 2am questionRequired fields
Who did this?userId (an internal identifier, not an email), sessionId, source IP
What did they do, to what?The action name, the object type and its id, the outcome
When, and in what context?A timestamp with timezone, a traceId to stitch services together

traceId is the most-omitted and most valuable field in a multi-service architecture: without it, "one request failed" is three log lines in three services you cannot connect.

Security events that must be logged, this being ASVS V16's list compressed:

  • Successful and failed logins (failures matter more)
  • Password changes, email changes, MFA enable/disable
  • Any change to anybody's permissions or roles
  • Denied access attempts — the one log line that detects probing
  • Reads or exports of sensitive data in unusual volume
  • Every admin action on another user's data

The fourth deserves emphasis: denied-access logs have the highest detection value. A user receiving 200 403s in one minute is an unambiguous signal; without logging it, m2-challenge detects nothing.

And the never-log list:

Never logWhy

Passwords, including wrong ones | Users type another site's password into yours | Tokens, session ids, API keys, refresh tokens | Your logs become a credential store | Card numbers, CVV, health data, national ID | Legal obligations, and logs live 90 days with many readers | The entire request body | It contains everything above, uncontrollably |

That last row causes the most incidents, because it is added for debugging and looks harmless: _logger.LogDebug("request: {Body}", body). It records every password, every token, every card number passing through that endpoint, and it stays because LogDebug "does not run in production" — until the day somebody raises the log level to investigate an incident.

View path

Comments

Join the discussion
Sign up to comment

Commenting needs an account with at least one completed lesson. That condition is what keeps this thread worth reading: every point belongs to someone who can be asked back, and reputation accrues over time.

Sign upSign in

You can still read every comment below without an account. Signing in brings you back to this exact spot, not to the top of the page.

Loading comments…