Course:Internet & Tools/
Lesson

AI tools cause more secret leaks than any other single factor in modern development. ChatGPT hardcodes APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. keys in every code sample it generates. Copilot autocompletes console.log(process.env.SECRET_KEY) without hesitation. Claude will write a deployment script that puts your database password in a shell command visible in CI logs. These are not hypothetical risks, they are patterns that happen daily, and they are how startups end up with surprise $40,000 AWS bills from crypto miners exploiting leaked credentials.

What counts as a secret

Not everything in your .env file is equally sensitive. Knowing the difference helps you decide how carefully to protect each value.

CategoryExamplesTreat as secret?
CredentialsDatabase passwords, OAuth client secretsAlways
API keysStripe, OpenAI, SendGrid, AWS access keysAlways
Signing keysJWT secrets, webhook signing keys, encryption keysAlways
TokensSession tokens, refresh tokens, deploy tokensAlways
Internal URLsPrivate API endpoints, internal service addressesSometimes
Public configPort numbers, log levels, feature flags, app nameNo

The test: could someone impersonate your app, access your data, or run up charges if they had this value? If yes, it is a secret.

02

How AI leaks your secrets, five real patterns

These are the five most common ways AI tools compromise your secrets. Learn to recognize them on sight.

Pattern 1: Hardcoded credentials in source code

// ChatGPT generated this "working" Stripe integration
const stripe = require('stripe')('sk_live_4eC39HqLyjWDarjtT1zdp7dc');

// Copilot autocompleted this database connection
const pool = new Pool({
  connectionString: 'postgres://admin:SuperSecret123@db.example.com:5432/production'
});

Pattern 2: Logging secrets to console

// Claude suggested this "debugging" code
console.log('Connecting with key:', process.env.STRIPE_SECRET_KEY);
console.log('JWT Secret:', process.env.JWT_SECRET);
// These appear in server logs, CI output, and monitoring dashboards

Pattern 3: Exposing server secrets to the browser

// Copilot doesn't distinguish client vs server variables
// This puts your secret key in the JavaScript bundle served to users
const apiKey = import.meta.env.VITE_STRIPE_SECRET_KEY; // WRONG prefix!
// Anyone can see this in DevTools > Sources

Pattern 4: Secrets in AI-generated CI/CDWhat is ci/cd?Continuous Integration and Continuous Deployment - automated pipelines that test your code on every push and deploy it when tests pass. configs

yaml
# ChatGPT generated this GitHub Actions workflow
- name: Deploy
  run: |
    curl -X POST https://api.cloudflare.com/client/v4/deploy \
      -H "Authorization: Bearer cf_token_abc123" \  # Hardcoded in the workflow file!
      -d '{"project": "myapp"}'

Pattern 5: Missing .gitignore entries

# AI never mentions adding .env to .gitignore
# It generates the .env file, you commit everything, secret is in git forever
git add .
git commit -m "initial setup"  # .env is now in history
After every AI-generated code session, do a manual audit: search your staged files for string patterns like sk_, api_key, password, secret, token, and any string longer than 20 characters that looks random. This single habit prevents most secret leaks.
03

The cardinal rule: fail if a secret is missing

It is tempting to provide a default fallback for secrets so your app starts in development without a complete .env. Resist that temptation:

// BAD - if API_KEY is missing in production, the app silently uses a fake key
// that fails at the worst possible moment
const API_KEY = process.env.API_KEY || 'dev-key-do-not-use';

// GOOD - if API_KEY is missing, the app refuses to start
const API_KEY = process.env.API_KEY;
if (!API_KEY) {
  throw new Error('FATAL: API_KEY is required but was not set');
}

For a production-grade validation pattern:

// secrets.js - validate all secrets at startup
function requireSecret(name) {
  const value = process.env[name];
  if (!value) {
    console.error(`FATAL: Required secret ${name} is not set.`);
    console.error('Set it in your .env file (dev) or platform dashboard (prod).');
    process.exit(1);
  }
  return value;
}

module.exports = {
  stripeKey: requireSecret('STRIPE_SECRET_KEY'),
  jwtSecret: requireSecret('JWT_SECRET'),
  databaseUrl: requireSecret('DATABASE_URL'),
};
04

Platform secrets management

Every serious hosting platform stores secrets separately from your code, encrypted at restWhat is rest?An architectural style for web APIs where URLs represent resources (nouns) and HTTP methods (GET, POST, PUT, DELETE) represent actions on those resources.. Use the platform's secrets system in production, never deploy with .env files.

Vercel

