When I built this website, I put in a rate limiter. The whole point was to stop someone from hammering the signup form and making my server spam a bunch of strangers. It worked. Five signups from one person and the door shuts.
Then I pointed an AI at my own site, told it to act like an attacker, and it walked right through that door in about forty seconds.
I want to be clear about what happened, because it is the whole lesson. I did not write bad code. I wrote careful code and still left a hole, because the hole was not in the part I was looking at. Reading your own code is not the same as attacking it. And an AI will happily do the second thing, if you ask.
The one that got me
Every request to a website can carry a little line that says "here is the IP address I am coming from." It is a real feature. Your site sits behind other servers, so the request has to carry the original visitor's address along with it.
The catch is that this line is just text the sender writes. Nothing checks that it is true. My rate limiter was counting signups per address, and I was reading the part of that line the attacker gets to make up. Change it every request, and every request looks like a brand new person. The counter never fills. The door never closes.
And every one of those requests makes my site send a real confirmation email. That is worse than a broken limit. It is an unlimited send button, pointed at anyone the attacker names, from my domain, and on my bill.
The fix was one line.

That forwarded-for line is actually a list. When the request passes through my own server on the way in, my server tacks the real address it saw onto the end. The attacker can scribble fakes on the front all day, but they cannot lie to my server about where the connection actually landed. So the fix was simple: read the end, not the front. Trust the part I write, not the part they write. Then I ran the exact same attack again and it died on the sixth request.
You do not need to be a security expert
You need to ask the right question. That is the part nobody tells the vibe-coding crowd. The AI is going to build exactly what you ask for and nothing more. If "attack this, assume you are an attacker, find what is exposed" is not a thing you say, then it is a thing that never happens. The AI does not make the mistake here. It just never brings up the thing you forgot to ask about.
The short version of the prompt is this: you are an attacker who has my code and my live site, and you are authorized to test it. Non-destructive only, do not message real people, do not dump real data. Find every way in, prove each one, then tell me the fix and why it happened.
That last part matters more than it looks. I will come back to it.
Two smaller holes, and a lie I believed
After the email bomb, the AI found two more, both on a poll feature I had built into the site.

Here is the part that stung. I had row-level security switched on for that poll table. If you glanced at the dashboard, it said protected. But the rule behind the switch said, in effect, let anybody through. So the security was on in name only. Anyone using the public key that ships in every visitor's browser could talk straight to my database, stuff the poll with fake votes, or read back the answers people typed in, completely skipping every check I had built on the front end.
My email table had the same switch on, with a rule that denied everyone by default. Same feature, opposite outcome. I would have sworn both were locked. One was.
We found both in the audit and plugged them the same day, inside about thirty minutes. I say we a lot. I mean me and the AI.
Then I ran it live on the patched site
To make the point honestly, I pointed the prompt at my live production site, on camera, with everything already fixed. It tried the doors that actually matter.

Seven held. It tried to blast my whole mailing list, blocked. Tried to read my subscriber emails with the public key, came back empty. Tried to stuff the poll and read the raw answers, blocked. Tried to find a secret key sitting in the page, none there.
It got exactly one thing. My lead-magnet downloads are fetchable without an email. And that one is a choice, not a miss. It is a convenience gate, not a security gate, and I am moving those to a real double opt-in anyway. The honest version of a security review is not "everything is perfect." It is "here is the one thing that is open, and here is why."
The reason none of the scary stuff landed is boring, and it is the actual answer. I store as little as I can. I never keep raw IP addresses, I hash them. My email list is locked to a key that never leaves my server. You cannot leak what you do not collect, and you cannot read what the public key was never allowed to touch.
The habit that matters more than any patch
Two things I want you to take from this.
The first is that security is a question you have to ask, not a feature the AI adds. So add it. Point your coding agent at your own build and tell it to break in. Red team, blue team, on your own code, before someone who is not you does it first.
The second is the one I almost missed. The audit is not the payoff. Running the attack found the holes once. But sitting with the AI afterward and asking why the poll table was open when I would have sworn it was locked, that is the part that changed me. Next time I will ask the right question before I ship, not after it is live. The tool found the bug once. Understanding why is what stops me digging the next ten.
That is the real force multiplier. Not that the AI is smart. That you finally asked it the right question, and then made it teach you the answer.



