Secrets in Logs: The Silent Credential Leak Most Teams Never Check
June 17, 2026
The Leak You're Probably Not Scanning
Most secret-scanning conversations focus on source code: .env files committed to Git, hardcoded keys in mobile apps, credentials baked into Docker images. Those are real risks. But there's a quieter channel that leaks credentials just as reliably — and that almost no team audits — application and infrastructure logs.
Logs are designed to capture everything useful for debugging. The problem is that "everything useful" often includes authorization headers, database connection strings, OAuth tokens, and full API request URLs — complete with secrets embedded in query parameters. Those log lines then flow into log aggregators, object storage buckets, SIEM platforms, and third-party observability tools, multiplying the blast radius of every accidental capture.
How Secrets Actually End Up in Logs
Understanding the common patterns makes it much easier to audit and fix them.
1. Full HTTP Request / Response Logging
Framework-level request loggers — Express middleware, Django's DEBUG=True mode, Spring Boot Actuator with verbose settings — can dump entire request objects. If a client sends an API key as a query parameter (e.g., ?api_key=sk_live_...) or in the request body, it lands verbatim in your logs.
2. Exception Stack Traces
When an SDK call fails — say, an AWS SDK call with a bad credential — the exception message frequently includes the credential that was tried. Unhandled exception handlers that log err.toString() or the full exception object are a common culprit.
3. Environment Variable Dumps
Startup scripts that log the full process environment for debugging (console.log(process.env), os.environ, ENV.inspect) capture every secret loaded at runtime. This pattern appears surprisingly often in containerized apps where developers want to confirm variables are injected correctly.
4. Database Connection String Logging
ORMs and connection pool libraries sometimes log the connection string on startup or on connection failure. A typical PostgreSQL DSN looks like postgres://app_user:S3cr3tP4ss@db.internal:5432/prod — password included.
5. Third-Party SDK Verbose Modes
Payment SDKs, analytics clients, and communication APIs often have a verbose or debug flag that logs outbound HTTP calls in full, including authorization headers. This mode gets enabled during development and quietly stays on in production.
Where Captured Secrets Go Next
The exposure doesn't stop at your application server. Logs travel:
- Log aggregators (Datadog, Splunk, Elastic, Grafana Loki) — often with broad access for the engineering org and long retention windows.
- Cloud object storage (S3, GCS) — log archives with misconfigured bucket policies are a historically well-documented source of data exposure.
- CI/CD build logs — printed to stdout during build steps, often readable by everyone in the org and sometimes publicly accessible on open-source repositories.
- Crash-reporting tools (Sentry, Bugsnag) — if the exception object includes credential fields and you log the full breadcrumb trail, those secrets are now in a third-party SaaS.
Each hop is a new access control boundary to maintain — and a new potential breach point.
How to Audit Your Logs for Exposed Secrets
Here's a practical process you can run today:
- Pull a representative log sample. Grab 24–48 hours of logs from your production environment. Pipe them to a local file if your aggregator allows export.
-
Run regex searches for common secret shapes. Useful starting patterns:
# AWS Access Key IDs grep -E 'AKIA[0-9A-Z]{16}' app.log # Generic bearer tokens in headers grep -iE 'authorization:\s*bearer\s+[a-z0-9\-_\.]{20,}' app.log # Stripe live keys grep -E 'sk_live_[0-9a-zA-Z]{24,}' app.log # Connection strings with passwords grep -E '[a-z]+://[^:]+:[^@]{6,}@' app.log # Query-parameter API keys (common pattern) grep -iE '[?&](api_key|apikey|token|secret|password)=[^&\s]{8,}' app.log -
Check your CI/CD build logs. Search for the same patterns in archived pipeline output. Many teams forget that
printenvorenvcommands run during debugging steps never got removed. - Review your log aggregator's access controls. Who has query access? Is retention set longer than your secret rotation cadence? Are logs exported to cold storage with separate permissions?
- Audit third-party integrations. Check whether your crash reporter, APM tool, or observability platform has a "scrub sensitive fields" or PII redaction feature — and whether it's actually enabled.
Fixes: Stopping Secrets from Entering Logs in the First Place
Redact at the Logger Level
Most structured logging libraries support redaction or masking. In pino (Node.js), you can specify redact paths:
const logger = pino({
redact: ['req.headers.authorization', 'body.password', 'body.api_key']
});
In Logback (Java), a custom PatternLayout with a masking converter can strip patterns before they're written. Configure this once at the framework level rather than trusting every developer to remember.
Never Log Raw Request Objects
Avoid logger.debug(req) or logger.info(request.params) in full. Instead, construct an explicit allow-list of fields worth logging — route, method, status code, duration, correlation ID — and log only those.
Sanitize Exception Messages Before Logging
Wrap SDK calls in a thin exception handler that strips known-sensitive fields from the error message before passing it to your logger. For example, scrub the credential from an AWS SDK InvalidClientTokenId error before logging the message string.
Disable Environment Dumps in Production
Make it a deployment gate: if NODE_ENV=production (or equivalent), any call to log the full environment object should either be blocked by a lint rule or result in a build failure. Tools like eslint-plugin-no-secrets can help catch these in code review.
Use Structured Logging with Schema Enforcement
When your log schema is defined explicitly — only known fields allowed — it's much harder for a secret to accidentally appear in a log line. JSON Schema validation on log events before emission is an under-used technique that pays dividends here.
SOC 2 and HIPAA Implications
If you're pursuing SOC 2 Type II, auditors will ask how you protect credentials and sensitive configuration data throughout their lifecycle — not just at rest in code. Secrets appearing in log aggregators accessible to broad engineering teams is exactly the kind of finding that generates a control deficiency. Under HIPAA, if your logs capture PHI-adjacent tokens or database credentials for systems that store health data, the logging pipeline itself becomes part of your protected environment and must be treated accordingly.
Documenting your log redaction controls, access policies, and retention rules — and being able to demonstrate them with evidence — is increasingly what auditors expect, not just a verbal assertion that "we don't log secrets."
Closing the Loop with Automated Scanning
Manual grep passes are a good starting point but don't scale. Your log redaction configuration can drift; a new developer can add a debug statement; a third-party library update can change its logging behavior. Continuous scanning of your repositories and configuration files — where the logging configuration itself lives — catches these regressions before they reach production.
If you haven't checked whether your codebase already contains log statements, debug flags, or SDK configurations that could push secrets into your log pipeline, run a free GhostCred scan to surface misconfigurations and exposed credentials in about 60 seconds.
Secrets in logs are fixable. The first step is knowing they're there.
See what's exposed in your own code.
Run a free scan