PocketBase is everywhere in the vibe-coded app ecosystem right now. It's the backend of choice for Lovable and Bolt.new projects that need a database — fast to set up, no SQL, and the admin panel is genuinely pleasant to use.
It also ships with every single collection completely open by default.
I recently audited a live 3D printing service built with React, Vite, and PocketBase on Hostinger Horizons. Within 30 seconds of opening the app, I had read every customer order the site had ever received — names, email addresses, phone numbers, physical delivery addresses, and links to every uploaded 3D file.
No login. No tools. Just a URL in a browser tab.
Here's what happened and why it's probably happening to your app too.
How PocketBase API rules work
Every collection in PocketBase has four API rule fields: List, View, Create, Update, and Delete. These rules control who can perform each operation via the API.
The default value for all of these rules is an empty string — which PocketBase interprets as no restriction. Any request, from anywhere, is allowed.
Supabase has the same problem with RLS (it's disabled by default), but there's more community awareness around it now. PocketBase's default-open API rules are less talked about, and the vibe coding tools that scaffold PocketBase backends don't set them during project generation.
The result: your app works perfectly, your users can sign in and place orders, and you have no idea that every record in your database is readable at a public URL.
What I found
The app had a print_requests collection — customer orders containing full PII. I hit the API endpoint directly with no auth token:
GET /api/collections/print_requests/records
HTTP 200 OK
Every record came back. Customer names, emails, phone numbers, physical addresses, material choices, and direct download links to their uploaded design files. The collection ID was visible in the minified JavaScript bundle, which meant the file URL pattern was predictable — anyone could enumerate and download the entire file library.
On top of that:
- CORS was set to wildcard (
*) — any website on the internet could silently pull this data from a victim's browser - The
rolefield was set client-side at registration — anyone could register themselves as an admin by modifying the request before it went out - The admin panel was publicly reachable — no IP restriction on the PocketBase superuser login page
- File upload restrictions existed only in the browser — the server accepted any file type and any size
Nine findings total. Two critical, two high, all addressable without a developer.
How to check if you're affected
Open your PocketBase admin panel and go to any collection. Click the API Rules tab.
If every field is blank — you're open.
You can also test it directly. Take your app's domain and try:
curl https://your-app.com/api/collections/your-collection/records
If you get records back without sending any auth token, so can anyone else.
How to fix it
Lock down API rules on every collection
For any collection that stores user data, set the rules in PocketBase admin → Collections → [collection] → API Rules:
| Rule | Minimum setting |
|---|---|
| List | @request.auth.id != "" |
| View | @request.auth.id != "" |
| Create | @request.auth.id != "" |
| Update | @request.auth.id = record.user_id |
| Delete | @request.auth.id = record.user_id |
This ensures only authenticated users can access data, and only the record owner can modify their own records.
For public collections (landing page contact forms, public product listings), only the specific operations that need to be public should be open — and nothing else.
Enable file protection
If you have a file field on a collection, go to that field's settings and enable the Protected toggle. This requires a valid session token to download any file. Without this, files are accessible by direct URL regardless of collection-level rules.
Lock down CORS
In PocketBase → Settings → Application → CORS allowed origins: replace * with your actual domain. There is no reason to accept cross-origin requests from arbitrary websites.
Block client-side role assignment
If your registration flow sets any field server-side that it trusts from the client (a role, plan, or admin field), add a Create rule to the users collection that rejects the value:
@request.data.role = "" || @request.data.role = "user"
This blocks any registration that tries to escalate privileges at the point of account creation.
The pattern
This is the same root issue every time: AI tools generate code that works. The app functions. Users sign up, orders come in, everything looks fine.
The security layer — API rules, file protection, CORS — requires deliberate configuration that's separate from making the app work. It's not in the happy path. AI tools skip it because configuring it correctly requires understanding your specific data model, not just generating a scaffold.
This isn't a PocketBase problem. PocketBase's docs cover API rules clearly. It's a deployment pattern problem — apps go live before anyone checks whether the defaults are safe.
If you're using PocketBase and haven't reviewed your API rules, Archer Labs does free threat briefs for AI-built apps. We look at your specific collections, your CORS config, your file access settings, and tell you exactly what's exposed — no scanner, no generic report.