Use Case 09  ·  Engineering Intelligence

The API key wasn't in the code. It was in the logs.

Every secret scanner is built on one assumption: a credential is exposed when it's written into the code. So teams guard the repo and assume a clean repo means safe secrets. But a live key can be absent from your code and still sit in cleartext somewhere else — put there not by a mistake in the code, but by the code working exactly as written.

CM
CodeMinder Team
September 2026  ·  4 min read

The Structural Reality

A clean repository tells you something real: the secret isn't in the code you scanned. It can't tell you everywhere that secret travels once the application starts running. Most secret-scanning focuses on artifacts — source, commits, PRs, config, container images — and those controls are essential. But a credential can be absent from every one of them and still become exposed at runtime: not because someone made an obvious mistake, but because several reasonable pieces of the system interacted exactly as designed.

What we found

A live third-party API key was appearing in application logs in cleartext. It was not committed to the repository, hardcoded in the application, present in Git history, or exposed through a config artifact. It was supplied to a third-party provider at runtime, in the request format that provider's API expects. On successful calls, nothing unusual happened. But when a request failed, the error handler did something entirely reasonable: it logged the failed request so an engineer could see what went wrong. The request included the full URL — and the full URL included the key.

The code was clean. The runtime wasn't. Every failed call to that provider had the potential to write a valid credential into the logging layer, in cleartext.

Why this is a different class of problem

The path matters, because the risk doesn't live in any single step — each one is a reasonable engineering decision:

01
A credential travels in a request
the provider expects the API key as part of the request — normal application behavior
02
The request fails
third-party APIs fail; nothing unusual about that
03
The error handler records the failed request
the application logs enough context to help an engineer debug — a reasonable decision
04
The credential reaches the logs
the full request contains the key, so it now exists somewhere it never did before — the logging layer, and wherever those logs travel

No single step looked dangerous. The risk emerged from the composition of them — and that's the part that matters.

The gap between code security and runtime security

A repository scanner can correctly report no secrets found and still miss this — not because it's broken, but because the secret was never in the repository. A static tool analyzes the code it sees. This risk only becomes visible when you follow the runtime path:

credential→ request→ failure→ error handling→ logging

The exposure was created by behavior. The system became insecure in motion, not at rest — which is why "our code is clean" and "our secrets are safe" are not the same statement.

We'd seen the shape before

This wasn't the first time sensitive values reached logs through normal application behavior. In an earlier finding — The Credential You Didn't Know Was Exposed — cloud access credentials were landing in application logs too. Different credentials, different mechanism, same underlying pattern: sensitive values moving through a legitimate runtime path and entering the logging layer as a side effect of normal behavior. Once you've seen it twice, it stops looking like an isolated mistake and starts looking like a category of risk — one that repository scanning alone doesn't cover.

What the systems reported vs. what was happening

The repository scannerRepository clean, no committed credentials✓
Static checksNo issue in the artifacts inspected✓
The applicationA failed request recorded to help debugging✓
Actually happeningA live credential copied into a cleartext log stream, able to persist anywhere those logs travel

Every system was telling the truth about its own slice. The exposure existed in the relationship between them — how the credential traveled, what happened when the request failed, and what the application recorded afterward.

What this means for you

A clean codebase is necessary. It isn't sufficient. "Did we expose a secret in our code?" and "where can this secret end up while the system is running?" are different questions — and the second requires following the behavior of the system. Worth asking, separately from any repo scan:

The shift is simple: don't only inspect where secrets are stored — inspect where they travel. A secret can be perfectly protected in the repository and still be exposed downstream.

The Core Idea

Your code can be clean and your runtime can still be leaking. Security controls tell you whether the things they inspect are safe; engineering reality depends on what happens between those controls, and after the system starts running. That's where this credential was exposed — not in the code, in the behavior.

← Use Case 08
The Alarm Fired Three Times. Nothing Got In.
View all cases →
The full Strategic Velocity Series

Your repo is clean. Are your logs?

Bring us one workflow you're not completely confident in. We'll show you how we'd trace the signals behind it.

Book a Demo →