Vibe Coding Security: What AI Won't Tell You

Marcus ThompsonMarcus ThompsonStartup Builder
Priya SharmaPriya SharmaAI Engineering Lead
13 min read

In early 2025, a founder shipped a social platform for AI agents. He built it entirely with AI tools. He said publicly that he "didn't write one line of code."

Security firm Wiz scanned it shortly after launch. They found a misconfigured database with open read and write access. Exposed: 1.5 million authentication tokens. 35,000 email addresses. Private messages between agents.

The app worked perfectly. It just had no security.

This is the vibe coding security problem in one story. The AI generates code that functions. It rarely generates code that is hardened. Veracode's 2025 GenAI Code Security Report found that nearly 45% of AI-generated code contains security flaws. That is not a niche edge case. That is almost half of everything being shipped right now by the fastest-growing cohort of builders in software history.

The good news: most of these vulnerabilities are predictable, and most of the fixes are straightforward. You do not need to be a security engineer. You need this checklist and the discipline to actually use it.

Vibe coding security checklist infographic covering 8 categories: secrets management, authentication, package safety, SQL and data safety, rate limiting, CORS and permissions, storage and payments, and security ops
The complete vibe coding security checklist — 8 categories, what to do, what never to do

Your Secrets Are Already Leaking

This is where most vibe coding security failures begin. Not with sophisticated attacks. With a .env file committed to GitHub or an API key pasted into a chat window.

Never paste API keys into AI chats. When you share a key with an AI assistant, that key travels through servers you do not control. Depending on the provider's data handling policies, it may be logged, used for training, or exposed in a breach. Use process.env.YOUR_KEY in your code. Store the actual value in a .env file that never leaves your machine. Reference environment variables by name when asking the AI to write code that needs them.

.gitignore is your first file, not your last. Before you write a single line of code, before you even initialize the project, create your .gitignore. Your .env file goes in it immediately. So does any file that might contain credentials, private keys, or service account JSON files. The number of times I have seen a developer commit a .env.local file three days into a project and then spend an afternoon rotating every secret in it is not small.

Rotate secrets every 90 days minimum. This is not paranoia. This is hygiene. API keys, database passwords, webhook secrets: all of them get rotated on a calendar. Services like Doppler or AWS Secrets Manager can automate this. Even a simple reminder in your calendar is better than never rotating at all. If you suspect a key was exposed at any point, rotate it that day, not eventually.

If you have ever pasted an API key into Claude, ChatGPT, or Cursor chat, rotate that key now. Not after finishing this post. Now.

Never Let AI Build Your Authentication

Authentication is the single most dangerous thing to get wrong, and it is also one of the things AI gets consistently wrong. Not because the AI is careless. Because auth has a thousand edge cases that only surface in production, and AI training data contains a lot of outdated, insecure auth implementations.

Kaspersky's analysis of vibe coding risks found that AI coding assistants frequently generate authentication using deprecated algorithms like MD5 for password hashing. A vibe coder who does not know the difference between MD5 and Argon2 will accept this code because it works, unknowingly leaving their users' passwords crackable in seconds with modern hardware.

Use Clerk, Supabase Auth, or Auth0. Full stop. These products exist because authentication is genuinely hard. Password hashing, session management, CSRF protection, account recovery, MFA, OAuth flows, brute force protection: all of it is already solved and battle-tested in these services. The cost of using them is a few dollars a month and an afternoon of integration time. The cost of rolling your own auth is an eventual security incident.

When you ask an AI to "add authentication," it will generate something that works. It will probably use bcrypt for password hashing, which is at least correct. But it will miss things. The password reset flow might not properly expire tokens. The session might not invalidate on logout. The "remember me" cookie might have the wrong flags. You will not know until someone exploits one of these.

Set session expiration with JWT max 7 days and refresh token rotation. If you are using JWTs, access tokens should expire in 15 minutes to an hour. Refresh tokens can live longer, but they must rotate on every use. A refresh token that gets stolen should only be usable once. The moment it is used, issue a new one and invalidate the old. This limits the blast radius of a stolen token to a single request.

