Most organisations address secrets by buying a store, moving values into it, and marking the item closed. The store is worth having. It is also the part of the problem that was never where the leaks happened.
A secret store changes who can fetch a value. It does not change what happens once the value has been fetched, and that is where nearly every real exposure occurs.
Remove, do not relocate
The strongest move available is not better storage. It is not having a long-lived credential at all.
Workload identity and OIDC federation replace a stored key with a short-lived token the platform issues on demand, scoped to a specific workload or a specific repository and branch. There is nothing to rotate, nothing to leak from a CI settings page, and nothing that keeps working after an engineer leaves.
A credential that expires on its own cannot be forgotten.
Every secret in a store should be examined with one question first: can this be replaced by an identity the platform already issues? For cloud API access, for database access on a managed service, for registry pulls and for service-to-service calls inside a cluster, the answer is increasingly yes. What remains is the genuinely irreducible set, which is far smaller than most estates assume.
The paths that actually leak
- Fetched at
- run time, never build time
- Delivered as
- a file with tight permissions, not an inherited variable
- Redacted in
- the collector, before egress
- Better still
- a short-lived identity, so there is no stored value to leak
This diagram as text
- The secret store — narrows who can fetch — everything below is still in front of you
- The paths everyone lists
- CI logs — masking matches the exact value
- Image layers — a later delete does not remove it
- Git history — and every clone and fork
- Process environment — inherited by children
- And the ones nobody lists
- Crash dumps and error reporters
- Observability payloads — headers in traces
- Backups of the store itself
Relationships
- The secret store → CI logs
- The secret store → Image layers
- The secret store → Git history
- The secret store → Process environment
- Process environment → Crash dumps and error reporters
- Process environment → Observability payloads
- The secret store → Backups of the store itself
CI logs. A build step that echoes its configuration, a verbose flag, a failing command printing its arguments. Masking helps and is not reliable: it matches on the exact value, so a base64-encoded or partially printed secret passes straight through.
Image layers. A secret used during a build stays in the layer that used it, even if a later instruction deletes the file. Anyone who can pull the image can recover it. Multi-stage builds and build-time secret mounts exist for this.
Git history. The value is in the objects forever, and in every clone and fork. Rotation is the only action that reduces risk; history rewriting is tidying.
The process environment. Inherited by children, readable by anything that can see the process, and routinely dumped by crash handlers that print the environment for debugging.
Observability payloads. An authorisation header captured in a trace, a request body logged at debug level, a token in a URL that lands in an access log. This is why redaction belongs in the collector, before anything leaves your boundary for a hosted backend.
Backups of the store. The vault’s own backups and snapshots are a copy of every secret you have, and they are frequently protected less carefully than the store.
What good looks like
- Fetched at run time, not build time. A secret that exists during a build is in the artefact.
- Delivered as a file with restrictive permissions, mounted into the container, rather than as an environment variable, which removes the inheritance and process-table paths.
- Short-lived wherever the platform supports it, so revocation is rare rather than routine.
- Scoped per workload. A shared credential makes the blast radius of one compromise the whole estate and makes the audit question unanswerable.
- Redacted at the collector, so what leaves the boundary is already clean.
- Scanned for in the pipeline, blocking. Pre-commit hooks are a convenience, not a control, because they run on the machine of the person who might bypass them.
- Rotatable without a deployment. If rotating a credential requires a release, it will not happen on the day it needs to.
Rotation is a test, not a ritual
Most estates can describe their rotation procedure and have not performed it. The first real rotation reliably finds a service that cached the value at startup and never re-reads it, a second consumer nobody knew about, and a hard-coded copy in a configuration file.
Rotate one credential deliberately, in a window, and watch what breaks. That exercise is worth more than the policy document, and it is the same shape as every other readiness exercise: the value is in having done it rather than in having described it.
What an auditor asks
Annex A 8.24 and the surrounding controls are not satisfied by owning a vault. The questions are narrower and most estates struggle with the same ones: who can read this secret, when was it last changed, is the same value used in more than one place, and can you show the access record.
An estate built on short-lived workload identity answers all four almost trivially, because there is no stored value to ask the questions about. That is the strongest argument for removal over relocation, and it is one an auditor recognises.
How STP approaches this
We start by asking which secrets can stop existing, because an estate with no long-lived credential in CI is in a materially different position from one with a well-managed vault. What remains is fetched at run time, delivered as a file, scoped per workload and redacted at the collector. Then we rotate one, deliberately, before anyone needs to, because the procedure nobody has run is the one that fails.
More on secure SDLC and application security and audit and compliance, or start a conversation.

