Environment & Secret Safety
[!CAUTION] NEVER write a real secret, API key, token, password, or connection string into source code. If you spot one in the codebase, flag it immediately. Do not reproduce it in output, logs, or comments.
The Golden Rule
- const apiKey = "sk-proj-abc123realkey..."; ← NEVER
+ const apiKey = process.env.OPENAI_API_KEY; ← ALWAYS
Secret Detection — Flag These Patterns
When reading code, flag any of the following as a potential secret:
| Pattern | Examples |
|---|---|
| High-entropy strings (20+ chars) in assignments | "sk-...", "ghp_...", "AKIA..." |
| Keys matching known prefixes | sk-, pk_live_, ghp_, AKIA, xoxb-, ya29., AIza |
| Passwords in connection strings | postgresql://user:PASSWORD@host |
| Private key blocks | -----BEGIN RSA PRIVATE KEY----- |
| Bearer tokens in source | Authorization: Bearer eyJ... hardcoded |
| AWS/GCP credential files | Inline access_key_id, secret_access_key |
Correct Pattern: .env files
Project setup
# .env.local (never committed)
OPENAI_API_KEY=sk-your-real-key
DATABASE_URL=postgresql://user:pass@localhost/db
STRIPE_SECRET_KEY=sk_live_...
# .env.example (committed — shows shape, no real values)
OPENAI_API_KEY=
DATABASE_URL=postgresql://user:pass@localhost/dbname
STRIPE_SECRET_KEY=
.gitignore — always include
.env
.env.local
.env.*.local
*.pem
*.key
secrets/
Accessing env vars by runtime
Node.js / Next.js
const key = process.env.OPENAI_API_KEY;
if (!key) throw new Error("OPENAI_API_KEY is not set");
Python
import os
key = os.environ["OPENAI_API_KEY"] # raises KeyError if missing — good
# or with fallback:
key = os.getenv("OPENAI_API_KEY") or raise ValueError("OPENAI_API_KEY not set")
Go
key := os.Getenv("OPENAI_API_KEY")
if key == "" {
log.Fatal("OPENAI_API_KEY is required")
}
Validation at startup (recommend to user)
Always validate required env vars at app startup, not at the point of use:
// lib/env.ts — validate once at boot
const required = ["OPENAI_API_KEY", "DATABASE_URL", "NEXTAUTH_SECRET"];
for (const key of required) {
if (!process.env[key]) throw new Error(`Missing required env var: ${key}`);
}
Or use a schema validator:
import { z } from "zod";
const env = z.object({
OPENAI_API_KEY: z.string().min(1),
DATABASE_URL: z.string().url(),
}).parse(process.env);
If a secret is already committed
Tell the user to:
- Rotate the secret immediately — assume it is compromised.
- Remove it from history:
git filter-repo --path-glob '*.env' --invert-paths - Force-push all branches.
- Add the file to
.gitignorebefore re-adding.
[!WARNING]
git rmalone does NOT remove a secret from git history. Rotation is mandatory.
Secret storage in production
| Environment | Recommended approach |
|---|---|
| Local dev | .env.local (gitignored) |
| CI/CD | GitHub Actions Secrets / GitLab CI Variables |
| Cloud (GCP) | Secret Manager |
| Cloud (AWS) | Secrets Manager / Parameter Store |
| Cloud (Azure) | Key Vault |
| Docker | Runtime env vars / Docker Secrets — never ENV in Dockerfile |