Software Engineering·July 21, 2026·8 min read

Security Best Practices for Vibe Coders

The most common security mistakes when building with AI tools — and how to avoid them. Covers API keys, environment variables, database security, authentication, and frontend vs. backend.

securityvibecodingapi-keysbeginnerstartup

The most common early-stage security disasters aren't sophisticated hacks — they're simple mistakes: an API key accidentally made public, a database left open to the internet, or a form that accepts any input. These are all preventable.

If Cartara flagged this in your diff, you may have added API calls, authentication code, or database access that touches security-sensitive patterns.


The Most Important Rule: Secrets Out of Code

An API key is like a password that gives access to a paid service. If someone gets your OpenAI key, they can run up thousands of dollars in charges on your account. Bots scan GitHub constantly for leaked keys and use them within minutes.

Never put an API key directly in your code:

```ts
// ❌ Never do this
const apiKey = "sk-abc123yourrealkey";
```

Always use environment variables instead:

```ts
// ✅ Do this
const apiKey = process.env.OPENAI_API_KEY;
```

The actual key lives in a .env file that never gets committed to Git.


Setting Up Environment Variables

The .env File

Create a .env file in your project root and put secrets there:

```
OPENAI_API_KEY=sk-abc123yourrealkey
STRIPE_SECRET_KEY=sk_live_abc123
DATABASE_URL=postgresql://user:password@host/dbname
```

Immediately add .env to your .gitignore file:

```

.gitignore

.env
.env.local
.env.production
```

Commit a .env.example with the keys but fake values so teammates know what's needed:

```

.env.example

OPENAI_API_KEY=your-key-here
STRIPE_SECRET_KEY=your-key-here
DATABASE_URL=your-database-url-here
```

When You Deploy

Set environment variables through your hosting platform's dashboard (Vercel, Railway, Render, Fly.io all have an "Environment Variables" section). Never upload your .env file — use the dashboard instead.

If You Accidentally Commit a Secret

Git remembers forever. Even if you delete the file and recommit, the secret is still in the history.

  1. Immediately revoke and regenerate the key in the service's dashboard
  2. Assume the key is already compromised — act accordingly

Frontend vs. Backend: A Critical Distinction

This is the most important security concept to understand.

Frontend = code that runs in the user's browser. Anyone can see it, inspect it, and manipulate it.

Backend = code that runs on your server. Users can't see or touch it directly.

Secrets must only exist on the backend. If your API key is in frontend JavaScript, every user of your app has your API key.

```ts
// ❌ Never call paid APIs from frontend code
// This key is visible to anyone who opens DevTools
const response = await fetch('https://api.openai.com/v1/...', {
headers: { 'Authorization': Bearer ${process.env.NEXT_PUBLIC_OPENAI_KEY} }
});

// ✅ Create a backend API route instead
// frontend calls your route, your route calls OpenAI
const response = await fetch('/api/generate', { method: 'POST', body: ... });
```


Database Security

Don't leave your database open to the internet. Default settings on many managed databases allow connections from any IP. Restrict access to your app's server only.

Use separate databases for dev and production. A mistake in development should never affect real user data. Most platforms make this easy — create a separate development database.

Enable Row Level Security (RLS) in Supabase. Without it, any logged-in user can potentially read all other users' data. Ask your AI assistant: "Enable RLS on this table so users can only see their own rows."


Authentication: Use a Provider

Building your own login system is one of the most common sources of security vulnerabilities. Password handling, session management, and token security are complex and easy to get subtly wrong.

Use an existing auth provider:

  • Clerk — easiest to set up, great UI components
  • Supabase Auth — built-in if you're already using Supabase
  • Auth0 — more powerful, slightly more setup

These handle passwords, sessions, OAuth (Google/GitHub login), and security updates automatically. See Authentication and Authorization.


Rate Limiting

If your app lets users trigger actions that cost you money (AI calls, emails, SMS), add rate limiting. Without it, a single user — or a bot — can drain your budget quickly.

```ts
// Basic rate limiting: max 10 requests per minute per user
const rateLimiter = new RateLimiter({ max: 10, windowMs: 60_000 });

app.post('/api/generate', rateLimiter.check, async (req, res) => {
// only reaches here if under the limit
});
```


What You'll See in Your Code

Security issues commonly surface in Cartara diffs as:

  • An API key variable — check it reads from process.env, not a hardcoded string
  • A new API route — ensure authentication is checked before processing
  • Database queries — ensure user data is filtered by the current user's ID
  • Frontend code calling external APIs — those calls should be in a backend route instead

If Something Goes Wrong

If you think a secret has been leaked:

  1. Revoke it immediately in the service dashboard — don't wait
  2. Generate a new key and update it in your hosting platform's environment variables
  3. Check your usage on the affected service for unexpected activity
  4. Review your git history for any other accidentally committed secrets

Speed matters. Keys found by bots are used within minutes.


Related concepts

Monitoring and Observability Basics
Monitoring tells you when your app is broken before your users do. This guide covers logs, metrics, error tracking, uptime monitoring, and the essential tools for small teams running live products.
Rate Limiting and Throttling
Rate limiting caps how many requests a client can make in a given window. It protects against abuse, runaway costs from paid APIs, and accidental self-inflicted overload.
Secrets and Config Management
Every app has settings that change between environments and sensitive values that must never leak. This guide explains the difference between config and secrets, where each should live, and how to manage rotation.

Turn shipping into understanding

Cartara measures what your team actually learns from every AI coding session.

Join the waitlist