What is Sensitive Data Exposure in Logs?
Sensitive data in logs occurs when an application writes security-critical or privacy-sensitive information to log files, including: passwords, authentication tokens (JWT, API keys, session IDs), credit card or bank account numbers, personally identifiable information (PII), health information (PHI), and encryption keys.
Logs are typically retained for extended periods, replicated to SIEM systems, backed up to less-secure storage, and accessed by a wider audience than production databases. Data that is carefully protected in a database may be freely readable in log files. Compliance frameworks (PCI-DSS, HIPAA, GDPR) explicitly prohibit logging certain categories of data.
How this occurs
Sensitive data enters logs via multiple paths:
- Debugging code left in production โ
log.Debug("User password: " + password) - Logging entire request/response bodies โ Middleware that logs HTTP payloads containing form fields or JSON with passwords
- Exception messages โ Stack traces that include method arguments containing sensitive values
- ORM/database logging โ Query loggers that record parameterized values alongside SQL statements
Vulnerable code examples
Java โ direct password logging
// VULNERABLE: Password written to log
public void authenticate(String username, String password) {
log.debug("Authenticating user: {} with password: {}", username, password);
// ...
}
C# โ full request body logging
// VULNERABLE: HTTP middleware logging entire request body โ may include passwords, tokens
app.Use(async (context, next) => {
context.Request.EnableBuffering();
var body = await new StreamReader(context.Request.Body).ReadToEndAsync();
_logger.LogDebug("Request body: {Body}", body); // Logs passwords from login forms
context.Request.Body.Position = 0;
await next();
});
Node.js โ JWT token in log
// VULNERABLE: Full Authorization header (bearing the JWT) logged
app.use((req, res, next) => {
console.log(`${req.method} ${req.path} - Auth: ${req.headers.authorization}`);
next();
});
Secure code examples
Java โ log username only, never password
// SECURE: Log only non-sensitive fields; omit credentials entirely
public void authenticate(String username, String password) {
log.debug("Authentication attempt for username: {}", username);
// password is never referenced in any log statement
}
C# โ selective request logging with field masking
// SECURE: Log only safe request metadata; mask or exclude sensitive fields
app.Use(async (context, next) => {
_logger.LogInformation("Request: {Method} {Path} from {IP}",
context.Request.Method,
context.Request.Path,
context.Connection.RemoteIpAddress);
// Body NOT logged โ or if needed, parse and redact sensitive fields first
await next();
});
Python / Django โ structured logging with field exclusion
import logging
import re
logger = logging.getLogger(__name__)
SENSITIVE_FIELDS = {'password', 'token', 'secret', 'api_key', 'credit_card', 'ssn'}
def safe_log_dict(data: dict) -> dict:
"""Return a copy of dict with sensitive values masked."""
return {
k: '***REDACTED***' if k.lower() in SENSITIVE_FIELDS else v
for k, v in data.items()
}
def login_view(request):
data = request.POST.dict()
logger.info("Login attempt: %s", safe_log_dict(data)) # password โ ***REDACTED***
What Offensive360 detects
- Password/secret in log calls โ Log statements where the argument is a variable named
password,secret,token,apiKey,credential, etc. - Full request body logging โ Middleware or interceptors that log HTTP request/response bodies without field filtering
- Exception logging with sensitive arguments โ
log.error(e)where exception messages may contain parameter values - SQL query logging with values โ ORM or JDBC logging configurations that record query parameters
Remediation guidance
-
Never log passwords or secrets โ Under any circumstances, at any log level. Remove all such statements from both production and debug paths.
-
Mask sensitive fields in structured logs โ When logging request/response data, parse the payload and replace sensitive field values with
[REDACTED]before writing. -
Avoid logging full request bodies โ If request logging is required for debugging, log only metadata (method, path, status, timing) and exclude body content.
-
Disable verbose ORM/query logging in production โ Hibernate, Entity Framework, and SQLAlchemy query loggers can expose parameter values. Restrict to development environments only.
-
Audit log retention and access โ Ensure log files are stored with appropriate access controls, encrypted at rest, and retained only as long as required by policy.