Common security mistakes in AI-generated apps
AI-generated code is usually secure in its syntax and careless in its boundaries. The recurring problems are not exotic: exposed secrets, permission checks only in the UI, tables with no access rules, trusting whatever the browser sends, and admin credentials used to make a stubborn query work.
1. Secrets in code that runs in the browser
The most common and the most expensive. It happens because calling the provider directly from a component is the shortest path to working code, and working code is what the model optimises for.
Check: search your deployed bundle for your secret's prefix. Fix: move the call to a server function and rotate the key.
2. Permission checks that only exist in the interface
The admin button is hidden for normal users, and the endpoint behind it accepts anyone. Hiding is not preventing; anybody can call the endpoint directly.
Check: call your own privileged endpoint from a signed-out or second account. Fix: verify identity and role inside the handler.
3. Tables with no access rules, or rules that allow everyone
A policy like `using (true)` makes a query work immediately and makes every row public. Equally common is a table with rules enabled and no policies at all, which silently returns nothing and then gets 'fixed' with admin credentials.
Check: for each table, say out loud who can read it and who can write it. Fix: owner-based policies, tested with a second account.
4. Trusting values that came from the browser
A request that includes `userId` or `price` or `isAdmin` in its body is a request that can be edited by anyone. The server should take the user id from the verified session and the price from the database.
// Wrong: the caller decides who they are
const userId = data.userId;
// Right: the session decides
const userId = context.userId;5. Admin credentials used as a workaround
Service-role keys bypass all access rules. Reaching for one because a query returned nothing converts a permissions bug into a data-exposure bug — and it will not be obvious afterwards, because everything works.
6. Public endpoints with no verification
Webhooks and cron endpoints are reachable by anyone who learns the URL. Without signature verification or a shared secret, a stranger can trigger whatever they do — including marking an order as paid.
7. Error messages that leak, and errors that hide
- Returning a raw stack trace to the browser tells an attacker about your stack and file layout.
- Swallowing the provider's message entirely leaves you debugging blind.
- The middle ground: log the detail on the server, return something accurate but unrevealing to the user.
The review checklist
- 1Search the deployed bundle for secret prefixes.
- 2List every table and name its read and write rules.
- 3Sign up a second account and try to reach the first account's data.
- 4Call each privileged endpoint while signed out.
- 5Confirm every public endpoint verifies its caller.
- 6Confirm user id, price and role never come from the request body.
- 7Check that a failed request logs enough detail for you and not for a stranger.
Frequently asked questions
- Is AI-generated code less secure than hand-written code?
- It makes different mistakes rather than more of them. It is strong on syntax and weak on boundaries, because boundaries depend on context it may never have seen.
- Can I ask the AI to review its own security?
- It is a useful first pass and a poor last one. It cannot test your live permissions with a second account — you can.
- What should I check before launch?
- The seven-step list above, plus a genuine signed-out walkthrough of your main flow.
Practice this in MessyDev
Reading it once helps. Doing it once sticks. These are the hands-on parts of MessyDev that cover the same ground.
Keep going
- Row Level Security explainedWhat Row Level Security is, why it is on by default in hosted databases, how a policy is evaluated, and the mistakes that make tables silently empty or dangerously open.
- How to keep API keys out of your frontendA practical method for moving secret-using code to the server, checking what actually shipped to the browser, and proving a key is no longer exposed.
- AI app launch checklistWhat to verify before real people use an AI-built app: access rules, secrets, signed-out behaviour, payments, email, errors and the boring things that decide whether a launch is quiet or embarrassing.