If you're feeling unstoppable after a vibe-coding session, do this before you do anything else: ask Claude for a full security audit of what it just built. Then tell it to fix everything it found. Rinse and repeat until the audit comes back clean.
It works because the AI reviews your code against a checklist it knows cold — SQL injection, XSS, CSRF, session handling, credential storage, access control. It catches stuff you'd never think to look for, which matters most if you didn't come up through traditional development.
Security researchers have found that roughly 45% of AI-generated code contains vulnerabilities, including command injection, hardcoded secrets, and SQL injection flaws (DXTalks).
To show you what that actually looks like, here are ten real findings from audits Claude ran on my own apps — the severity it assigned, and how each one got fixed. This is one audit pass.
High severity
- Account passwords stored in plaintext. One app encrypted its vault entries with AES-256-GCM but stored a separate accounts table's passwords as raw text. One database dump and every password is readable. Fix: encrypt those the same way as the vault, with a backward-compatible helper and a one-time migration for the existing rows.
- Auth token sitting in browser localStorage. A "remember me" token was being written to localStorage, where any XSS or sketchy browser extension can grab it. Fix: move it into an httpOnly, Secure, SameSite=Strict cookie so JavaScript can't see it at all.
- Plaintext password fallback in a login check. A builder app checked the password against a freshly hashed value — but also had a fallback comparison straight against the plaintext password in config.php. Anyone who could read that file had the password. Fix: store a pre-hashed password and verify against it with one
password_verify()call.
Medium severity
- Subscription bypass through Stripe parameters. A success page activated an account from a subscription ID in the URL without checking the subscription belonged to the logged-in user. Anyone with any valid Stripe subscription ID could turn their account on for free. Fix: confirm the subscription's customer matches the logged-in user's Stripe customer ID before activating.
- Session fixation window. The login flow called
session_regenerate_id(false). Thefalsemeans the old session file never gets deleted, so a pre-login session ID stays alive. Fix: change it totrue. One character. - Change-password didn't check the current password. The endpoint only checked the new password's length. A hijacked session could change the password and lock the real owner out. Fix: require the current password and verify it server-side before allowing the change.
- XSS in the confirmation-modal system. PHP escaped a filename correctly, but the JavaScript modal read it back out of a data attribute — which the browser HTML-decodes — and dropped it into
innerHTML. A file named with anonerrorpayload runs the second a moderator clicks it. Fix: set the modal's text withtextContent, notinnerHTML. - Missing CSRF check on an admin action. An admin "view as another user" endpoint skipped CSRF verification, so a forged request could make an admin open someone else's data. Fix: add the same
verifyCsrf()call every other state-changing action already had.
Low severity
- No CSRF token on the login form. This lets an attacker quietly log the victim into the attacker's account, so the victim ends up entering their data into it. Low impact, but real. Fix: add a CSRF token to the login form like every other form.
- HTTPS not forced. The HTTP-to-HTTPS redirect in
.htaccesswas commented out. Session cookies only get flagged Secure when HTTPS is detected, so a plain HTTP request ships the cookie in the clear. Fix: uncomment the redirect.
These security issues are the same handful of mistakes showing up app after app — credential storage, session handling, output escaping, access control. That's exactly why an audit is critical: the failure modes are predictable, and an AI that's seen thousands of them finds yours fast.
But the audit is only as good as your ability to read the results and judge them. Severity is a judgment call. "Encrypt those passwords" can be done a dozen right ways and a dozen wrong ones. If you've never lived the full software development life cycle, you can run the audit — but you won't always know which findings to lean on or whether the fix actually fixed anything. It's a force multiplier, not a substitute for knowing what you're looking at.
Leave a comment