# Add a secret linked to an environment
vercel env add STRIPE_SECRET_KEY production
# Vercel prompts you to type the value securely

# Secrets are encrypted and scoped per environment
# Development, Preview, and Production each have their own values

Cloudflare Workers

# Wrangler prompts for the value - it never appears in shell history
wrangler secret put STRIPE_SECRET_KEY

# Access in your Worker code via the env binding
export default {
  async fetch(request, env) {
    const stripe = new Stripe(env.STRIPE_SECRET_KEY);
  }
};

Railway

Railway auto-provisions and injects database credentials when you add a database service. For custom secrets, use the Variables tab in your project dashboard. Railway injects them automatically at runtimeWhat is runtime?The environment that runs your code after it's written. Some languages need a runtime installed on the machine; others (like Go) bake it into the binary..

AWS / GCP / Azure

For enterprise projects, use a dedicated secrets manager: AWS Secrets Manager, Google Secret Manager, or Azure Key Vault. They add versioning, automatic rotation, and detailed access audit logs.

PlatformHow to set secretsEncryptionScoping
VercelCLI or dashboardAt restPer environment
Cloudflarewrangler secret putAt restPer Worker
RailwayDashboard VariablesAt restPer service
AWS Secrets ManagerCLI or consoleAt rest + in transitPer secret, IAM policies
Google Secret ManagerCLI or consoleAt rest + in transitPer secret, IAM policies
05

Sharing secrets with teammates safely

The instinct when someone says "I need the dev database password" is to paste it in Slack. Do not do that, chat logs are kept forever and are often not encrypted at restWhat is rest?An architectural style for web APIs where URLs represent resources (nouns) and HTTP methods (GET, POST, PUT, DELETE) represent actions on those resources..

MethodSecurityConvenience
Password manager (1Password, Bitwarden)High, encrypted, access-controlledMedium, requires team setup
Platform dashboardHigh, encrypted, audit loggedHigh, self-service
Encrypted message (age, gpg)High, end-to-end encryptedLow, requires tooling
Slack / Discord DMLow, stored in plaintext logsHigh, but dangerous
EmailLow, stored on mail serversMedium, easy to search/leak

For new teammates: document the process in your README. Copy .env.example, reach out to a specific person, get credentials through a secure channelWhat is channel?A typed conduit in Go used to pass values between goroutines - can be unbuffered (synchronous) or buffered (async queue)..

06

Detecting and responding to leaked secrets

Prevention with git hooks

git-secrets prevents you from committing known secret patterns:

# Install and configure
brew install git-secrets   # macOS
cd your-repo
git secrets --install      # Adds pre-commit hook
git secrets --register-aws # Adds AWS key patterns

# Scan before committing
git secrets --scan         # Current files
git secrets --scan-history # Entire git history

GitHub also runs automatic secret scanning on public repos and will alert you if it detects a credential pattern from a known providerWhat is provider?A wrapper component that makes data available to all components nested inside it without passing props manually..

If a secret leaks

Act immediately, assume the secret is already being exploited:

  1. Rotate the credential in the service's dashboard (generate new key, revoke old one)
  2. Update the new value in your secrets manager and all deployment platforms
  3. Scrub git history with git filter-repo if the secret was committed, then force-push
  4. Audit access logs to check if the secret was used by unauthorized parties
  5. Notify your team that the old credential is compromised and the new one is deployed
Removing a secret from git history does not help if the repo was ever public, forked, or cloned before you caught it. Rotation is always the first priority, scrubbing history is a secondary cleanup step.
07

Key rotation habits

Rotating secrets reduces the blast radius of any single leak:

  • Rotate high-value keys quarterly (Stripe, AWS, database passwords)
  • Rotate immediately when a team member with production access leaves the company
  • Rotate immediately if a .env file is accidentally shared or committed
  • Use short-lived tokens where the service supports it (OAuth2What is oauth?An authorization protocol that lets users grant a third-party app limited access to their account on another service without sharing their password., temporary AWS credentials)
  • Keep a rotation log, document when each secret was last rotated and by whom
08

Quick reference

ActionTool / Method
Store production secretsPlatform dashboard (Vercel, Cloudflare, Railway)
Share dev secrets safelyPassword manager (1Password, Bitwarden)
Prevent committing secretsgit-secrets pre-commit hook + .gitignore
Scan for leaked secretsgit secrets --scan-history, GitHub secret scanning
Respond to a leakRotate immediately, update platforms, scrub history
Validate at startuprequireSecret() function that exits on missing values
Audit AI-generated codeSearch for hardcoded strings, console.log of secrets