Ask any developer whether hardcoding an API key into source is a bad idea, and they'll say yes without hesitation. Then look at almost any real codebase — especially anything built quickly, for a hackathon, a prototype, or "just to get it working" — and you'll find one anyway. This isn't a knowledge problem. It's a friction problem.
The moment it happens
It rarely starts as a decision. It starts as debugging. You're testing a third-party API integration, the environment variable isn't loading for some reason, so you paste the key directly into the function just to confirm the request works. It works. You move on to the next thing. The key stays.
Later, someone runs git add . without checking the diff carefully, and the key is now in the commit history — which, importantly, doesn't go away even if you delete the line in a later commit. Anyone with clone access to that repository, at any point in the future, can find it by searching the history.
Why "it's a private repo" doesn't fully solve this
A private repository narrows who can see the key, but it doesn't eliminate the risk categories that matter most:
- Contractors, former employees, or anyone who briefly had repo access retain whatever they cloned.
- If the repo is ever made public — open-sourced later, or accidentally toggled — the entire history goes with it.
- CI/CD logs, error-tracking tools, and support tickets often include full stack traces that can leak a hardcoded value even if the repo itself stays private.
The fix, and why it's worth the extra 30 seconds
Environment variables solve this cleanly:
import os
API_KEY = os.environ["STRIPE_SECRET_KEY"]
The key lives in a .env file (excluded from version control via .gitignore) locally, and in your hosting platform's environment variable settings in production. It's not committed, it's not in your logs by default, and rotating it is a config change rather than a code deploy.
The friction that causes people to skip this step is almost always a missing habit, not a missing tool — keep a .env.example file in the repo with every variable name and no real values, so the "correct" path is exactly as fast as the shortcut.
If a key has already been exposed
Rotate it. Don't just remove the line from the current file — the old value is still valid until you generate a new one and revoke the old one at the provider. Removing it from the code without rotating the key protects you from nothing.