API Keys in Git History Teach More Than Any Pen Test Never Will
Every few weeks, another headline appears: a major company exposes an API key in a public repository, and someone scrapes it within minutes. The response is usually a flurry of blog posts about the importance of secret management, a rushed rotation, and a promise to do better. But the truth is that these incidents are not isolated failures. They are the norm. And the most revealing thing about them is that they are almost always discovered by accident, or by automated scanners, not by the expensive penetration tests that organizations pay for to find vulnerabilities. Git history is a treasure trove of real-world credentials, and it teaches us more about actual security posture than any simulated attack ever will.
The Leak Is the Lesson
Penetration tests are designed to find exploitable vulnerabilities: unpatched software, misconfigured servers, SQL injection points. They are methodical, thorough, and often very good at what they do. But they are also blind to the most common way that credentials actually get compromised: through the code itself. A pen tester might spend weeks probing a web application for weaknesses, while a simple grep for api_key in the company's public GitHub repos would have found a live AWS secret in a matter of minutes.
The gap is not about skill. It is about assumptions. Pen testers assume that the organization has some baseline of hygiene, that secrets are not sitting in plain sight. In reality, they almost always are. A 2023 study by GitGuardian found that over 10 million secrets were exposed in public GitHub commits in a single year, and that number has been climbing steadily. These are not all low-value credentials. Many are valid AWS keys, Slack tokens, and database passwords.
Git history is a permanent record of every mistake a developer has ever made. It is also a record of every time a developer did something right, only to undo it later. The key that was committed six months ago, then removed in a later commit, is still there in the history. Anyone with access to the repository, or to a public mirror, can retrieve it. This is not a theoretical risk. Automated tools like trufflehog and gitleaks are designed to scan entire git histories, not just the current state of the code.
The lesson is simple: if you want to know how vulnerable an organization really is, look at what its developers have committed over time. The leaks are not outliers. They are the norm. And they are far more likely to lead to a breach than any clever exploit a pen tester might dream up.
From Slip to Breach: The API Key Lifecycle
An API key is born in a configuration file, often a local environment variable or a hardcoded constant during development. It is meant to be a temporary measure, a way to get the code working before proper secret management is set up. But temporary measures have a way of becoming permanent. The developer commits the code, pushes to a branch, and the key is now part of the repository. It may be in a file that is later deleted, but the history remains.
Rotation policies are supposed to mitigate this. If a key is rotated regularly, the leaked key becomes useless after a short window. But in practice, rotation is often ignored. A 2024 survey by Vault found that more than half of organizations do not have a formal rotation policy, and among those that do, the average time between rotations is over 90 days. That is a long time for a leaked key to be active.
The blast radius of a single leak is determined by the key's scopes. A key with broad permissions, such as access to an entire cloud account, can be catastrophic. A key with limited scopes, such as read-only access to a single bucket, is less damaging but still a risk. The problem is that many organizations do not enforce least privilege. Developers often request the most permissive key available because it is easier, and the key ends up with far more access than it needs.
Revocation is another weak point. Even when a leak is detected, the response time is often slow. A 2022 analysis by Lacework found that the median time to detect a leaked cloud credential was 19 days, and the median time to revoke it was another 12 days. That is over a month during which the key is fully usable. In the fast-moving world of automated credential theft, a month is an eternity.
What UnYOLO and Agent Credential Brokers Change
The traditional answer to credential leakage has been better secret management: vaults, encrypted storage, and access controls. But these tools still rely on the developer to use them correctly, and they do nothing to prevent keys from being committed in the first place. A newer approach is the agent credential broker, exemplified by tools like UnYOLO. Instead of storing long-lived keys, these brokers issue short-lived, scoped tokens on demand.
UnYOLO, which describes itself as an agent credential broker and policy engine for GitHub, sits between an AI agent or developer and the services they need to access. Instead of handing out a static API key, it evaluates the request, checks the policy, and issues a temporary token that is valid for a single session or a short time window. The token is automatically revoked when it expires, and the broker logs every use.
This has a profound effect on the leak problem. Even if a token is committed to git history, it is useless by the time anyone finds it. The token is gone, expired, and cannot be replayed. The broker also enforces least privilege at the policy level. An agent that only needs to read a specific repository gets a token with read-only access to that repository, nothing more. This limits the blast radius of any single leak.
For AI agents, which are increasingly being used to automate coding tasks, this is a critical shift. Agents often need to interact with multiple services, and if they are given a single long-lived key, that key becomes a single point of failure. A broker can issue a new token for each step of a workflow, each with its own scope and expiration. The agent never sees the master credential, and the broker can revoke access instantly if the agent behaves unexpectedly.
Adopting a broker is not without friction. It requires changes to how developers and agents authenticate, and it adds a new component to the infrastructure stack. But the trade-off is clear: the risk of a leaked key being usable is drastically reduced. The broker turns a permanent leak into a temporary inconvenience, and it does so without requiring developers to change their habits.
The Wire-Level Reality of Credential Theft
Understanding how credentials are actually stolen helps explain why git history is such a rich source. When an API key is used, it is sent over the network in an HTTP header, typically Authorization or a custom header like X-API-Key. HTTPS encrypts the payload, so an eavesdropper on the wire cannot see the key. But the metadata is not encrypted.
Proxies, load balancers, and content delivery networks (CDNs) sit between the client and the server. These intermediaries can log headers, including the ones that contain API keys. A misconfigured proxy might log all headers to a file, and that file might be accessible to a wider audience than intended. There have been multiple incidents where a CDN or logging service accidentally exposed sensitive headers.
Even without direct header logging, timing and size leaks can reveal information. A request that includes a long token will take slightly longer to process than one with a short token. An attacker who can observe the timing of requests might be able to infer the length of a secret, which can narrow the search space. This is a subtle attack, but it is a reminder that the wire is not a safe place for secrets.
The reality is that most credential theft does not come from wire-level interception. It comes from the places where credentials are stored: configuration files, environment variables, and git repositories. The wire is just the delivery mechanism. If the key is already in the repo, the attacker does not need to intercept anything. They just need to clone the repository.
Why Pen Tests Overlook the Obvious
Penetration tests are designed to simulate attacks, not to audit an organization's hygiene. They follow a methodology: reconnaissance, scanning, exploitation, and reporting. The tests are often scoped to specific systems or networks, and they rarely include the source code repository as a target. Even when they do, the focus is on finding code-level vulnerabilities, not secrets.
There is also the issue of insider risk. Pen tests are usually conducted with the knowledge of the organization, and they simulate external attackers. But the most common source of credential leakage is not an external attacker. It is an employee who accidentally commits a key, or a contractor who uses a personal account, or a former employee who still has access to a repository. Pen tests do not simulate these scenarios.
Automation is the key advantage that secret scanners have over manual testing. A tool like gitleaks can scan an entire git history in minutes, and it can be integrated into a CI pipeline to run on every commit. This is something a pen tester cannot do manually. The scanner can also be trained to recognize patterns specific to an organization, such as internal service names or custom token formats.
This is not to say that pen tests are useless. They are essential for finding vulnerabilities that automated scanners might miss, such as business logic flaws or complex attack chains. But they are not a substitute for secret scanning. The two approaches are complementary, and the best security programs use both. The problem is that many organizations rely almost exclusively on pen tests and neglect the simple act of scanning their own repositories.
Turning Git History into a Security Audit
The good news is that git history can be turned into a powerful security audit tool. The first step is to scan all branches, not just the main branch. Developers often create feature branches that are never merged, but they still contain secrets. These branches are often forgotten, but they are still accessible to anyone with repository access.
Secret scanners should be integrated into the CI pipeline, so that every commit is checked. This is a simple addition that can catch secrets before they are pushed. Many scanners can be configured to block a commit if a secret is found, or to alert the developer immediately. The scanner should also be run on a regular basis against the entire repository history, to catch older leaks that might have been missed.
Hunting for keys in commit messages is another technique. Developers sometimes paste keys into commit messages as a way to document something, or they might use a key as part of a test. These are easy to find with a simple search, and they are often overlooked by traditional secret scanners that focus on file contents.
Rewriting history to remove a secret is possible, but it is difficult and risky. It requires a force push, which can disrupt other developers' workflows, and it does not guarantee that the secret has been removed from all copies of the repository. The pragmatic approach is to assume that any committed secret is compromised and to rotate it immediately. This is the same advice that applies to a physical key: if you lose a copy, you change the lock.
Practical Playbook for Teams
So what should a team actually do? The first step is to adopt a credential broker for all machine identities, including API keys, service accounts, and tokens. This is a significant change, but it is the most effective way to reduce the impact of a leak. The broker should be integrated with the CI/CD pipeline and with any AI agents that are used in development.
Rotation should be a fixed schedule, not an afterthought. Keys should be rotated on a regular basis, even if there is no suspicion of a leak. This limits the window of exposure and ensures that any leaked key becomes useless quickly. The rotation process should be automated as much as possible, to reduce the burden on developers.
Monitoring for anomalous usage patterns is another layer of defense. If a key that is normally used from a specific IP address suddenly starts making requests from a different country, that is a red flag. The monitoring system should alert the security team, and the key should be revoked automatically if the pattern is suspicious. This is not a replacement for proactive scanning, but it is a safety net.
Finally, treat every commit as a potential leak. This is a mindset shift. It means that the default assumption is that secrets will be exposed, and the design should account for that. It means that keys should have the minimum necessary permissions, and that they should be short-lived. It means that the security team should be scanning the repository on a regular basis, not just when there is a suspected incident. This is a lot of work, but it is the work that actually prevents breaches.
The uncomfortable truth is that most organizations are not doing this. They are still relying on pen tests and hoping for the best. But the evidence is clear: the leaks are in the git history, and they are waiting to be found. The tools to find them are available, and the methods are well-understood. The only question is whether teams will take the lesson seriously before the next headline.