Vibe Coding 馃5 min read
Vibe Coding Security: Five Holes To Check Today
Models do not write insecure code on purpose. Security is just the thing nobody put in the prompt. Five holes account for most of it, all findable in an afternoon without being a security engineer.
By Juan Molina

On this page
The security problem with vibe coding is not that models write insecure code on purpose. It is that security is almost always the thing nobody put in the prompt, and a model builds what it was asked for.
Ask for a checkout and you get a checkout. It will work. Whether it can be robbed is a different question, and it is not one that gets answered by looking at the screen.
Five holes account for most of it. All five are findable in an afternoon, and none of them require you to be a security engineer.
1. The secret key in your front end bundle
Every payment provider, and most commerce APIs, issue at least two kinds of key. A publishable one that is designed to sit in a browser and can do almost nothing, and a secret one that can read every order and every customer you have.
A model given one key uses that key. It has no way to know which one you pasted, and it will not stop to ask.
How to check: open your live site, view source, and search the JavaScript files for sk_, secret, api_key and token. Anything you find there is public. Environment variables do not save you either: in most front end frameworks, any variable prefixed for client use is compiled straight into the bundle.
If you find one: rotate it immediately, before you fix the code. It has been readable by anyone who loaded your site.
2. The price that came from the customer
The most common and most expensive one. The cart lives in the browser, it knows the total, and it sends the total to the server when the customer pays.
Which means the customer sends you the price. Developer tools are built into every browser, changing a value before it is submitted takes about ten seconds, and no amount of front end validation prevents it, because the validation is also running on their machine.
How to check: look at the network request your checkout sends. If it contains an amount, a total, or a price, you have this problem.
The fix: send product identifiers and quantities. The server looks up its own prices, applies its own discount rules, and calculates the total itself. The browser asks, the server decides.
3. Endpoints that only check who you are in the interface
Generated apps hide the admin link when you are not logged in, which looks like access control and is not. The route is still there and still answers.
The same applies to anything belonging to one customer. If /api/orders/1043 returns an order because the identifier is valid, without checking whether the person asking owns it, then changing the number walks through everybody's orders, with their addresses, in a loop anyone can write.
How to check: log out, paste an admin URL directly, and see what happens. Then log in as one account and request another account's order by its identifier.
The fix: every endpoint that returns data checks, on the server, who is asking and whether that person owns this specific record. Not who the interface thinks they are. Who the request proves they are.
4. Webhooks nobody verified
Your payment provider tells your server that a payment succeeded by calling a URL. That URL is on the public internet, and so anyone can call it.
If your handler marks an order paid because a request arrived saying so, then anyone who finds that URL can mark any order paid without paying. Providers sign every webhook precisely to prevent this, and verifying the signature is a step that is easy to leave out when the happy path already works.
How to check: find your webhook handler and look for a signature verification before anything else happens. If the first thing it does is read the body and update an order, that is the hole.
While you are there: the same handler probably has the duplicate problem too. Webhooks retry, and a handler that grants store credit twice for one payment is a slower version of the same bug.
5. Dependencies nobody chose
Models suggest packages. Some are the obvious right answer, some were popular three years ago, and occasionally one does not exist at all, which is its own hazard because somebody may have registered the name.
How to check: run npm audit, and look up anything you do not recognise. A package with very few downloads that appeared recently deserves a moment of attention before it ships.
The thing these five have in common
Every one is on the server side of a store: keys, prices, ownership checks, payment confirmations. None of them are in the part you can see.
That is the actual asymmetry in vibe coding. The storefront is the half you can evaluate by looking at it, and models are very good at it. The transactional half is the half where being wrong is expensive, and it is invisible in a demo.
Which is why our answer is not a checklist. It is to not write that half. Keys are separated into publishable and secret by design, prices come from the server, ownership is checked on every read, and webhooks are signed and deduplicated because the backend is the thing we maintain.
Where that is the wrong answer: if you are not taking payments, most of this does not apply to you and you should not restructure anything. If you are already on a hosted platform, its checkout handles all five and you should not be building your own. And a backend does not protect a storefront you wrote badly, so the other mistakes are still yours.
Run the five checks anyway. They take an afternoon, and the first one is worth doing before you finish reading this.














