AI-coded apps

    How to Stop Cursor AI from Hardcoding API Keys to GitHub

    A terminal running BFG Repo Cleaner to purge a leaked API key from git history after rotating the key.

    To stop Cursor from hardcoding API keys into code that reaches GitHub, keep secrets in a git-ignored .env file, instruct the assistant to read from environment variables rather than inline literals, and add a pre-commit secret scanner plus GitHub push protection so a key cannot be committed by accident. If a key already reached GitHub, rotate it immediately, because it should be treated as compromised, then purge it from the repository history with a tool like BFG Repo Cleaner. Deleting the file in a new commit is not enough, since the key remains in the git history.

    Short answer

    Stop the leak at two levels: prevent hardcoding, and contain a key that slipped through. To prevent it, store secrets in a .env file listed in .gitignore, tell Cursor to use environment variables instead of literal keys, and add a pre-commit scanner such as gitleaks plus GitHub's push protection. If a key already reached GitHub, first rotate it, since automated scanners find exposed keys within minutes, then remove it from history with BFG Repo Cleaner or git filter-repo and force-push. Deleting the file alone does not help, because the secret stays in the commit history until you rewrite it.

    Why Cursor hardcodes API keys

    An AI assistant hardcodes a key because the quickest way to satisfy a prompt like connect to this service is to write the literal value directly into the code. The model is optimizing for working code in the moment, not for secret hygiene, so unless you steer it, it may place the key inline where it is easy to use and easy to leak.

    This is not unique to Cursor; any code assistant can do it. The fix is to make the safe path the default by telling the assistant how you handle secrets and by having guardrails that catch a hardcoded key before it ever reaches a commit. Treat the assistant as a fast junior developer who needs your conventions made explicit.

    Stop it before it happens: .env configuration

    The foundation is a .env file that holds your secrets and is excluded from git. Add .env, and variants like .env.local and .env.production, to your .gitignore so the file is never committed, and load the values through your framework's environment access, such as process.env, rather than writing them in source. Commit a .env.example with placeholder values instead, so the structure is shared without the secrets.

    Then make the assistant follow this. In Cursor, a rules file that states secrets must come from environment variables and never be inlined pushes generated code toward reading from .env rather than pasting a literal. Combined with the .gitignore, this means the normal output of the assistant keeps keys out of both your code and your commits.

    If a key already hit GitHub: rotate first

    If a key has already been pushed, rotate it before anything else. Treat any secret that reached a repository, especially a public one, as compromised, because automated bots scan GitHub for exposed keys continuously and can find and use one within minutes. Revoke the exposed key at the provider and issue a new one, so that even if it was scraped, it no longer works.

    Rotation is the step that actually protects you, and it comes first for a reason. Cleaning the git history matters, but it does not undo exposure that already happened; a key that was public for even a short time may already be in someone else's hands. Only after you have rotated should you move on to removing the secret from history.

    Purge it from history with BFG Repo Cleaner

    Once the key is rotated, remove it from the repository history so it is not handed to everyone who clones the repo. BFG Repo Cleaner is a fast, purpose-built tool for this: it rewrites history to strip a file or replace a secret across all past commits, and it is simpler for this task than raw git commands. You point it at the repo, tell it to delete the secret file or replace the secret text, then run git's garbage collection and force-push the cleaned history.

    The modern alternative is git filter-repo, which the GitHub documentation recommends for rewriting history. Either way, the operation rewrites commit hashes, so every collaborator must re-clone or reset to the new history, and any open pull requests may need to be recreated. Coordinate the rewrite with your team so no one reintroduces the old history from a stale clone.

    Why deleting the file is not enough

    Deleting the key in a new commit feels like a fix, but it only removes the secret from the current version. Git keeps every past commit, so the key still exists in the history and is visible to anyone who inspects earlier commits or clones the repo. A casual remove API key commit actually advertises exactly where to look for it.

    This is why the two real steps are rotation and history rewriting, not deletion. Rotation makes the exposed key useless, and rewriting removes it from the past commits where it would otherwise live indefinitely. Deleting the file without doing either leaves a working key sitting in your history for anyone to find.

    Prevention layers

    Good prevention is layered, so that if one control misses a key, another catches it. The table below shows how the common layers fit together and what each one stops.

    LayerWhat it doesWhat it catches
    .gitignore plus .envKeeps secret files out of commitsA committed .env file
    Assistant rulesTell Cursor to use env vars, not literalsInlined keys in generated code
    Pre-commit scannerScans staged changes for secretsA secret before it is committed
    GitHub push protectionBlocks pushes containing known secretsA secret before it reaches GitHub
    Secret scanningAlerts on secrets already in the repoA secret that was pushed

    The point of stacking them is coverage. The .gitignore stops secret files, assistant rules stop inlined keys, a pre-commit scanner catches what the first two miss, and GitHub push protection and secret scanning act as a final net at the remote. No single layer is perfect, but together they make a committed key unlikely.

    Emergency response checklist

    If a key is already exposed, act in order rather than at random. The checklist below puts the steps in the sequence that actually protects you.

    StepActionDone?
    RotateRevoke the leaked key and issue a new one[ ]
    AssessCheck the provider's logs for any misuse[ ]
    Purge historyRemove it with BFG Repo Cleaner or git filter-repo[ ]
    Force-pushPush the cleaned history; have collaborators re-clone[ ]
    Prevent recurrenceAdd a pre-commit scanner and push protection[ ]

    The order matters more than anything. Rotating first neutralizes the exposed key, assessing tells you whether it was already misused, and purging history plus adding prevention stops it from recurring. Skipping straight to history cleanup without rotating leaves you exposed to a key that may already be compromised.

    Scan the build too

    Repository hygiene handles your source and its history, but a secret can still reach users if it was compiled into the app itself, for example an assistant inlining a key that then ships in the build. That copy is not in a .env or a commit you can rewrite; it is in the artifact your users download.

    A scanner like PTKD.com analyzes your app build and reports findings ordered by severity and mapped to OWASP MASVS, including secrets embedded in the binary, so you catch a key that made it into the shipped app. To be clear about the boundary: PTKD does not rewrite your git history, rotate your keys, or configure Cursor. It checks the built artifact for the exposed secrets that repository cleanup alone cannot reach.

    What to take away

    • Cursor hardcodes keys because inlining a literal is the quickest way to satisfy a prompt; make the safe path the default with rules and guardrails.
    • Keep secrets in a git-ignored .env, load them from environment variables, and commit only a placeholder .env.example.
    • If a key reached GitHub, rotate it first, since bots find exposed keys within minutes, and treat it as compromised.
    • Remove the key from history with BFG Repo Cleaner or git filter-repo, then force-push and have collaborators re-clone; deleting the file alone does not help.
    • Add a pre-commit scanner and GitHub push protection, and scan your build with PTKD.com for secrets that reached the shipped app.
    • #cursor
    • #api key leak
    • #bfg repo cleaner
    • #git history
    • #secret scanning

    Frequently asked questions

    Why does Cursor hardcode API keys?
    Because inlining a literal value is the quickest way to satisfy a prompt like connect to this service, and the model optimizes for working code in the moment rather than secret hygiene. It is not unique to Cursor; any assistant can do it. The fix is to make the safe path the default with explicit rules and guardrails that catch a hardcoded key before it commits.
    How do I configure .env so keys are not hardcoded?
    Store secrets in a .env file and add .env, .env.local, and .env.production to .gitignore so it is never committed. Load values through environment access like process.env rather than writing them in source, and commit a .env.example with placeholders to share the structure. Add a Cursor rules file telling the assistant to use env vars, never inline literals.
    My key is on GitHub, what do I do first?
    Rotate it before anything else. Treat any secret that reached a repository, especially a public one, as compromised, because bots scan GitHub continuously and can find and use a key within minutes. Revoke the exposed key at the provider and issue a new one so it no longer works, then check the provider's logs for misuse before cleaning history.
    How do I remove a secret from git history with BFG Repo Cleaner?
    After rotating the key, use BFG Repo Cleaner to delete the secret file or replace the secret text across all past commits, then run git garbage collection and force-push the cleaned history. git filter-repo is the modern alternative GitHub recommends. The rewrite changes commit hashes, so every collaborator must re-clone or reset to the new history.
    Is deleting the file enough to remove a leaked key?
    No. Deleting the key in a new commit only removes it from the current version; git keeps every past commit, so the key still lives in history and is visible to anyone who clones the repo. A remove API key commit even advertises where to look. The real steps are rotating the key and rewriting history to strip it.
    How do I catch a secret that shipped in my app?
    Repository cleanup handles source and history, but a key an assistant inlined can still be compiled into the app that ships to users, where a .env or commit rewrite cannot reach it. A scanner like PTKD.com (https://ptkd.com) analyzes your build and reports secrets embedded in the binary, mapped to OWASP MASVS. It does not rotate keys or rewrite history; it checks the built artifact.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free