Logs help developers diagnose failures and help security teams reconstruct important events. The same convenience can create a second problem: a log statement may copy passwords, session tokens, API keys, personal data, or confidential request contents into systems that were never meant to hold them.
Once sensitive data reaches a log, it can spread to collectors, search indexes, dashboards, exports, support tools, and backups. Access controls on the original application no longer define every place where that data can be read. A credential that was protected in a secret store may become exposed through a much broader logging path.
The defensive goal is not to make logs vague. It is to record enough information to answer operational and security questions without recording sensitive values that those questions do not require. This article explains how to make that decision at the point where events are designed, why redaction alone is not enough, and how to verify that sensitive data stays out of the logging pipeline.
Treat logging as another data flow
A useful mental model is that a log entry is not temporary debug text. It is data sent to another system.
Consider a sign-in request:
client
|
v
application ----> authentication service
|
v
log collector ----> search index ----> dashboardIf the application logs the complete request body, the password can cross into every downstream logging component even though the authentication service only needed it briefly to verify the user.
The trust boundary has changed. People and services that are allowed to search logs may now be able to read a value that application users never intended to expose to them.
A safer design starts by asking what question the event needs to answer. For a failed sign-in, operators may need to know when it happened, which account identifier was involved, which service handled it, and why authentication failed. They do not need the submitted password.
For example:
time=2026-09-09T02:15:04Z
event=authentication_attempt
account_id=8421
result=failed
reason=invalid_credentialThis event remains useful while avoiding the most sensitive input.
The core rule is: design the log schema from the investigation question, not from whatever data happens to be available in memory.
Start with the threat model
Keeping sensitive data out of logs mainly reduces accidental disclosure through the logging system.
The failure condition is simple: an application handles a sensitive value correctly during its main operation but copies that value into a secondary system with different readers, retention periods, exports, and backups.
This control is particularly relevant for values such as passwords, authentication tokens, private keys, recovery codes, and API credentials. These values can grant authority if disclosed, so logging them can turn read access to logs into an unintended authentication path.
Other sensitive data may not grant authority but can still create unnecessary exposure. Personal identifiers, financial details, private messages, or confidential business fields should be logged only when the operational purpose justifies it and the logging environment is designed to protect them.
Data minimization in logs does not protect a secret that is already exposed elsewhere. It does not replace access control on log systems, encryption where appropriate, retention limits, or protection against log tampering. It narrows a different risk: sensitive values should not enter a broad secondary data flow without a reason.
Prefer selecting fields over deleting dangerous ones
There are two common ways to build a log event from a request.
The first copies everything and then tries to remove known-sensitive fields:
copy request
remove password
remove access_token
remove card_number
write logThe second constructs the event from fields that were deliberately approved:
new event
add request_id
add account_id
add operation
add result
write logThe second model is easier to reason about because new application fields do not automatically become new log fields.
Suppose a request originally contains username and password. A redaction rule removes password, so the log appears acceptable. Six months later, a developer adds recovery_code to the request. If the logger serializes the whole request, the new value can begin flowing into logs before anyone updates the redaction list.
With explicit field selection, recovery_code is absent unless someone deliberately adds it to the event schema.
This is the same defensive principle used by allowlists elsewhere in security: when the safe set is small and understandable, selecting the allowed data is usually more robust than trying to enumerate every dangerous value that may appear now or later.
Separate identifiers from authenticators
Logs often need to identify which credential or session was involved without storing the credential itself.
For example, an API service may need to record that credential cred_73f2 made a request. It does not need to record the bearer token presented by that credential.
credential_id=cred_73f2
operation=invoice.read
result=allowedA non-secret credential identifier supports correlation and investigation. The secret authenticator remains outside the log.
The distinction matters because hashing an authenticator is not automatically a good substitute for an identifier. A hash can still be sensitive when the original value has low entropy or when the digest becomes a stable cross-system tracking value. More importantly, a system that already has a non-secret identifier does not need to transform the secret at all.
Prefer an identifier designed for logging and correlation. If a protocol or legacy system provides no such identifier, decide explicitly whether correlation is important enough to justify deriving one, and have that design reviewed in the context of the credential type and threat model.
Redaction is a safety net, not the primary design
Even well-designed event schemas can receive unexpected values. Framework middleware may log request headers. Exception handlers may include object representations. A third-party library may emit connection strings or URLs containing credentials.
Central redaction can reduce the impact of those mistakes. A logging layer might recognize fields named password, authorization, or api_key and replace their values before serialization.
For example:
authorization=[REDACTED]That is useful defense in depth, but it has limits.
A field-name rule cannot recognize every secret. A token may appear inside a URL, an exception message, a nested object, or a field with an unexpected name. Pattern matching also creates false positives and false negatives because many secret formats are not uniquely identifiable from text alone.
The stronger order of controls is therefore:
1. do not select sensitive data for the event
2. redact known dangerous fields at shared logging boundaries
3. restrict who can read retained logs
4. limit retention to what the use case requiresRedaction catches mistakes. It should not justify sending complete sensitive objects into the logger.
Be careful with errors and diagnostic logging
Sensitive data often enters logs through failure paths rather than ordinary event code.
Imagine a client library raises an error that includes the full request URL. If credentials were placed in the URL, logging the exception can disclose them even though the application never explicitly logged a credential field.
Likewise, debug helpers that serialize an entire request, configuration object, environment, or database record can bypass carefully designed structured events.
The practical response is to treat diagnostic paths as part of the same logging design. Review what exception objects contain before logging them. Avoid dumping complete request and configuration objects. Give developers specific safe fields they can add when they need more context.
Temporary debug logging deserves the same scrutiny as permanent logging. A statement intended to exist for ten minutes can still be collected, replicated, and retained after the original code is removed.
Decide what to do when logging cannot be sanitized
A logging pipeline can fail in awkward ways. A sanitizer may throw an error. Structured serialization may encounter an unexpected object. A component may be unable to determine whether a field is safe to record.
For security-sensitive events, the application should have a deliberate policy rather than silently falling back to raw data.
In many applications, dropping an unsafe field while preserving non-sensitive event metadata is preferable to emitting the original value. For example:
event=payment_update
request_id=7d18...
customer_id=[OMITTED]
logging_note=sensitive_field_unavailableThe exact policy depends on the event and operational requirements. Some environments may need to reject an operation if mandatory audit evidence cannot be produced safely; others should keep serving traffic while recording a reduced event. What should not happen is an automatic fallback from “sanitized logging failed” to “log the entire object instead.”
This trade-off should be tested because failure paths are where emergency logging shortcuts tend to appear.
Test the logging boundary with known markers
Code review can catch obvious logging mistakes, but verification should also exercise the running system.
In a test environment, submit distinctive non-production marker values through fields that must never be logged. Then perform the actions that could expose them: successful requests, validation failures, authentication failures, exceptions, retries, and background processing.
Search the logging destination for those markers. The important destination is not only local application output. Check the retained system that operators actually query, because collectors or middleware may add data after the application emits an event.
This test can reveal problems such as:
application event is clean
|
v
HTTP middleware logs headers
|
v
collector stores sensitive markerUse synthetic values that cannot authenticate to anything and do not resemble real personal data. The purpose is to prove that the logging path excludes known test markers, not to put real secrets into a test.
Automated tests can also assert that structured event objects contain an expected set of fields. That catches schema drift before a new request field silently appears in logs.
Plan for data that has already been logged
Preventing future exposure does not remove sensitive values that already exist in retained logs.
If a real credential has been logged, treat the credential as potentially exposed according to who and what could access the relevant logging path. Removing one visible log entry does not necessarily remove copies from indexes, exports, caches, replicas, or backups.
For an authentication secret, revocation or rotation is usually the important containment action because it removes the value’s future authority. Cleanup of retained copies is still useful where supported, but it should not be mistaken for revocation.
For non-credential sensitive data, response depends on the data type, where it propagated, retention capabilities, and organizational requirements. The general lesson is operational: logging systems have their own data lifecycle, so incident response must consider more than the application’s primary database.
Use stronger controls when the consequences justify them
A small internal service may be adequately served by explicit structured events, shared redaction, restricted log access, and short retention.
A system that handles highly sensitive data or grants broad log access may justify more defense in depth: separate log views, field-level access restrictions where the platform supports them, tighter export controls, automated detection for known secret formats, or separate destinations for events with different sensitivity.
Those controls add operational complexity. They are most useful after the application has reduced what it sends. A sophisticated logging platform cannot reliably compensate for an application that indiscriminately records complete requests and secrets.
The decision should follow the data and threat model: identify what the event must answer, record the minimum fields needed to answer it, and protect the retained result according to its remaining sensitivity.
Conclusion
Useful logs do not require complete copies of application state. They require carefully chosen evidence about events.
Start by defining the question each event should answer. Select only the fields needed for that question, use non-secret identifiers instead of authenticators, and treat shared redaction as a backup control rather than permission to log everything. Test failure and diagnostic paths with synthetic markers, and search the real retained destination to verify that excluded values stay excluded.
The practical security boundary is simple: a value should not gain a new audience and a new retention lifecycle merely because it passed through code that needed to log something nearby.