DEV Community

Cover image for Why Cursor Keeps Hardcoding Your API Keys (And How to Stop It)
Charles Kern
Charles Kern

Posted on

Why Cursor Keeps Hardcoding Your API Keys (And How to Stop It)

TL;DR

  • AI coding assistants paste real-looking secrets straight into source files because that is what their training data did.
  • The key gets committed, pushed, and scraped from public repos within minutes.
  • Move secrets to environment variables and run a pre-commit secret scanner. That is the whole fix.

I was reviewing a small Flask app a friend built almost entirely with Cursor. Nice little tool. Then I opened the main module and the first line that wasn't an import was an OpenAI key sitting in plain text. A real one. Still active.

He didn't put it there. He asked the assistant to "add the OpenAI call" and it helpfully wired up the client, key and all. The key was his, pasted in during an earlier prompt, and the model just kept reusing it inline every time it touched that file.

The vulnerable code

This is roughly what was in there (CWE-798: Use of Hard-coded Credentials):

import openai

openai.api_key = "sk-proj-9aXfK2mQ8vNpL4rT7wYzB3cD5eF1gH6j"

def summarize(text):
    resp = openai.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": text}]
    )
    return resp.choices[0].message.content
Enter fullscreen mode Exit fullscreen mode

It runs. Tests pass. It also leaks the moment the repo goes public, and bots scan new GitHub commits for exactly this pattern in seconds.

Why this keeps happening

The model learned from millions of tutorials and StackOverflow answers where the author dropped a literal key inline to keep the example short. That shortcut is everywhere in the training data, so the model treats inline secrets as the normal way to show working code. It has no concept of which strings are sensitive. To the model, "sk-proj-..." is just a string that makes the example complete.

The fix

Pull the secret out of source entirely:

import os
import openai

openai.api_key = os.environ["OPENAI_API_KEY"]
Enter fullscreen mode Exit fullscreen mode

Put the real value in a .env file, add .env to .gitignore, and catch mistakes before they ship with a scanner:

pip install pre-commit
# .pre-commit-config.yaml with gitleaks
gitleaks detect --source . --no-banner
Enter fullscreen mode Exit fullscreen mode

Then rotate the key that was already exposed, because once it touches a commit it is burned.

I've been running SafeWeave for this. It hooks into Cursor and Claude Code as an MCP server and flags hardcoded secrets before I move on to the next file. That said, even a basic pre-commit hook with gitleaks will catch most of what's in this post. The important thing is catching it early, whatever tool you use.

Top comments (0)