Security & Safety Considerations For Your Small/Personal [Perhaps] Vibe-Coded Web Apps
Just one section in this weekend Bonus Drop, as we’re weaving in some security & safety advice for your vibe[-less] coded mini/personal web apps as well as source for an app I’ve been non-vibe-coding (but 100% vibe-checking) for the past two weeks. It’s just a simple app that renders a preview of OpenGraph tags on a given website. I’ve been obsessed with OpenGraph tags since they became a standard (I have no idea why), and have been vowing to write an app like this every time the interstitial “buy now” modals pop up on opengraph.xyz.

Given the focused functionality, I was tempted to vibe code it, but — since I decided to host it on the big, bad internet — there was no way I was trusting Claude (et al.) to make something that could withstand the poking I see everyday across the global honeypot sensor fleet I help shape and manage.
In reality, there’s no such thing as a “just personal” web app anymore. The moment you put something on the internet, even if it’s just running on your little VPS that nobody knows about, you’ve painted a target on it. Bots don’t care if your app is personal or professional. They scan everything. They probe everything. They try to break everything. They abuse everything.
So, let’s take a look at the safety/security features that we baked into this app, then discuss what you should do if you are still determined to vibe code something that’s going to be on the internet.
SSRF Protection: Your Server Isn’t a Proxy Service
The purpose of this app is to fetch content and render part of it. So, the first thing that keeps me up at night with any URL-fetching service is SSRF (Server-Side Request Forgery). You give users the ability to make your server fetch any URL, and suddenly some clever person realizes they can try to make your server scan your internal network, hit cloud metadata endpoints, or worse.
My solution? Block everything that even smells like a private IP:
- No localhost (sorry,
127.0.0.1) - No private ranges (
10.x.x.x,192.168.x.x, etc.) - No link-local addresses
- HTTP and HTTPS only – no
file://, nogopher://, no weird protocols
Is this paranoid? Maybe. But I’d rather explain why someone can’t preview their local development site than explain why my server was used to map someone’s network.
Rate Limiting: Bots Gonna Bot
Within minutes of deploying this app, I had bots hitting it. Not malicious bots necessarily, just…bots doing bot things. Crawling, indexing, poking around.
The rate limiting isn’t just about protecting my server resources (though that’s important). It’s about being a good citizen. When my app fetches OpenGraph data, it’s making requests to other people’s servers. If someone decides to hammer my API, I don’t want to become an unwitting participant in a DDoS attack.
So I set up different limits:
- Regular browsers: 10 requests per minute (reasonable for a human clicking around)
- Anything that looks like a bot: 1 request per minute (and yes, I check
User-Agents, though that is not a panacea)
CSRF Tokens: One-Time Use, No Exceptions
CSRF protection might seem like overkill for a simple preview tool. But, I don’t know how someone might try to chain this tool with other exploits. Maybe they’re trying to use it to make authenticated requests from a victim’s browser. Maybe they’re trying to use it as part of a more complex attack.
So every request gets a fresh CSRF token. Use it once, and it’s gone. Try to reuse it? Nope. Try to use someone else’s token? Double nope. The tokens expire after 15 minutes too, because why leave them lying around?
The Little Things That Add Up
Then there are all the “small” security features that nobody notices until they prevent something bad:
- Content Security Policy: Sure, my app doesn’t execute user-provided JavaScript, but belt and suspenders, right?
- Request size limits: 1KB max for request bodies. If you need more than that to send me a URL, something’s fishy.
- URL length limits: 2,048 characters max. That’s the RFC recommendation, and it prevents various overflow shenanigans.
- Referrer validation: Requests should come from my domain, not from someone else’s attack page.
- Security headers galore:
X-Frame-Options,X-Content-Type-Options, the full monty. - Input Sanitizaon: We don’t trust any input provided to this app; it’s paranoia that will pay off in the long run.
INVOKING MANDATORY "LONG POST" CAT PICTURE PROTOCOL