The Packages AI Suggests Can Hurt You

This one is underappreciated, and it is getting worse.

AI models are trained on code that includes package names. Some of those packages have been abandoned. Some are deprecated with known vulnerabilities. And in an emerging attack pattern called "dependency confusion" or "package hallucination," AI models sometimes suggest packages that do not actually exist. Attackers register those names on npm before you realize what happened. Retool's analysis of vibe coding risks calls this out as one of the most underappreciated attack vectors in AI-generated codebases.

Verify every package the AI suggests before installing. Before running npm install anything, check the package on npmjs.com. Confirm it exists. Check the download count. Check the last publish date. Check who maintains it. A package with 12 downloads and no activity in three years should raise a flag.

Always ask for newer, more secure package versions. AI training data skews toward older, more documented versions of packages. Ask explicitly: "Is this the latest stable version? Are there known security issues with this version?" Then check npm or the GitHub repo yourself.

Run npm audit fix right after building. Every project, every time. npm audit scans your installed dependencies against a database of known vulnerabilities. npm audit fix resolves the ones it can automatically. For the ones that require manual intervention, the output tells you exactly what is vulnerable and why. This takes 30 seconds. There is no reason not to do it.

Every Input Is an Attack Surface

SQL injection has been on the OWASP Top 10 for over a decade. It still causes breaches every year. Why? Because developers, including AI systems, continue to build database queries by concatenating user input with SQL strings.

Sanitize every input and use parameterized queries always. Never build a query like "SELECT * FROM users WHERE email = '" + userEmail + "'". A user who types ' OR '1'='1 into that email field now has access to your entire users table. Use your database library's parameterized query syntax instead: the library handles escaping, and the query structure cannot be altered by user input no matter what they type.

This applies to everything: form fields, URL parameters, API request bodies, file names, headers. If it comes from outside your system, treat it as hostile until proven otherwise.

Enable Row-Level Security from day one. If you are using Supabase or any Postgres-based system, RLS is a database-level policy that controls which rows a user can read, write, or delete. Without it, your backend code is the only thing between a user and every row in your database. With it, even if your backend has a bug that passes the wrong user ID, the database itself enforces the boundary.

Enable it before you write your first API endpoint. Adding it later means auditing every existing query to make sure nothing breaks. Starting with it costs you an hour of reading documentation. Skipping it costs you much more.

Runtime Hygiene and Access Control

These are the controls that feel obvious but get skipped under launch pressure.

Remove all console.log statements before shipping. Every console.log(user) or console.log(apiResponse) you leave in production is a potential data exposure. Logging services like Sentry, Datadog, or LogRocket capture these. So do browser developer tools when users inspect your frontend. Strip them before deployment, or use a logging library that you can disable in production.

CORS should only allow your production domain. Never wildcard. Access-Control-Allow-Origin: * means any website can make requests to your API using a visitor's browser credentials. That is not an acceptable configuration for anything that handles real user data. Lock CORS to your specific production domain and, if needed, a specific list of staging domains.

Validate all redirect URLs against an allow-list. Open redirects are a common phishing vector. If your app takes a redirect_url parameter and forwards users there without checking it, an attacker can craft a link that looks like it goes to your app but actually redirects to a malicious site. Maintain a list of allowed redirect destinations and reject anything not on it.

Check permissions server-side. UI-level checks are not security. Hiding a button from a user who does not have admin access is good UX. It is not security. Anyone with a browser developer tool or a direct API client can bypass UI checks. Every sensitive action, deletion, role change, payment, export, must be validated on the server against the authenticated user's actual permissions.

Rate Limiting: The Control Most Vibe Coders Skip

Rate limiting is the security control that feels unnecessary until the moment it is critically necessary.

Apply auth and rate limits to every endpoint, including mobile APIs. Mobile apps are not protected by security-through-obscurity. Anyone can intercept their traffic with a proxy. Your mobile API endpoints need the same rate limiting, authentication, and input validation as your web endpoints.

Rate limit everything from day one. 100 requests per hour per IP is a start. This is a baseline, not a ceiling. Adjust based on your actual usage patterns. But having no rate limit at all means a single automated script can hit your API thousands of times per minute, run up your costs, scrape your data, or attempt credential stuffing attacks at scale.

