Your team rotates API keys every 90 days. You have a calendar reminder, a runbook, maybe even a script that automates the swap. It feels responsible. It feels secure.
An attacker who found your key at 9:02 AM was done by 9:07.
That five-minute window is not a hypothetical. It is the median time from credential leak to first malicious use, according to multiple years of GitGuardian research. Your 90-day rotation schedule was completely irrelevant. The damage was done before your morning standup even started.
This post is about why rotation became gospel in security culture, what it actually protects against (some things, not the things you think), and what the threat model actually looks like today. Then we will get into the approaches that do work.
The Rotation Myth
Rotation came from a sensible place. The logic: if your credentials have a bounded lifespan, even a compromised one becomes useless eventually. In an era when key theft was mostly physical (someone copied it from a sticky note, a printed doc, a shared drive) and attackers moved slowly, rotation provided real protection. If you rotated every 90 days, a key that leaked in month one was dead by month three.
The problem is that the threat environment changed completely. Attackers are automated. The moment a key shows up in a public GitHub repo, on a paste site, or in a misconfigured CI log, bots are scanning for it. These are not humans sitting at a keyboard waiting for an opportunity. They are scripts with one job: find credentials and use them.
Rotation is a lagging control. It addresses credentials that have already been exploited by eventually ending the attacker’s access. That is genuinely different from preventing exploitation in the first place. Confusing the two has led organizations to invest heavily in rotation tooling while leaving the actual leak vectors completely unaddressed.
The other problem with rotation as a mental model: it trains teams to think about credentials as inherently long-lived things that just need periodic replacement. That framing shapes architecture decisions, tooling choices, and how engineers think about secrets hygiene. If a 90-day credential feels safe, a 30-day one must be twice as safe. But an attacker still only needs five minutes.
Short-lived credentials, instant revocation, and proxy layers are different in kind, not just degree. We will get to those.
The Numbers Don’t Lie
GitGuardian’s annual State of Secrets Sprawl reports have tracked this for years, and the numbers are bleak in a clarifying way.
In 2023, GitGuardian detected over 12.8 million secrets exposed in public GitHub commits alone. That number does not include private repos with misconfigured access, CI/CD log leakage, Slack exports, or the rapidly growing attack surface from AI coding assistants that pass code context to LLM APIs.
The median time from a secret being committed to a public repository to its first unauthorized use: approximately five minutes. Some research puts it closer to three. The window narrows every year as scanning infrastructure improves and more attackers operate in this space.
Now run the math on your rotation schedule. A 90-day rotation means a key is live for 129,600 minutes. If it leaks at any point during that window, the attacker needs just five of those minutes. The remaining 129,595 are irrelevant. Your rotation event at day 90 closes the window on a credential that was probably used on day one.
The exposure window is the problem, not its length. A 30-day rotation gives attackers 43,200 minutes of potential exposure. Still way more than five. Even weekly rotation yields 10,080 minutes, two thousand times the attacker’s median need.
The only rotation cadence that approaches meaningful prevention is measured in minutes or hours, not days or months. And at that point, you have stopped thinking about rotation and started thinking about short-lived credentials, which is an entirely different architecture.
There is also the human factor. Rotation requires action: someone runs the script, updates the secret in every place it is referenced, tests that nothing broke, and confirms the old key is actually dead. In practice, teams find undocumented places where the old key was hardcoded. The rotation “completes” but the old key remains live in a forgotten Lambda environment variable or a third-party integration that nobody updated. You now have two live keys instead of one.
What Rotation Actually Protects Against
To be fair, rotation is not useless. It earns its place in a security program; it just does not belong where most teams put it.
Deprovisioning. When an employee leaves or a service is decommissioned, key rotation is exactly the right tool. Rotating the key cuts off access for the departed employee or service without requiring you to know exactly where their copy lived. It is brute-force but effective for this specific problem.
Audit and compliance. Frameworks like SOC 2, PCI DSS, and ISO 27001 often include rotation requirements. These requirements were written when rotation was the best available control, and they remain in the standards. Meeting them is real compliance work, even if the threat model has evolved beyond what rotation addresses.
Limiting blast radius over time. If a key was compromised without your knowledge, rotation does eventually end that persistent access. You might not catch the attacker, but you force them to re-acquire credentials. For nation-state actors who want long-term quiet access, this matters.
Forcing credential hygiene. The discipline of rotating keys regularly tends to surface undocumented dependencies. If rotation breaks something, that something was probably already a problem. Rotation as a forcing function for auditing secret usage has operational value, separate from the security narrative around it.
So keep rotation in your playbook. Schedule it, automate it, meet your compliance requirements. Just stop treating it as prevention. It is cleanup, not protection.
The Real Threat Model
Where do API keys actually leak? The answer has changed in the past few years, and if your threat model is still focused on the classical vectors, you are watching the wrong doors.
.env files committed to version control. This remains the single largest source of credential exposure. Developers create .env files locally, .gitignore does not get set up correctly (or gets set up after the first commit), and secrets land in the repo. With monorepo sprawl and dozens of services per organization, the attack surface is large. GitHub’s secret scanning catches many of these, but only after the commit lands.
CI/CD pipeline logs. Build logs are often accessible to more people than production credentials are. A build that echoes environment variables during a debug run, or an error message that includes an API key in a stack trace, can leak credentials to anyone who can read the pipeline logs. In many organizations, that is most of the engineering org plus contractors.
AI coding tools. This is the new and growing one. When a developer pastes code context into an AI assistant, that context sometimes includes API keys from config files, test fixtures, or clipboard history. The LLM processes it, may include snippets in responses, and the key has now passed through a third-party system. The risk is not necessarily that the AI provider is malicious; it is that context travels further than the developer intended.
Hardcoded keys in application code. Developers under deadline pressure hardcode keys directly. These end up in feature branches, merged PRs, and eventually git history where they live forever unless explicitly purged.
Third-party integrations. When you paste an API key into a SaaS tool to connect an integration, you are extending trust to that vendor’s entire security posture, their employees, and their breach exposure. API keys shared with integrations are rarely scoped or monitored.
The pattern across all these vectors: once a key exists as a static string, it can be copied. Every copy is a potential exposure.
Short-Lived Credentials: The Model That Actually Works
The fundamental shift is this: instead of a key that lives for 90 days and gets rotated, issue a credential that lives for 15 minutes and cannot be renewed by the attacker.
This is how AWS IAM works with STS-issued session tokens. It is how OAuth access tokens work when implemented correctly. The token has a TTL measured in minutes or hours, not days. When it expires, the attacker needs the refresh token or the ability to generate a new one. They usually do not have that.
The challenge: most SaaS APIs still issue static keys. Stripe gives you an API key. Twilio gives you an auth token. OpenAI gives you an API key. These are not short-lived by default. The provider controls that architecture, and most have not moved to short-lived credential issuance.
This is where the proxy layer pattern matters. Rather than giving your application a direct Stripe API key, you route API calls through a proxy that authenticates requests using a short-lived, scoped token. The proxy holds the real credential; your application never touches it. The token your application uses can expire in minutes, be scoped to specific operations, and be revoked instantly without touching the upstream key at all.
The advantages compound:
- If a short-lived token leaks, it is probably already expired before the attacker can use it
- The upstream key never appears in application code, logs, or LLM context
- Revocation is immediate and certain, not dependent on propagation delays
- You can scope tokens to specific operations: read-only, specific endpoints, rate-limited
Building this yourself takes real engineering effort. The proxy layer needs to handle auth, token issuance, request forwarding, and logging. But the security properties are genuinely different from rotation alone. You are changing the model, not tweaking the parameters.
Instant Revocation
Here is the problem with revoking a static API key: you often do not know where it has been copied.
You issued one key. A developer copied it to their local .env. A teammate put it in the staging environment. Someone pasted it into a Notion doc “temporarily.” It is in the CI/CD system under three different names because different services reference it. You can revoke the key at the source, but all those copies are still out there, and you do not have a complete inventory of them.
True instant revocation requires that you control the credential path. If applications are authenticating with tokens you issued, and those tokens are validated against your system, you can revoke them instantly and with certainty. The moment you mark a token as revoked in your system, every subsequent request using it fails.
This is the phantom token pattern. The token your application holds is not the real upstream credential. It is a reference that your proxy resolves to the real credential at request time. Revoke the phantom token and the reference is broken. The attacker, your ex-employee, the compromised third-party integration: all of them immediately lose access. No hunting down copies. No hoping the old key was actually disabled everywhere.
The upstream key can remain unchanged. Only the phantom token that provides access to it is revoked. This is also operationally safer: you are not scrambling to rotate a live production credential while an incident is unfolding. You revoke the token, buy yourself time, and rotate the upstream key deliberately.
Practical Implementation
If you want to move in this direction without rebuilding your entire secrets architecture, here is where to start.
Audit your git history. Tools like git-secrets, truffleHog, and gitleaks can scan your repository history for committed credentials. Run them. The results will probably be uncomfortable. Purge any secrets you find and rotate the affected keys immediately, regardless of whether you have evidence of exploitation.
Inventory your static keys. List every API key your applications use. For each one: who has a copy, where is it stored, what can it do, and when was it last rotated? Most teams find this exercise surfaces keys they forgot existed.
Scope your keys. Many APIs allow you to create keys with restricted permissions. A key that can only read from a specific endpoint cannot be used to exfiltrate data or run up charges. Scoping limits blast radius even if you cannot eliminate static keys entirely.
Move secrets to a secrets manager. HashiCorp Vault, AWS Secrets Manager, and similar tools give you centralized storage, access logging, and automated rotation. They are not a complete solution because they still deal in static secrets, but they are much better than .env files and hardcoded strings.
For AI agents: never pass real keys to LLM context. If you are building or using AI agents that call external APIs, the agent should never hold the actual API key. Use the proxy pattern: the agent authenticates to your proxy with a scoped token, the proxy makes the upstream call. The real key never appears in the prompt, the response, or any logged context.
Add a proxy layer for high-value integrations. Start with the integrations that matter most: payment APIs, data APIs, authentication providers. Route calls through a thin proxy that issues and validates short-lived tokens. You get audit logs, instant revocation, and scoped access without waiting for the upstream API provider to change their model.
If you want instant revocation and phantom tokens without building the proxy layer yourself, that is exactly what API Stronghold is built for. Your applications get short-lived, scoped tokens. Your real upstream credentials never leave your control. Revocation is immediate and complete.
Try it free for 14 days at https://www.apistronghold.com. No rotation schedule required.