The vibe-coding era has produced a generation of apps that work — but were never designed with security in mind. When you're shipping with AI, the AI doesn't know your deployment environment. It doesn't know what's in your .env file, what your web server exposes, or that your .git folder is sitting in your web root.

The result is a class of vulnerabilities that aren't sophisticated at all. They're not zero-days. They're not complex injection attacks. They're just things that are sitting in plain sight — accessible to anyone with a browser and five minutes.

Here are the five most common data exposure issues in AI-built apps, and exactly how to check if you're vulnerable right now.

Before you start: Replace yoursite.com in every command below with your actual domain. Run each check from your terminal or just paste the URL into a browser. If you get back anything other than a 404 or an error page, you have a problem.
1
Is your .env file accessible?

Your .env file contains every secret your app needs to run: database credentials, API keys, OAuth secrets, encryption keys. It was never meant to be served over the web — but in a surprising number of deployed apps, it is.

Run this check
curl -s https://yoursite.com/.env | head -20
# Or just open this URL in your browser:
# https://yoursite.com/.env
🚨 If you see anything other than a 404: Your database password, Stripe secret key, and every other credential your app uses just became public. Anyone who finds this URL — and attackers scan for it automatically — owns your database.
Why AI-built apps get this wrong: When you build with Cursor or Lovable, the AI generates a .env file and tells you to configure it. It doesn't automatically configure your web server to deny access to dotfiles. If you're using a static host or a misconfigured Express server, the file is served like any other.
✓ How to fix it: Add a rule to your web server to block access to .env and all dotfiles. For Express: app.use((req, res, next) => { if (req.path.startsWith('/.')) return res.status(404).end(); next(); }). For Nginx: location ~ /\. { deny all; }. For Vercel: add to vercel.json. Also: add .env to your .gitignore if it isn't already.
2
Is your git history exposed?

If your .git directory is accessible over the web, attackers can reconstruct your entire codebase — including files you deleted from your repository. Including .env files you committed and then removed. Including API keys you "rotated" six months ago but forgot to actually revoke.

Run this check
# Check 1: Is the .git folder exposed?
curl -s https://yoursite.com/.git/HEAD

# If you see something like "ref: refs/heads/main"
# your entire git history is downloadable.

# Check 2: Can the config file be read?
curl -s https://yoursite.com/.git/config
🚨 If .git/HEAD returns a ref: Your full source code is recoverable. Tools like git-dumper can reconstruct your entire repository from an exposed .git folder in minutes. Every commit, every deleted file, every secret ever committed is now recoverable.
Why this happens: When you deploy by syncing a folder to a server, or when your build process copies the entire project directory to the web root, the .git folder comes along for the ride. AI tools that generate deployment scripts don't always exclude it. Neither do "deploy to Heroku" one-click buttons if you don't check what they're uploading.
✓ How to fix it: Block access to .git at the web server level. Nginx: location ~ /\.git { deny all; }. Apache: add RedirectMatch 404 /\.git to your .htaccess. If you're on a platform like Render or Railway, verify your deploy is building from source (not copying a local folder with .git included). Better: your build output directory should never contain .git at all.
3
Are your API keys in client-side JavaScript?

This one is subtle and extremely common in AI-generated code. When you ask an AI to "add Stripe to my app" or "integrate the OpenAI API," it will sometimes generate code that puts the secret key directly in your frontend JavaScript. The logic is sound from a "getting it to work" perspective. The security implications are catastrophic.

Run this check
# View your page source and search for key patterns
curl -s https://yoursite.com | grep -iE "(sk_live|sk_test|api_key|secret|token)" | head -20

# Also check your main JS bundle
# Open DevTools → Sources → look for sk_live_, Bearer tokens,
# or anything that looks like a secret in your .js files
🚨 If you find a live secret key: Anyone who views your page source can extract it. There are bots that continuously scrape public websites looking for exposed API keys. Your Stripe account will be drained. Your OpenAI bill will explode. Your users' data is accessible to anyone.
Why AI-generated code does this: AI models generate code that works in isolation. When you describe "call the OpenAI API from my React app," the model produces a solution that works — but it includes the API key directly in the frontend because that's the simplest working implementation. It doesn't architect a backend proxy because you didn't ask for one.
✓ How to fix it: Secret keys belong on the server, never the client. Any API call that requires a secret key should go through your backend: client → your server endpoint → third-party API. Your frontend should only ever hold public keys (like Stripe publishable keys, not secret keys). Audit every fetch() and axios call in your frontend code and make sure none of them contain credentials.
1 in 5
public GitHub repos contain at least one hardcoded secret (GitGuardian, 2025)
24 hrs
average time before an exposed AWS key is exploited after being pushed to GitHub
4
Is your admin panel password-protected?

