Secret Management: How Credentials End Up in Code (and How to Stop It)
Credentials committed to source code repositories are a persistent and well-exploited vulnerability class. Attackers scan public repositories continuously for API keys, database passwords, private keys, and service account credentials. When they find them, they act quickly: the time between a credential appearing in a public repository and it being used maliciously is measured in minutes in many documented cases. For private repositories, a credential in source control is a credential accessible to every person with repository access, often including contractors, former employees in access review backlogs, and third-party integrations.
The reason credentials end up in code is not that developers are careless. It is that putting the credential where the code needs it is the fastest path to a working local development environment, a passing test, or a successful deployment. The alternative, using a secrets management service or environment-level configuration, requires more steps and more infrastructure. When those alternatives are not well-established as the standard in an engineering team, the shortcut becomes the default, and the shortcut is to put the secret in the code.
Why Source Control Is a Particularly Dangerous Location for Secrets
A credential in source control is not just present in the current state of the repository. It is present in the commit history. Removing a credential from the current HEAD of a repository does not remove it from the history. A developer who commits a credential, realises the error, and deletes it in a follow-up commit has not resolved the exposure: the credential is still visible in the commit log to anyone with access to the repository. Properly removing a credential from a repository's history requires rewriting the history, which is disruptive in shared repositories, and even after history rewriting, clones and forks made before the rewrite still contain the credential.
The practical implication is that any credential that has been committed to source control must be treated as compromised and rotated, regardless of how quickly it was removed from the current state. The response to discovering a committed credential is not to delete the commit and continue using the credential. It is to rotate the credential immediately, investigate whether it was used maliciously during the exposure window, and then address the process that allowed it to be committed in the first place.
Detecting Secrets Before They Are Committed
The first line of defence against credentials in source control is detection at the pre-commit stage, before the credential enters the repository at all. Pre-commit hooks can run credential scanning tools against staged changes and block the commit if a credential pattern is detected. These tools use pattern matching against known formats for common credential types: cloud provider access keys, private key file headers, database connection strings with embedded passwords, and generic high-entropy string patterns that may indicate a credential.
Pre-commit hooks rely on the developer having the hook configured locally, which is not guaranteed in all team environments. CI/CD pipeline scanning provides a server-side backstop: every push to the repository triggers a scan of the committed content. Findings from CI/CD scanning generate alerts and, depending on the severity policy, may block the pipeline until the credential is removed and rotated. The combination of pre-commit and pipeline scanning provides defence in depth: the pre-commit hook catches most cases at the point of authoring, and the pipeline scan catches cases that bypass the hook.
Replacing Secrets in Code with Proper Secret Management
Detection tools address the symptom. The systemic fix is providing an alternative that is as low-friction as the bad pattern. That alternative is a secrets management service that stores credentials centrally, controls access by workload and environment, rotates credentials automatically where supported, and provides an audit trail of access. Application code retrieves credentials from the secrets management service at runtime rather than reading them from configuration files or environment variables set at deployment time from a static store.
The transition from credentials in code or in static configuration to a secrets management service requires effort proportional to how widely distributed the existing credential patterns are. A codebase that has credentials in multiple locations, across multiple services, referenced in deployment scripts and CI/CD environment variable stores, requires a systematic inventory before remediation can be planned. That inventory is itself a security exercise: understanding every location where a credential is stored and how it is accessed is necessary to ensure that rotating the credential does not break dependent services.
Building the Habit of Secrets Hygiene
Developer training on secrets management is most effective when it is specific and practical rather than general. Teaching developers how to use the secrets management service the organisation has adopted, how to configure local development environments to use dummy credentials rather than production ones, and how to read scanner output and respond to a detected credential builds the habit faster than a policy document about credential handling. Making the secure path the path of least resistance is the goal: if accessing a secret from the secrets management service is as simple as reading an environment variable, developers will use it.
Credential exposure through source control is one of the most common and most impactful findings in application security assessments. If you want to understand your current exposure and build a systematic approach to secrets management, get in touch at info@cyberlinx.com.au.
Related Articles