Password reset routes get their own strict limit: 3 per email per hour. Password reset endpoints are among the most abused in production systems. Without a specific limit, an attacker can use your reset flow to enumerate valid email addresses or to spam your users. Three attempts per email per hour stops abuse while still working for legitimate users who clicked the wrong thing.

Costs, DDoS, Storage, and Payments

Cap AI API costs in your dashboard and in your code. If you are calling OpenAI, Anthropic, or any AI API in your product, set hard spending limits in the provider's dashboard. Then add a check in your code that tracks usage and fails gracefully when limits are approached. An AI feature with no cost cap is an open-ended financial liability. A single automated abuse scenario or a viral traffic spike can generate thousands of dollars in API costs before you notice.

Add DDoS protection via Cloudflare or Vercel edge config. Both Cloudflare (free tier covers most small apps) and Vercel's edge middleware can absorb and filter malicious traffic before it reaches your application servers. This is infrastructure-level protection that costs nearly nothing to set up.

Lock down storage buckets. Users should only access their own files. An S3 bucket or Supabase Storage bucket configured as public read is readable by anyone who knows or can guess the URL. User-uploaded files should be private by default, served through signed URLs with expiration times. Combine this with RLS policies so users cannot access each other's files even through your API.

Limit upload sizes and validate file type by signature, not extension. A user can rename a PHP script to photo.jpg and upload it. Extension-based validation catches the naive case. Signature-based validation checks the actual bytes at the start of the file against known file format signatures. Libraries like file-type in Node.js do this automatically. Set maximum upload sizes in both your frontend and your API. A file upload endpoint with no size limit is a denial-of-service waiting to happen.

Verify webhook signatures before processing any payment data. Stripe, Paddle, and every serious payment processor sign their webhook payloads with a secret. Before you process any webhook event, verify the signature. This prevents an attacker from hitting your webhook endpoint with a fake "payment succeeded" event.

Use Resend or SendGrid with proper SPF, DKIM, and DMARC records. Transactional email that lacks these DNS records will land in spam, and your domain can be spoofed for phishing attacks. These records are configured in your DNS and take about 30 minutes to set up correctly. They are not optional if you are sending email from a domain you care about.

Use the AI as Your Security Engineer

Here is the most underused security tool in a vibe coder's arsenal: the same AI that wrote the code.

Ask the AI to act as a security engineer and review your code. After building a feature, paste the relevant code into Claude or your AI of choice and ask: "Act as a security engineer. Review this code for vulnerabilities. Focus on authentication, input validation, SQL injection, XSS, and data exposure." The AI will often catch things it did not catch when it was writing the code, because the task is now explicit. This is not a substitute for a real security audit, but it catches low-hanging fruit in minutes.

Ask the AI to try and hack your app. Tell Claude: "Here is my API. You are a penetration tester. What attacks would you try? What inputs would you send? What endpoints would you probe first?" You will get a list of attack vectors you had not considered. Then go fix them before a real attacker finds them.