If You’re Still Intent On Publising Vibe-coded Apps
I had Claude take a look at my app and appsec-focused code and it made some suggestions (such as tightening up the JWT implementation). It also suggested some separation-of-concerns improvement I ultimately accepted (those are as important as security/safety code).
If you’re determined to be a vibe-first coder, then it is important to tell your coding assistant that you care about safety/securty up-front. Otherwise it will do what we all do, and that is to take the easy path first, then try to bolt on some safety checks (and that always ends badly). To that end, here are some prompts you can add to your AGENT.md/CLAUDE.md to help the LLM take security into account as it probabilistically generates barely functional code… (NOTE: Claude refined each of these for me, but it mostly just sentence-ized things and I’m not sure the extra blather is necessary.)
Foundation Security Prompts
Build a [web app/API/service] that processes user input with defense-in-depth security. Include:
- Input validation with allowlist approach (specify what’s allowed, reject everything else)
- SSRF protection blocking private IPs, localhost, and internal networks (including IPv6)
- Rate limiting with both per-IP and distributed attack protection
- CSRF tokens that are cryptographically secure and single-use
- Security headers including CSP without unsafe-inline or unsafe-eval
Show me the security middleware first, then the business logic.
Threat Modeling Prompts
Before we code, identify the OWASP Top 10 risks for this [feature/endpoint]. For each risk:
- Explain how it could be exploited in our context
- Provide specific mitigation code
- Include test cases to verify the protection works
Start with the highest risk scenarios.
*Input Validation Prompts**
Create input validation for [user data] that:
- Uses a schema validation library (like Zod, Joi, or Yup)
- Validates data types, formats, and business rules
- Implements length limits based on actual requirements
- Blocks potentially dangerous patterns (SQL, NoSQL, command injection)
- Sanitizes output based on context (HTML, SQL, shell, URL)
Include comments explaining what each validation prevents.
Authentication & Authorization Prompts
Implement authentication that:
- Never stores sensitive data in code or config files
- Uses environment variables with validation for secrets
- Implements proper session management with timeout
- Includes API key rotation mechanism if applicable
- Logs authentication attempts for security monitoring
Show me both the happy path and how it handles attacks.
Rate Limiting & DoS Protection Prompts
Design rate limiting that protects against:
- Brute force attacks (progressive delays)
- Distributed attacks (not just IP-based)
- Resource exhaustion (memory/CPU limits)
- Slow POST/Slowloris attacks
- Bot traffic vs legitimate users
Include cleanup mechanisms to prevent memory leaks.
Error Handling & Logging Prompts
Implement error handling that:
- Never exposes internal details to users
- Logs security events with enough detail for forensics
- Uses different error messages for different audiences (user vs logs)
- Includes correlation IDs for tracing
- Rate limits error responses to prevent enumeration
Show examples of what to log vs what to show users.
Code Review Security Prompts
Review this code for security vulnerabilities:
[do whatever you do to tell your assistant where the code is]
Check for:
- Injection vulnerabilities (SQL, NoSQL, Command, LDAP, XPath)
- Authentication/authorization bypasses
- Sensitive data exposure (keys, passwords, PII in logs)
- SSRF/CSRF/XSS possibilities
- Rate limiting gaps
- Memory leaks or DoS vectors
For each issue found, provide:
- Severity level
- How it could be exploited
- Fixed code
- Test to verify the fix
API Security Prompts
Create an API endpoint that:
- Validates Content-Type and Accept headers
- Implements request size limits
- Uses request signing or HMAC for sensitive operations
- Includes request timeout protection
- Validates referrer/origin for browser requests
- Returns consistent error structures that don’t leak information
Include example curl commands showing both valid and malicious requests.
Data Protection Prompts
Implement data handling that:
- Sanitizes all user input before storage
- Escapes output based on context (HTML, JavaScript, SQL, URL)
- Implements field-level encryption for sensitive data
- Includes data retention/deletion policies
- Prevents timing attacks on sensitive comparisons
Show me the data flow from input to storage to output with security controls at each step.
Context-Specific Security Prompts
Build a frontend form that:
- Validates input client-side AND server-side
- Implements CSRF protection with rotating tokens
- Sanitizes display of user-generated content
- Uses CSP-compatible event handlers (no inline JavaScript)
- Includes aria-labels that don’t expose sensitive info
Explain the security purpose of each validation.
For Database Operations
Create database queries that:
- Use parameterized queries exclusively (no string concatenation)
- Implement row-level security where applicable
- Include audit logging for sensitive operations
- Use least-privilege database accounts
- Handle connection pool exhaustion gracefully
Show examples of prevented SQL injection attempts.
For File Uploads
Implement file upload that:
- Validates file types by content, not extension
- Implements size limits and quota management
- Stores files outside web root
- Generates random filenames
- Scans for malware if applicable
- Prevents path traversal attacks
Include tests showing how each attack vector is blocked.
For Session Management
Design session handling that:
- Generates cryptographically secure session IDs
- Implements proper session timeout (idle and absolute)
- Regenerates session ID on privilege elevation
- Securely transmits sessions (Secure, HttpOnly, SameSite flags)
- Implements concurrent session limits
Show the complete session lifecycle with security controls.
FOR THE LAZY FOLKS LIKE ME
If you’re impatient, at least keep these key phrases to include in prompts handy for quick use:
- “with defense in depth”
- “following OWASP guidelines”
- “include security comments”
- “show prevented attack examples”
- “with audit logging”
- “using principle of least privilege”
- “with input validation and output encoding”
- “including rate limiting and timeout protection”
- “with secure defaults”
- “fail securely with generic error messages”
Remember: the LLMs are only going to do what you tell them (and, they will make 💩 up if you aren’t precise).
FIN
You are now armed with principles, prompts, and real examples of ensuring the safety and security of your vibe[-less] coded mini/personal web apps.
Remember, you can follow and interact with the full text of The Daily Drop’s free posts on:
- 🐘 Mastodon via
@dailydrop.hrbrmstr.dev@dailydrop.hrbrmstr.dev - 🦋 Bluesky via
https://bsky.app/profile/dailydrop.hrbrmstr.dev.web.brid.gy
☮️
Leave a comment