🥴 Vibe Coder's Guide
Practical tips, security checklists, and easy-to-follow recommendations for vibe coders to make your AI-generated apps more secure.
🔑 Authentication & Authorization
- ✓Use a trusted auth provider (Auth0, Clerk, Supabase Auth, etc.) instead of rolling your own
- ✓Always require strong passwords (min 12 chars, mixed case, numbers, symbols)
- ✓Implement proper session timeouts and refresh token rotation
- ✓Validate user permissions on both client AND server
- ✓Use JWTs but store them securely (HTTP-only cookies)
🛡️ Data Validation
- ✓Validate ALL user input on the server, even if validated on the client
- ✓Use a schema validation library (Zod, Yup, Joi, etc.)
- ✓Sanitize user input to prevent XSS attacks
- ✓Use parameterized queries to prevent SQL injection
- ✓Implement rate limiting on all API endpoints
🔍 API Security
- ✓Use HTTPS for all API endpoints (no exceptions!)
- ✓Implement proper CORS policies
- ✓Add security headers (Content-Security-Policy, X-Content-Type-Options, etc.)
- ✓Hide sensitive error details in production
- ✓Use API keys with least privilege principles
💾 Database Security
- ✓Encrypt sensitive data at rest
- ✓Use database roles with minimal permissions needed
- ✓Never expose your database directly to the internet
- ✓Back up your data regularly and test restores
- ✓Use prepared statements for all database queries
🔥 Quick Fixes for Common Vibe Coding Issues
Hard-coded Secrets
// ❌ BAD: Hard-coded API keys in your code const apiKey = "sk_live_51KjD...";
// ✓ GOOD: Use environment variables const apiKey = process.env.API_KEY; // Make sure to add API_KEY to your .env file and .gitignore
Insecure Direct Object References
// ❌ BAD: Fetching data without authorization check app.get('/api/users/:id', (req, res) => { const user = db.getUser(req.params.id); res.json(user); });
// ✓ GOOD: Check that the user is authorized app.get('/api/users/:id', (req, res) => { // Verify current user has permission to access this user if (req.user.id !== req.params.id && !req.user.isAdmin) { return res.status(403).json({ error: 'Not authorized' }); } const user = db.getUser(req.params.id); res.json(user); });
Cross-Site Scripting (XSS)
// ❌ BAD: Directly inserting HTML from user input document.getElementById('content').innerHTML = userComment;
// ✓ GOOD: Sanitize user input or use framework escaping import DOMPurify from 'dompurify'; // Option 1: Sanitize HTML if you need to allow some HTML document.getElementById('content').innerHTML = DOMPurify.sanitize(userComment); // Option 2: Text content only (preferable if HTML not needed) document.getElementById('content').textContent = userComment;
📚 Resources
Recommended Tools
Attribution
Information compiled from OWASP, Mozilla Web Security Guidelines, Node.js Security Best Practices, and Auth0 Documentation.