Skip to content

Why Does AI-Generated Code Sometimes Expose API Keys and Secrets?

Problem

When I read Reddit threads about AI coding assistants, I kept seeing complaints about exposed API keys. Developers were shocked when their AI-generated code contained hardcoded secrets in clear text.

The exposed secrets problem
┌─────────────────────────────────────────────────────────────┐
│ │
│ const apiKey = "sk-proj-abc123xyz789"; │
│ const dbPassword = "myPassword123"; │
│ │
│ → API key leaked to git history │
│ → Unauthorized API usage │
│ → Financial charges on your account │
│ → Data breach │
│ │
└─────────────────────────────────────────────────────────────┘

I asked myself: Why does AI-generated code expose secrets?

Environment

  • AI coding assistants: Claude, ChatGPT, GitHub Copilot
  • Context: Building applications that connect to external APIs
  • Security concern: Secrets management in AI-assisted development

What happened?

The original poster in the Reddit thread asked:

OP's question
"What am I missing? What are people doing to get all the mess
and api keys in clear?"

A comment (3 points) gave the direct answer:

The root cause
"The messy code / exposed keys stuff is usually just lack of
basic discipline, not the tool itself"

Another comment (2 points) added:

Expert judgment needed
"Ai is pretty useless without having skills enough to know
when it's wrong"

I realized the problem isn’t the AI tool. It’s how developers use it.

The Solution

Immediate Fixes

  1. Never paste API keys into AI chat interfaces

AI models may store or log your conversations. Hardcoded secrets in prompts can end up in training data or logs.

  1. Use environment variables for all secrets
config.js - Correct approach
const apiKey = process.env.API_KEY;
const dbPassword = process.env.DB_PASSWORD;
if (!apiKey || !dbPassword) {
throw new Error("Missing required environment variables");
}
async function fetchData() {
const response = await fetch("https://api.example.com/data", {
headers: {
"Authorization": `Bearer ${apiKey}`
}
});
return response.json();
}
  1. Provide AI with code templates that use environment variables
Secure prompt template
"Write me a function to call the OpenAI API using environment
variables for the API key. Never hardcode secrets."
  1. Run security audits on generated code before deployment
Security audit flow
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ AI Generates │ → │ Security │ → │ Deploy │
│ Code │ │ Audit │ │ (Safe) │
└─────────────┘ └─────────────┘ └─────────────┘

Long-term Practices

  1. Use .env files locally (never commit them)
.env.example
# .env - Add to .gitignore!
API_KEY=sk-proj-your-actual-key-here
DB_PASSWORD=your-secure-password
  1. Configure git hooks to scan for secrets pre-commit
pre-commit hook with secret scanning
#!/bin/bash
# Scan for potential secrets before commit
git diff --cached | grep -E "(api[_-]?key|secret|password|token)" && \
echo "Potential secret detected! Review your changes." && exit 1
  1. Use secrets management tools
  • AWS Secrets Manager
  • HashiCorp Vault
  • Azure Key Vault
  • Google Secret Manager
  1. Establish clear security boundaries in AI prompts
Security-focused prompt
"Implement authentication with these requirements:
- All secrets must come from environment variables
- No hardcoded credentials anywhere in the code
- Add validation for missing environment variables
- Log all authentication events for audit
- Follow OWASP authentication best practices"

The Reason

I think the key reason for exposed secrets is lack of developer discipline.

AI coding assistants generate code based on patterns in their training data. When training examples contain hardcoded values, AI may replicate this pattern.

The problem compounds when:

  • Developers provide AI with existing code containing hardcoded secrets
  • AI models don’t understand security context or production implications
  • No explicit instructions are given to use environment variables
  • Code generation focuses on functionality over security
AI's perspective
┌─────────────────────────────────────────────────────────────┐
│ │
│ AI sees: "const apiKey = '...'" in training data │
│ AI thinks: "This pattern makes code work" │
│ AI generates: Same pattern to make your code work │
│ │
│ Missing: Security context, production implications │
│ │
└─────────────────────────────────────────────────────────────┘

A comment (2 points) noted:

AI's trust boundary issue
"Recently, left to its own devices, opus did a very interesting thing...
decided to establish really poor trust boundaries through the
entire app stack"

AI can propagate security anti-patterns without explicit guidance.

Why This Matters

Exposed API keys lead to:

  • Unauthorized API usage and financial charges
  • Data breaches
  • Account compromise
  • Reputation damage
  • Compliance violations (GDPR, HIPAA, SOC2)
Impact of exposed secrets
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ API Key │ → │ Attacker │ → │ Your │
│ Exposed │ │ Access │ │ Losses │
└─────────────┘ └─────────────┘ └─────────────┘
Financial, Data, Reputation, Compliance

Common Mistakes

I identified these mistakes developers make:

  1. Copying generated code directly to production without review

  2. Assuming AI-generated code is automatically secure

  3. Not understanding local vs production security differences

  4. Skipping security audits for “quick prototypes” that become production

  5. Trusting AI to establish security boundaries without explicit guidance

The bad pattern AI might generate

BAD - Never do this
// ❌ NEVER DO THIS - AI might generate this pattern
const apiKey = "sk-proj-abc123xyz789";
const dbPassword = "myPassword123";
async function fetchData() {
const response = await fetch("https://api.example.com/data", {
headers: {
"Authorization": `Bearer ${apiKey}`
}
});
return response.json();
}

The secure pattern to explicitly request

GOOD - Always request this pattern
// ✅ ALWAYS DO THIS - Explicitly request AI to use env vars
const apiKey = process.env.API_KEY;
const dbPassword = process.env.DB_PASSWORD;
if (!apiKey || !dbPassword) {
throw new Error("Missing required environment variables");
}
async function fetchData() {
const response = await fetch("https://api.example.com/data", {
headers: {
"Authorization": `Bearer ${apiKey}`
}
});
return response.json();
}

Summary

In this post, I explained why AI-generated code sometimes exposes API keys and secrets. The key point is that the problem stems from lack of developer discipline, not inherent flaws in AI tools.

AI doesn’t understand security context. It generates functional code patterns from training data. Without explicit guidance to use environment variables, AI may output hardcoded secrets.

Security must be explicitly requested and audited. Never paste secrets into AI interfaces. Always review generated code before deployment.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments