Secrets Management & Software Supply Chain
Two of the most common ways organisations get breached today: leaked secrets and compromised dependencies. Neither requires an attacker to find a bug in your code — both let them walk in through a door your own tooling left open.
:::
Secrets
Where secrets leak
- Source code and commit history — deleting a secret in a later commit does not remove it from history; anyone can
git log -pand find it - CI logs and pipeline definitions — a
curlcommand with a token in the URL, printed to a public build log - Container images and layers — a secret set as an
ENVin an early Docker layer stays in the image even if a later layer removes the file - Chat, tickets, screenshots — "quickly pasting the API key into Slack so you can test it" is one of the most common leak paths, and the hardest to scan for
- Client-side JavaScript and mobile apps — anything shipped to a browser or a phone is, functionally, public
:::warn
Container image layers are append-only from a history standpoint. RUN echo $SECRET > /tmp/s.txt followed by RUN rm /tmp/s.txt in a later layer does not remove the secret — it's still sitting in the earlier layer, extractable with docker history or by pulling the image and inspecting layers directly.
Prevention
- Pre-commit / pre-receive scanning (gitleaks, trufflehog, GitHub secret scanning) — catch the secret before it's committed, not after
- Central secret stores with short-lived credentials and audit logs — a vault that issues a token good for one hour is far less valuable to steal than one good forever
- Never commit secrets — use environment injection or volume mounts at runtime instead of baking values into files or images
- Rotate immediately when a leak is detected — not "when convenient." A leaked key is a live incident from the moment of exposure, whether or not you've seen evidence of misuse yet
Detection
- Enable secret scanning on every repository, including private ones — "private" is not "safe," and private repos get made public by accident more often than people expect
- Monitor public GitHub for your organisation's tokens (GitHub has native support that scans public repos for recognizable token formats from major providers and notifies the provider directly)
- Treat every leaked cloud key as a production incident: rotate it, check access logs for the period it was exposed, and only then investigate root cause
A worked example
A developer commits a .env file containing a database password to a public fork by accident, then deletes it two minutes later in a follow-up commit. What actually happened:
- The secret is permanently in git history, retrievable by anyone who clones the repo, forever, regardless of the follow-up commit
- GitHub's own secret-scanning bots typically index new public commits within minutes — often faster than the developer notices the mistake
- The only correct fix is: rotate the credential immediately, then worry about scrubbing history (which doesn't undo the exposure, it just cleans up going forward)
The two-minute delete gave a false sense that the problem was handled. It wasn't.
Software supply chain
Your application is mostly other people's code. That code can be:
- Accidentally vulnerable (known CVEs)
- Intentionally malicious (typosquatting, compromised maintainer accounts)
- Hijacked at build time (dependency confusion, compromised CI)
Practical controls
| Control | Purpose |
|---|---|
| SCA (Dependabot, Snyk, etc.) | Known vulnerabilities in dependencies |
| Lockfiles + integrity hashes | Reproducible, tamper-evident installs |
| Private package mirrors / allow-lists | Reduce exposure to public registry attacks |
| Signed commits & protected branches | Protect the source of truth |
| Artifact signing & verification | Ensure what you deploy is what you built |
| SLSA / provenance | Prove how an artifact was produced |
Dependency confusion
If your internal package is named the same as a public one, some package managers prefer the public version by default (it looks "newer" or is resolved first, depending on configuration). Attackers register the public name and wait for a misconfigured install to pull their version instead of your internal one — silently running their code inside your build. This exact technique was demonstrated against major companies including Apple, Microsoft, and Tesla in a widely publicized 2021 research disclosure. Use scoped packages (@yourorg/package-name) and explicit registry configuration to prevent this.
Typosquatting in practice
A developer means to npm install crossenv but types npm install cross-env — or the reverse — and one of the two is a malicious package designed to look like the real one. At install time, npm runs the package's install scripts with the same privileges as the developer running the command. There is no sandboxing by default. A single typo can mean full code execution on a developer's machine or a CI runner.
🧪 Hands-on lab — find your own exposure
Part 1 — secrets in history (10 minutes)
git clone <a repo you maintain>
cd <repo>
pip install detect-secrets # or: brew install gitleaks
gitleaks detect --source . -v
Even in a repo you believe is clean, check whether any findings surface in old commits, not just the current tree.
Part 2 — dependency confusion exposure (10 minutes)
- List your organization's internal/private package names.
- For each one, check whether that exact name is already registered on the public npm/PyPI registry.
- If any are unregistered, that's a live dependency confusion risk — register a placeholder under your org or configure your package manager to explicitly pin the internal registry as the only source for those names.
:::
:::challenge Test yourself
- A secret was committed and deleted in the very next commit, five minutes later. Is rotation still necessary? Explain why or why not.
- Explain dependency confusion in your own words, and name one concrete configuration change that prevents it.
- Your Docker image was built with a secret passed via
ENVand later "removed" in a subsequentRUN rmlayer. Is the secret actually gone from the image? Why or why not?
Key terms
- Secret scanning — automated detection of credentials in code and history
- Typosquatting — publishing a malicious package with a name close to a popular one
- Provenance — metadata that describes how an artifact was built
- Dependency confusion — tricking a package manager into installing a public malicious package instead of an intended private one, by name collision
- Short-lived credential — a secret that expires quickly (minutes to hours), limiting the value of theft
Recap
Treat secrets as production credentials from the moment they are created, and treat every dependency as code you are responsible for, even though you didn't write it. Automation, least privilege, and rapid rotation are the practical defences — and speed of rotation matters more than perfection of prevention, because leaks will still happen.
References
- OWASP Secrets Management Cheat Sheet
- SLSA — supply-chain integrity framework
- Dependency confusion research (Alex Birsan) — the original disclosure covering Apple, Microsoft, Tesla and others