TLDR;
- The Security Risks with Vibe Coding study by Astra Security found 17 endpoints across the four AI-built apps that were reachable without any authentication at all.
- Broken access control was the most severe category whenever it appeared, including a BOLA that returned 811 user profiles to any authenticated account.
- Default-deny on every route, authorization enforced at the data-access layer, and strict refusal to trust client-supplied identifiers close most of this class.
- Astra’s autonomous pentesting flags both missing-authentication endpoints and broken object-level authorization at pentest-grade confidence.

We handed four vibe-coding tools (Emergent, Replit, Lovable, Base44) the same prompt for a FastAPI user-management microservice. The spec was explicit: JWT auth, parameterized queries, rate limiting, four-tier role model with per-endpoint scope. Each tool shipped a build, and our flagship autonomous pentest surfaced 137 confirmed vulnerabilities across all four.
17 of those were endpoints that required no login, including some that changed passwords, invited admins, or created entities with an attached role.
Another 11, concentrated in three of the four apps, were cases where logging in gave an attacker access to data that was supposed to belong to someone else. Together, that is 28 broken access control findings out of 137, which is why we are writing it up on its own.
What is broken access control, and what counts as a failure?
Broken access control sits at the top of the OWASP Top 10 (A01:2021) because when it fails, every other control fails with it. A perfect WAF, strong password hashing, airtight TLS, and rate limiting are useless if the endpoint returning account data does not check who is asking for it.
Broken access control comes in two shapes. The first is missing authentication, where the endpoint does not check for a valid session at all. CWE-306 covers it, and the typical failure mode is that the frontend hides the button and nobody checks what happens when someone sends the same request manually.
The second is broken authorization, where the session is valid, but the server does not check whether this particular user is allowed to access this resource. CWE-639 covers the IDOR vulnerability pattern, where swapping ?id=4291 for ?id=4292 returns someone else’s record.
A route with no auth check is bad, obviously. A route where the backend trusts the user_id in the request body is worse, because it looks correct in a code review and only breaks when someone sends a different one.
What we found across the four apps

All four tools received an identical prompt with explicit role requirements (SuperAdmin, Admin, Manager, Viewer with per-endpoint scope), and all four shipped different variations on the same problem.
One build’s /api/…/entities/Profile returned data to any unauthenticated caller. Another allowed unauthenticated password changes on arbitrary accounts, which is as close to a free takeover primitive as a bug class gets. A third let an outside attacker forge an admin invitation and attach any role to it, including SuperAdmin.
One build also allowed audit-log tampering and deletion, which is the quiet kind of failure, because it removes the evidence that any of the other failures happened.
On the authenticated side, one build exposed 811 user profiles to any logged-in user through a users endpoint with no object-level check, which is the textbook BOLA pattern. Another had a pagination bypass that let an authenticated attacker request ?page_size=99999 and receive the full database in one response, including password hashes.
A third accepted a role field in the body during profile updates, so a Viewer could promote themselves to SuperAdmin with one PATCH request.
The root cause in every case was the same. The generator wrote correct authentication code for the login route and the primary data-fetch routes, and did not reapply it on the long tail of endpoints the prompt did not individually enumerate.
The default was open rather than closed, so every endpoint added later inherited the open posture. Nobody wrote broken code. Nobody wrote enough code.
How to prevent broken access control
Three practices close most of this class at the source, and together they define how to secure API endpoints against both halves of the finding.
Default-deny on every route: Enforce authentication globally through middleware and explicitly list the public endpoints (/login, /register, /health). A newly added route should fail a basic no-auth smoke test by default. This single architectural choice would have closed all 17 missing-auth findings in the study.
Enforce authorization at the data-access layer: Row-level security on the database, or ownership checks inside the repository layer, means a missed check in one handler does not expose the entire resource. The 811-profile BOLA and the pagination bypass both lived in handler-level logic, which is why one missed line gave up the user table.
Never trust client-supplied identifiers: Any request for a resource ID outside the caller’s scope should return 403 or 404, not partial or filtered data. Any request that includes a role field during a profile update should be rejected unless the caller is explicitly authorized to set that role.
If you are building with an AI tool, the fix happens in the prompt. Asking for “role-based access control” gets you nothing, because that is a feature name and the tool will treat it as one. Tell it exactly which role can read, write, and delete which entity, and tell it to enforce those rules at the repository layer rather than at the route. Then check it yourself, which takes about a minute per endpoint.
curl -i -X GET "https://your-api.example.com/api/users/42" \
-H "Authorization: Bearer <viewer-token>"
If a Viewer-level token returns another user’s record instead of a 403, you have the finding. Run it against every endpoint that returns per-user data, not only the one you remember protecting. This is what API endpoint security actually looks like in practice.
Final thoughts
The cost of broken access control is paid at runtime, but the fix is paid at prompt time. Every finding in this writeup would have cost one sentence to prevent (which role can read which entity, which fields a user is allowed to set, which routes stay open and which do not).
Grab the free report for the hardened prompt and the 10-minute checklist you can run against anything you have already shipped. When you want someone to actually look, Astra’s autonomous pentest runs the same three-agent pipeline we used in the study against your live application.