AI tools love generating admin panels. They're one of the first things you ask for: "add an admin dashboard where I can see all users." The panel gets built, it works, and it gets deployed. But does it actually require authentication? Is it at a predictable URL? Is the authentication bypassable?

Run this check
# Try common admin paths directly in your browser:
https://yoursite.com/admin
https://yoursite.com/admin/dashboard
https://yoursite.com/admin/users
https://yoursite.com/dashboard
https://yoursite.com/api/admin/users

# For each one: do you get a login prompt, or do you get data?
🚨 If any admin route returns data without auth: Every user record, every order, every piece of private data in your system is accessible to anyone. Attackers enumerate common admin paths automatically. Your admin panel is not hidden by obscurity — it will be found.
Why this happens: When AI generates an admin route, it often focuses on the functionality first. Authentication middleware is added as a follow-up step — and sometimes the follow-up step doesn't happen, or the middleware is applied inconsistently. It's also common for AI-generated code to protect the UI but leave the underlying API endpoints unprotected.
✓ How to fix it: Audit every route that starts with /admin or serves sensitive data. Every single one should go through authentication middleware before returning anything. Also check your API routes: /api/users, /api/admin/*, /api/reports — any endpoint that touches user data needs auth. Consider moving your admin panel to a non-standard path and adding IP allowlisting for extra protection.
5
Are you logging sensitive data?

This one is invisible until it's a problem. AI-generated code is enthusiastic about logging — it adds console.log() and debug statements liberally, because they're helpful for development. The problem is that those logs often end up in production, and they often contain things that should never appear in a log: passwords, tokens, user emails, request bodies with payment information.

Run this check
# Search your codebase for problematic logging patterns
grep -r "console.log" . --include="*.js" | grep -iE "(password|token|secret|email|credit|card|ssn|auth)" | head -20

# Also check: does your error handler log the full request body?
# Does your ORM log queries with interpolated values?
# Does your auth middleware log the Authorization header?
❌ Common AI-generated pattern — leaks credentials
// This logs everything, including passwords
app.post('/api/login', (req, res) => {
  console.log('Login attempt:', req.body); // ← Logs username + password
  const { email, password } = req.body;
  // ...
});

// This leaks tokens
app.use((err, req, res, next) => {
  console.error('Error:', req.headers); // ← Logs Authorization header
  res.status(500).json({ error: err.message });
});
✓ Fixed version — logs safely
// Log only what you need — never sensitive fields
app.post('/api/login', (req, res) => {
  console.log('Login attempt for:', req.body.email); // ← Safe
  const { email, password } = req.body;
  // ...
});

// Sanitize error logs
app.use((err, req, res, next) => {
  console.error('Error on', req.method, req.path, err.message); // ← Safe
  res.status(500).json({ error: 'Internal server error' });
});
🚨 Why this matters beyond compliance: Your logs are often stored in cloud logging services (Papertrail, Logtail, Datadog) that have their own access controls and retention policies. A data breach doesn't require someone to break into your database — reading your logs may be enough. Under GDPR, logging user passwords or unmasked emails in production can constitute a reportable breach.
✓ How to fix it: Audit every console.log and console.error in your codebase. Never log full request bodies on auth endpoints. Never log the Authorization header. Use a logging library that supports redaction (like pino with redact option). In production, set your log level to warn or error — debug logs should never run in prod.

The 10-Minute Security Checklist

Run all five checks right now. It takes less time than your last standup. Here's the summary:

Found something? Don't panic — but act fast. Rotate every credential that may have been exposed. Check your cloud provider logs for unusual access in the past 30 days. If user data was accessible, you likely have breach notification obligations.

These aren't edge cases

Every single one of these checks catches real vulnerabilities in real production apps, every week. The founders who build with AI tools aren't careless — they're moving fast, and security review isn't part of the vibe-coding workflow.

The fixes are simple. The exposure, if left unchecked, is not. A single crawled .env file is enough to drain your database, max out your cloud bill, and send breach notifications to your entire user base.

Run the checks. Fix what you find. Then go back to shipping.