What you'll learn
- ✓Understand the 5 security rules for AI-assisted development
- ✓Protect API keys with .env files and .gitignore
- ✓Run npm audit and fix vulnerabilities
- ✓Complete the security deployment checklist
Why Security Matters More Than Ever
Here is a statistic that should get your attention: studies have found that nearly half of all AI-generated code contains security vulnerabilities. Not because the AI is malicious -- because security requires intentional, defensive thinking that AI does not always prioritize. AI optimizes for "does it work?" not "is it safe?"
When you write code with Claude Code, the code works. It runs, it does what you asked, and it often looks clean and professional. But "working" and "secure" are two different things. A door with no lock works perfectly fine -- until someone walks through it who should not.
This lesson is the most important one on the trail. The concepts here are not optional best practices you can skip. They are rules. Follow them every time, and your projects will be safe. Skip them once, and you risk exposing your API keys, your data, or your users' information.
⚠️This Is Not Theoretical
Real people have had their AWS accounts drained of thousands of dollars because they accidentally committed an API key to a public GitHub repository. Bots constantly scan GitHub for exposed secrets. If your key is public for even a few minutes, assume it has been compromised.
The 5 Security Rules
These five rules cover the vast majority of security issues you will encounter as a builder using AI tools. Memorize them. Follow them without exception.
Rule 1: AI-Generated Code Is Untrusted Code
All code needs review before it ships -- AI-generated code is no exception. Professional developers review each other's work, and you should review AI-generated code the same way.
What to do:
- Read the code changes before accepting them
- If you do not understand something, ask Claude Code to explain it
- Pay special attention to code that handles user input, database queries, or authentication
> Review this file for security vulnerabilities:
src/app/api/users/route.ts
💡 Tip
You do not need to understand every line at a deep technical level. But you should be able to explain what each file does and why it exists. If a file is a mystery to you, that is a red flag.
Rule 2: Secrets Are Sacred
API keys, database passwords, tokens, and credentials are secrets. They grant access to services that can cost you money, expose your data, or compromise your users. Treat every secret like your bank password.
The rules for secrets:
- NEVER put a secret directly in a code file
- NEVER commit a secret to Git
- ALWAYS use environment variables (
.envfiles) - ALWAYS add
.envto.gitignorebefore your first commit - If you accidentally expose a secret, revoke it immediately and generate a new one
Here is the correct pattern:
# BAD -- secret is directly in the code
# src/lib/supabase.ts
const supabase = createClient(
'https://abc123.supabase.co',
'your-supabase-publishable-key-here'
)
# GOOD -- secret comes from environment variable
# src/lib/supabase.ts
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
)
# .env.local (NOT committed to Git)
NEXT_PUBLIC_SUPABASE_URL=https://abc123.supabase.co
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=your-supabase-publishable-key-here
# .gitignore (committed to Git)
.env
.env.local
.env*.local
⚠️ Warning
If you ever see Claude Code put an actual API key, password, or token directly in a code file, stop immediately and fix it. Move the value to .env.local and replace it with process.env.VARIABLE_NAME. This is a non-negotiable rule.
Rule 3: Less Access Is More Safety
The principle of least privilege says: give every tool, user, and service the minimum access it needs to do its job. Nothing more.
In practice:
- If your app only reads from the database, use a read-only database key
- If an MCP server only needs access to one table, do not give it access to all tables
- If a feature does not need admin permissions, do not use admin credentials
- If a user should not see certain data, enforce that at the database level with Row Level Security
-- Instead of allowing everything:
CREATE POLICY "Allow all" ON projects
FOR ALL USING (true);
-- Be specific about what is allowed:
CREATE POLICY "Users can read their own projects" ON projects
FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "Users can insert their own projects" ON projects
FOR INSERT WITH CHECK (auth.uid() = user_id);
Rule 4: Review Every Diff
When Claude Code changes your code, a diff shows you exactly what was added, removed, or modified. Read it. Every time.
# See what changed since your last commit
git diff
# See a summary of changed files
git diff --stat
You are looking for:
- Hardcoded secrets that should be environment variables
- New dependencies you did not ask for
- Changes to files you did not expect to change
- Code that handles user input without validation
- Database queries built with string concatenation (a sign of SQL injection risk)
> Show me a summary of all changes since the last commit
and flag anything that might be a security concern.
💡Diff Before You Commit
Make this a habit: run git diff before every git commit. It takes 30 seconds and catches problems before they become part of your history. Once something is committed and pushed, it is much harder to fully remove.
Rule 5: Commit Often, Revert Freely
Git is your safety net. Commit every time something works. If the next change breaks something, you can revert to the working state instantly.
# The safe workflow:
git add .
git commit -m "Working state: projects page loads from database"
# Now make a risky change...
# If it breaks:
git checkout .
# You are back to the working state. No damage done.
The opposite of this -- making many changes without committing -- is dangerous. If you go an hour without committing and something breaks, you have to manually figure out what went wrong across dozens of changes. Commit often, and each revert is surgical.
Where API Keys Should (and Should Not) Live
| Where | Safe? | Details |
|---|---|---|
| .env.local | Yes | Local development, not committed to Git |
| Vercel dashboard | Yes | Production environment, encrypted storage |
| Source code files | NO | Will be committed to Git and exposed |
| Git history | NO | Even deleted keys persist in history |
| Chat messages | NO | Do not paste keys into Claude conversations |
What to Do If You Expose a Key
Even experienced developers accidentally commit a secret. The response must be immediate:
- Revoke the key immediately in the service's dashboard
- Generate a new key and update
.env.localand your deployment platform - Remove it from Git history using
git filter-branchor BFG Repo Cleaner - Check for unauthorized usage in the service's logs
Security Audit Your Project
Run through this audit on your current project. Do not skip any step.
- Check for exposed secrets in code:
# Search for common secret patterns in your code
grep -r "sk-" src/ --include="*.ts" --include="*.tsx"
grep -r "eyJ" src/ --include="*.ts" --include="*.tsx"
grep -r "password" src/ --include="*.ts" --include="*.tsx"
If any of these return actual secret values (not process.env references), fix them immediately.
- Verify .gitignore:
cat .gitignore
Confirm these entries exist:
.env
.env.local
.env*.local
node_modules/
- Run npm audit:
npm audit
This checks all your installed packages for known security vulnerabilities. If it finds any:
# Automatically fix what it can
npm audit fix
# For remaining issues, review them manually
npm audit
- Check your Git history for secrets:
# Search recent commits for potential secrets
git log --all --oneline -20
git diff HEAD~5..HEAD
- Verify environment variables:
# Make sure .env.local exists and has your secrets
ls -la .env.local
# Make sure .env.local is NOT tracked by Git
git status
If .env.local appears in the Git status output (not as ignored), you have a problem. Add it to .gitignore immediately.
The npm audit Command
When you install packages with npm, you are trusting code written by thousands of developers. npm audit checks every package against a database of known vulnerabilities.
Severity levels: Low (fix when convenient), Moderate (fix before deploying), High (fix before deploying -- serious), Critical (fix immediately).
npm audit # Check for vulnerabilities
npm audit fix # Auto-fix what it can
npm audit fix --force # Force major version updates (test afterward!)
⚠️ Warning
The --force flag can introduce breaking changes by upgrading to major new versions. Test your app afterward. If things break, revert with git checkout . and address vulnerabilities manually.
The Security Deployment Checklist
Before you deploy anything to the internet, walk through this checklist. Every item should be checked.
⚠️Pre-Deployment Security Checklist
Secrets:
- .env.local file exists and contains all secrets
- .env.local is listed in .gitignore
- No API keys, tokens, or passwords in any code file
- No secrets in any commit in your Git history
- Environment variables are set in your deployment platform (Vercel)
- .env.example exists with placeholder values (no real secrets)
Dependencies:
npm auditshows no high or critical vulnerabilities- You can explain what every installed package does
- No unnecessary packages are installed
Code quality:
- All user inputs are validated (forms, URL parameters, etc.)
- Database queries use parameterized statements (not string concatenation)
- You have reviewed the AI-generated code, not just accepted it blindly
- Error messages do not expose internal details to users
Infrastructure:
- HTTPS is enabled (Vercel handles this automatically)
- Database has Row Level Security enabled
- Service role keys are NEVER used in frontend code
- Admin endpoints (if any) require authentication
Building Security Habits
Security is not a one-time task. It is a set of habits that become automatic with practice. Here are the habits to build:
Before every commit:
git diff # Review what changed
git status # Check no secret files are staged
Before every deployment:
npm audit # Check for vulnerable packages
When installing new packages:
> Before installing this package, are there any known security
concerns with it? Is it actively maintained?
When Claude Code modifies sensitive files:
> Show me exactly what changed in the API route and confirm
no secrets are hardcoded.
The Security Mindset
The most important takeaway is not any specific command -- it is the habit of asking: "What happens if someone sees this code on GitHub? What if this key gets exposed? Do I understand what this code does before I ship it?" That security instinct gets stronger with practice.
Paw Print Check
Before moving on, make sure you can answer these:
- 🐾What are the 5 security rules, and can you explain each one in a sentence?
- 🐾Where should API keys be stored, and where should they NEVER be stored?
- 🐾What does npm audit do, and how often should you run it?
- 🐾What should you do immediately if you accidentally commit a secret to GitHub?
- 🐾Why is reviewing AI-generated code important even if it works correctly?
Next Up
The Agentic Landscape
Move beyond single tools into multi-agent systems, orchestration patterns, and the future of AI-assisted development.