Start with Identity
SWI-T022 · Credential storage

Secrets in repositories and CI

A credential committed to a config file or pasted into a pipeline variable travels with every clone, fork, and log line, and it keeps working for as long as nobody notices it left the vault.

WidespreadModerate to detect
First observed: 2013ATT&CK T1593.003

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.

Seen in the wild

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.

Last reviewed By SWI Community TeamSuggest a correctionHow we research
Seeing this technique used differently, or have a detection rule that works better? Email [email protected]. See all briefs in the technique catalog, or volunteer as a CVE Analyst.
Mapped to MITRE ATT&CK where a technique ID exists. Independent, community-driven analysis, not a substitute for the ATT&CK knowledge base. See the disclaimer.