← All articles

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:

  1. 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.
  2. 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
  3. Check your CI/CD build logs. Search for the same patterns in archived pipeline output. Many teams forget that printenv or env commands run during debugging steps never got removed.
  4. 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?
  5. 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