The Vibe Coding Problem
"Build me a user authentication system with Stripe payments."
The AI delivers. The code looks clean. It passes the tests. It deploys to production.
Six weeks later, a researcher finds that the OTP verification code is returned in the API response body. Every account on the platform is takeable without inbox access.
This is not hypothetical. We've found this exact vulnerability — OTP in response body — on multiple platforms built by AI coding tools. We've found hardcoded AES keys in production JavaScript bundles. We've found Basic Auth credentials shipped to browsers. We've found authentication middleware that redirects to localhost:3200 in production.
What AI Assistants Get Wrong About Security
1. Authentication Middleware That Breaks in Production
AI-generated middleware often has subtle environment assumptions:
// AI generated this. Looks fine locally.
const signInUrl = new URL(`${req.nextUrl.origin}/sign-in`)
return NextResponse.redirect(signInUrl)
Problem: req.nextUrl.origin in Next.js middleware resolves from the internal Node.js request — http://localhost:3200 — even when the public URL is https://yourapp.com. The redirect sends users to localhost.
Result: Authentication breaks silently in production while appearing to work in development.
2. OTP Leaked in API Response
AI assistants frequently generate password reset flows that leak verification codes:
// AI generated this. Do you see the problem?
app.post('/api/reset-password', async (req, res) => {
const otp = generateOTP()
await sendEmail(req.body.email, otp)
// "helpful" error message for debugging
res.json({
success: true,
message: 'OTP sent',
debug: { otp } // CRITICAL: OTP in response
})
})
We've seen production variants of this across multiple platforms. Every account is compromised the moment someone reads the response body.
3. Hardcoded Secrets in Client Bundles
AI tools often generate server-side logic and client-side logic in the same file, then bundle it:
// In your React component, AI-generated
const AES_KEY = "super_secret_key_1234" // goes to the browser
const IV = "initialization_vec" // goes to the browser
We found a production fintech app with AES encryption keys and Basic Auth credentials fully readable in the browser's source view. The security team thought their data was encrypted. It wasn't — anyone could decrypt it.
4. Missing Authorization on Admin Routes
AI generates happy-path code well. It generates security edge cases poorly:
// AI generated admin API — missing the auth check
export async function GET(req: Request) {
const users = await db.select().from(usersTable)
return Response.json(users)
}
The AI added authentication to the frontend route guard. It forgot to add it to the API route itself. The API is directly accessible.
5. SQL Injection via Template Literals
When AI generates database queries under time pressure or with less context:
// AI generated — vulnerable to injection
const query = `SELECT * FROM users WHERE email = '${email}'`
await db.execute(query)
This appears in AI-generated code far more often than in human-reviewed code, because the AI optimizes for making the demo work, not for production safety.
What To Do About It
The Pedro Security Review Process
After every major AI-generated feature:
- Check every new API route — does it require authentication?
- Grep your bundles for secrets:
grep -r "secret\|key\|password\|token" public/ - Test authentication flows without session cookies
- Test with real HTTP requests, not just browser navigation
- Run an automated scan against the production URL
Pedro catches these automatically. Every endpoint is tested unauthenticated. Every response is scanned for credential patterns. Every redirect is verified.
Scan your AI-generated app →