vibeAudit tells you your app isn't secure. So we asked the obvious question: is vibeAudit secure? We pointed our own scanner at ourselves. Here's the honest answer.
No. Not at first. We had real vulnerabilities. Our own tool caught them. Here's every single one.
Skeptical of security tools that never admit flaws? So are we. Try vibeAudit on your own app — 30 seconds, free. Read-only scan, your app is never modified.
Finding 1: Missing Security Headers
Our first deploy had no Content Security Policy headers. None. Zero. A basic XSS attack could have loaded external scripts on our domain. Our scanner flagged it immediately with a "Medium" severity rating.
We added them the same day. It took 5 minutes.
# What we added to our FastAPI middleware:
@app.middleware("http")
async def add_security_headers(request, call_next):
response = await call_next(request)
response.headers["Content-Security-Policy"] = (
"default-src 'self'; script-src 'self'; "
"style-src 'self' 'unsafe-inline'; "
"img-src 'self' data: https:; "
"connect-src 'self' https://api.stripe.com"
)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
return response
Claude Code never suggested adding these headers. Not once across the entire build. It built our whole web layer without a single security header. (More on what Claude Code misses)
Finding 2: Stack Traces Leaking to the Browser
Our FastAPI app was running in development mode. When something broke, the full Python traceback went straight to the browser. File paths, library versions, internal function names — all visible to anyone who triggered an error.
An attacker could use this to map our tech stack and find known vulnerabilities in our dependencies. We added a production error handler:
# Before: FastAPI default — full traceback in response
# After: Custom exception handler for production
@app.exception_handler(Exception)
async def production_error_handler(request, exc):
# Log the full error server-side
logger.error(f"Unhandled exception: {exc}", exc_info=True)
# Return generic message to the client
return JSONResponse(
status_code=500,
content={"detail": "Internal server error"}
)
Finding 3: No Rate Limiting on the Scan Endpoint
Our core feature — the /api/scan endpoint — had zero rate limiting. Someone could have sent a thousand scan requests per second, burning through our resources and potentially using us as a proxy to hammer other people's sites.
Claude Code built the endpoint. It worked perfectly. It never once suggested adding rate limiting. We added it after our own scan flagged it.
# What we added:
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@app.post("/api/scan")
@limiter.limit("3/minute")
async def scan_url(request: Request, data: ScanRequest):
# ... scan logic
How many of your endpoints are missing rate limits? vibeAudit checks for rate limiting gaps — paste your URL to find out. Read-only scan, your app is never modified.
Finding 4: Session Tokens in URL Parameters
Early versions of vibeAudit passed session data in query strings. That means session tokens showed up in server logs, browser history, and any analytics tools. If someone shared a URL from their dashboard, they were potentially sharing their session.
We moved to httpOnly cookies. It took an afternoon to refactor.
# Before — token in URL (bad):
# /dashboard?session=eyJhbGciOiJIUzI1NiJ9...
# After — httpOnly cookie (safe):
response.set_cookie(
key="session",
value=token,
httponly=True,
secure=True,
samesite="lax",
max_age=86400
)
Finding 5: Open Redirect on Payment Success
After a successful Stripe payment, we redirected users to a URL passed as a parameter. The problem: we didn't validate that URL. An attacker could craft a payment link that redirected users to a phishing site after they paid. "Thanks for your purchase — now enter your password on this fake login page."
We added URL validation. Only redirects to our own domain are allowed now.
# Before — any redirect URL accepted:
redirect_url = request.args.get("redirect", "/")
return redirect(redirect_url)
# After — validated against allowed domains:
from urllib.parse import urlparse
ALLOWED_HOSTS = {"vibeaudit.net", "www.vibeaudit.net"}
def safe_redirect(url: str) -> str:
parsed = urlparse(url)
if parsed.netloc and parsed.netloc not in ALLOWED_HOSTS:
return "/"
if parsed.scheme and parsed.scheme not in ("https", ""):
return "/"
return url
Every App Has Vulnerabilities. Including Security Tools.
We're not embarrassed by this list. We're proud of it. Every app has vulnerabilities — the question is whether you find them before your users do.
A security scanner that pretends to be perfect is lying to you. We'd rather show you our scars and prove the tool works. We eat our own dog food. You should too. (Here's the full security checklist for AI-built apps)
FAQ
Q: Did vibeAudit find vulnerabilities in itself?
Yes. We found 5 issues: missing CSP headers, stack trace leaks, no rate limiting, session tokens in URLs, and an open redirect. We fixed all 5.
Q: Is vibeAudit safe to use on my app?
Yes. vibeAudit runs read-only scans. It never modifies your app, writes data, or stores your results.
Don't trust us — test us. Paste your URL into vibeAudit and see what your AI-built app is hiding. 30 seconds, free, no signup. (Or read our security testing guide first.) Read-only scan, your app is never modified.