We have done this on projects built with Claude Code and the results are consistently useful. The AI finds IDOR vulnerabilities (insecure direct object references, where changing an ID in a URL gives you someone else's data), rate limiting gaps, and missing authorization checks with surprising regularity.

Log critical actions. Every deletion. Every role change. Every payment. Every bulk export. These events should be logged with a timestamp, the authenticated user's ID, and enough context to reconstruct what happened. When something goes wrong, your logs are the only way to answer "what happened, when, and who did it?"

Compliance, Backups, and Environment Separation

Build a real account deletion flow. GDPR fines are not theoretical. The right to erasure is a legal requirement for users in the EU, and courts in multiple jurisdictions have extended similar protections elsewhere. When a user deletes their account, their personal data must actually be deleted, not just soft-deleted or flagged as inactive. Build the deletion flow before you launch, not after you receive your first legal notice.

Automate backups and test restoration. An untested backup is nothing. Backups that you have never restored from are not backups. They are the feeling of having backups. Automate your database backups on a schedule. Then once a month, actually restore from a backup into a test environment and confirm the data is correct and complete. The moment you need to restore from a backup is not the time to find out the process does not work.

Keep test and production environments completely separate. Different databases. Different API keys. Different service accounts. Different environment variables. An action taken in the test environment should never touch production data, and production credentials should never be present in your local development environment.

Never let test webhooks touch real systems. Stripe and most payment processors have test mode webhooks. Use them. Your staging environment should be configured to receive test webhooks only, with test-mode API keys. A test webhook hitting a production endpoint can trigger real emails, real charges, or real fulfillment depending on your system.

The Security Mindset Vibe Coding Requires

Here is the honest framing: vibe coding removes most of the friction from building software. That is its power. But security has always lived in the friction. The careful review before committing. The second opinion on the authentication flow. The five minutes spent reading what a package actually does before installing it.

When the AI removes friction, it sometimes removes the friction that was protecting you.

Databricks framed this well: vibe coding fundamentally breaks traditional application security models by creating a development culture where pre-production security tools are bypassed entirely. The core philosophy of pure vibe coding prioritizes speed above all else, creating a workflow that is incompatible with the friction of legacy security gates.

The fix is not to slow down. It is to make security habits as fast as the building habits. A CLAUDE.md file that instructs your AI agent to always use parameterized queries, always validate inputs, always use environment variables for secrets costs you ten minutes to write and saves you from an entire category of vulnerabilities on every project going forward.

The 45% vulnerability rate in AI-generated code is real. But it is not destiny. It is the baseline for developers who treat security as an afterthought.

The security layer is your job. The AI cannot want it for you.


Sources


FAQ

What is the biggest security risk in vibe coding?

Secret exposure is the most common: API keys committed to version control, pasted into AI chat windows, or hardcoded in source files. The second biggest is insecure authentication, where AI generates functional but vulnerable auth flows. Both are preventable with the checklist above.

Should I build authentication myself when vibe coding?

No. Use Clerk, Supabase Auth, or Auth0. Authentication has too many edge cases, too many security-critical decisions, and too much ongoing maintenance for a vibe-coded custom implementation to be reliable. The cost of these services is far lower than the cost of a single auth-related breach.

How do I prevent SQL injection in AI-generated code?

Always use parameterized queries, also called prepared statements. Never concatenate user input directly into a SQL string. When reviewing AI-generated database code, look for any string that uses + or template literals to build a query with variable input and replace it with your library's parameterized equivalent.

What is Row-Level Security and why does it matter?

Row-Level Security (RLS) is a database-level access control policy that restricts which rows a user can read, write, or delete based on their identity. In Supabase and Postgres, you define policies like "users can only select rows where user_id matches their authenticated ID." This means even if your backend code has a bug, the database itself enforces the boundary. Enable it from day one.

How do I rate limit an API built with AI tools?

Most frameworks have middleware for this. In Next.js, use Vercel's edge rate limiting or a library like upstash/ratelimit. In Express, use express-rate-limit. Ask your AI to "add rate limiting to all API routes with a limit of 100 requests per hour per IP, and a separate limit of 3 per email per hour on the password reset route" and it will generate the implementation. Then verify it actually works.

What does it mean to validate file types by signature?

File extensions can be renamed by anyone. A malicious user can name a script photo.jpg. Signature-based validation checks the actual bytes at the beginning of the file against known patterns for each format. For example, JPEG files always start with FF D8 FF. Libraries like file-type in Node.js do this check automatically and return the actual file type regardless of the extension.

Does GDPR apply to my vibe-coded app?

If your app has any users in the European Union, yes. GDPR requires you to delete personal data when a user requests it, to be able to export a user's data on request, and to have legitimate grounds for processing their data. Build the account deletion flow before you launch. The fine structure for violations starts at 2% of global annual revenue or 10 million euros, whichever is higher.

Stay in the loop. Get weekly tutorials on building software with AI coding agents. Speak to the community of Builders worldwide.

Free forever, no spam. Tutorials, tool reviews, and strategies for founders, PMs, and builders shipping with AI.

Learn More