# Secrets in repositories and CI

Source: https://startwithidentity.com/techniques/secrets-in-repositories-and-ci/
Last updated: 2026-09-29
License: content by Start with Identity. Cite the source URL.

---

## How it works

Developers put secrets, API keys, database passwords, cloud access keys, into source code and CI configuration for the same reason they end up anywhere convenient: it is the fastest way to get something working. A key gets hard-coded during a debugging session and never removed, or it sits in a `.env` file that gets committed by accident, or it is set as a pipeline variable that prints to a build log when a script echoes its environment. Once a secret reaches a public or even broadly-shared private repository, it is copied by every clone, every fork, and often by scanners that crawl public code hosts specifically looking for credential-shaped strings, within minutes of the commit landing.

GitGuardian's August 2026 research on n8n API tokens shows the mechanics at scale: it found 4,576 unique n8n API tokens exposed in public GitHub commits across 1,255 hostnames, frequently sitting in the same config file as the instance URL that made the leaked token immediately usable. Of 896 reachable instances the researchers tested, 321 accepted at least one leaked token, about 36 percent. From there, read access to a workflow automation platform is not read-only in effect: a workflow can be built that invokes a stored credential, such as a connected service's API key, and ships the result to an external endpoint without ever displaying the underlying secret value.

## Why it works

The control assumption that fails is that a repository or a build log is a private space. Git history is permanent by design, a secret committed and later deleted still exists in every prior commit unless the history itself is rewritten, and CI logs are often retained and accessible to a wider audience than the pipeline's actual operators. A second assumption that fails is that a credential's presence implies intent: automation platforms and CI systems hold live connections to many other systems, so a single leaked orchestrator token is worth more than any one credential it touches, and an attacker does not need to read a secret's value when they can use the platform holding it to act on their behalf.

## How to detect it

- Automated secrets scanning on every commit and pull request, flagging credential-shaped strings before they merge rather than after.
- Outbound API calls from an automation platform or CI runner to a destination that was never part of an approved workflow or pipeline step.
- Authentication to an internal service from an IP range or client that does not match any known CI runner or developer workstation, using a token that maps to a pipeline credential.

Be honest about the limits: pattern-based secret scanning catches recognizable key formats well but misses generic-looking strings, and a scanner tuned aggressively enough to catch those generates enough false positives on ordinary code that teams stop reading its output. Detection here is a backstop; it does not substitute for keeping secrets out of the repository and log stream in the first place.

## How to stop it

- **Keep secrets out of the repository entirely** by using a dedicated vault or secrets manager and injecting values at runtime rather than storing them in source or config files.
- **Scan every commit and CI log for credential patterns** before merge and before logs are retained, using an open-source or commercial secrets scanner as a required pipeline gate.
- **Rotate every credential a workflow tool can reach if its own token ever leaks**, since read-only access to an orchestrator is not read-only for the credentials it holds.
- **Treat automation platform tokens as non-human identities** with an owner, an expiry, and scoped permissions rather than a single broad key shared across workflows.
- **Rewrite git history and revoke immediately when a secret is committed**, rather than only deleting the file in a later commit, since the value remains reachable in history until then. See [secrets rotation](https://startwithidentity.com/glossary/secrets-rotation/).

## Seen in the wild

- [GitGuardian found 4,576 leaked n8n tokens, and a third of reachable instances accepted them](https://startwithidentity.com/blog/2026-08-05-leaked-n8n-api-tokens-expose-connected-credentials/)
- [JadePuffer used a service principal whose secret appeared in a public GitHub issue to wipe Azure resources in seven minutes](https://startwithidentity.com/blog/2026-09-28-jadepuffer-used-leaked-service-principal-credentials-to-wipe-azure-tenants/)
- [GitLab's incoming email address is a non-expiring token that commits code and runs CI as you](https://startwithidentity.com/blog/2026-09-23-gitlab-incoming-email-token-lets-anyone-commit-and-run-ci-as-you/), a credential routinely pasted into READMEs and tickets

## Sources

This brief maps to T1593.003 (Search Open Websites/Domains: Code Repositories), a Reconnaissance-tactic technique that explicitly covers adversaries searching public repositories for exposed credentials and API keys, matching the GitGuardian n8n research below. T1552.001 (Unsecured Credentials: Credentials In Files) is scoped to an adversary who already has access to a host or share and searches its local files for stored credentials; it does not cover scanning public code hosts before any compromise has happened, which is the mechanism this brief actually describes.

- [MITRE ATT&CK T1593.003: Search Open Websites/Domains: Code Repositories](https://attack.mitre.org/techniques/T1593/003/)
- [Top 6 open source secrets scanning and NHI tools](https://startwithidentity.com/articles/top-6-open-source-secrets-scanning-nhi-tools/)
- [What is secrets management](https://startwithidentity.com/guides/fundamentals/what-is-secrets-management/)
