The security holes AI coding assistants ship most often
· Arketo team
The awkward thing about AI-written vulnerabilities is that they aren't bugs. The code does exactly what it was asked to do. The hole is in what nobody asked for, and since a vibe-coded app has no reviewer beyond the person prompting, nobody asks.
Four holes come up over and over when a prompt-built app gets its first serious look. Nothing exotic in here. All four pass every test the assistant wrote for itself.
1. The route nobody put behind the auth check
The app has auth. Login works, sessions work, the dashboard checks for a user. And then there's /api/admin/export, added three prompts later, which checks nothing, because you asked for "an export endpoint" and not "an export endpoint behind the same middleware as everything else."
There's a rule worth memorizing here: in prompt-built apps, auth gets applied where it was mentioned, not where it's needed. Every route added after the auth conversation happened is a coin flip.
To check: list every route reachable from outside and write the name of its guard next to it. If the honest answer for some route is "well, the frontend doesn't link there," that's an open door. Attackers don't browse your frontend.
2. The webhook that believes anyone
Stripe, GitHub, your email provider, they all deliver events by POSTing to your app, and they all sign those requests precisely so you can check who's calling. Assistants write the handler and skip the signature check, nearly every time, because the unverified version is the one that works in the first test.
That leaves you with an endpoint where anyone who guesses the URL can mark orders as paid. One curl command. That's the whole exploit.
Your provider's docs have the verification snippet, and it's maybe five lines. You just have to ask your assistant for it, because it won't volunteer.
3. The API key in the browser
Framework conventions decide what ships to the client: anything prefixed NEXT_PUBLIC_, VITE_, or the like gets bundled into the JavaScript, readable in dev tools by anyone who cares to look. Assistants were trained on ten thousand quickstart tutorials that put keys exactly there, because it makes the demo work in one shot. So that's what they do.
An LLM key in the bundle means strangers running inference on your card. A database key in the bundle means something considerably worse.
The check is mechanical. Grep your built bundle for key, secret, and token. Whatever you find is public and should be treated as already leaked: rotate it, then move the call to the server.
4. The update endpoint that takes any field
"Let users edit their profile" turns into an endpoint that writes the request body into the user record. The whole body. Including role: "admin", if the caller feels like adding it. Nobody asked the app to accept that field. Nobody asked it not to, either.
Every write endpoint needs an explicit list of fields the caller may set. If the request body goes into the database unfiltered, admin is one POST away.
Where these actually live
Look at where the four sit. None of them are visible in the file itself. The unguarded route looks exactly like the guarded one, because the middleware lives somewhere else. The webhook handler is perfectly clean code whose problem is an absence. What makes each of these a hole is position: which path it sits on, which boundary it's past, what trusts it.
That's why we treat security as a diagram problem. When Arketo maps an app, trust boundaries get drawn as real objects on the canvas, and something like "traffic reaches this service on a path that skips auth" shows up as a critical finding on the exact edge where it happens. It's the same assistant that built the app, running the review it skipped the first time around. The live demo shows what a drawn boundary looks like. Better to meet yours there than in a pentest report.
