How to Audit Your Backend's Security With Only the App ID: Nine Checks and a Script

For people who do not write code, this is the single biggest problem: you cannot search for the name of a thing nobody has told you about. So here is the list of names, and a script that asks each one about your app.

Nine questions asked of a running backend by a client holding only the app id that ships in every front-end bundle: seven came back wrong on a default setup, including a stranger being able to add, edit and delete rows in every class and read two provider keys, and all seven were closed afterwards

For people who do not write code, this is the biggest problem there is — bigger than deployment, bigger than bugs. Nearly half of what they struggle with is this one thing, and it has an awkward shape: you cannot search for the name of a problem nobody has told you about.

An assistant will not interrupt itself to mention that your app has no concept of permissions. It was not asked. And you did not ask, because asking requires already knowing the word.

So the useful thing is not advice. It is a list of names, and a way to check each one against the app you actually have.

Watch it instead

Not knowing what you don’t know is number 6 in our countdown of what actually goes wrong for people building with AI.

Video: We Analyzed 130,000 Vibe Coder Posts. These Are the Problems That Actually Hurt.
Watch it instead We Analyzed 130,000 Vibe Coder Posts. These Are the Problems That Actually Hurt.
From the Back4app channel. This guide is the long version of its sixth position; the countdown itself is in the companion post. Open on YouTube →

What did the questions come back with?

Seven answers nobody wants, on a backend nobody had touched:

Nine questions asked of a default backend: seven came back wrong, including a stranger being able to read twelve rows, add rows to every class, delete rows, edit a row it did not own, create new classes and read two provider keys, with all eighteen class operations open to everyone

The auditor holds nothing but the app id. That is worth sitting with for a second, because the app id is not a secret — it is in every front-end bundle, visible to anyone who opens the network tab.

Nobody writes a post about the vulnerability they do not know they shipped. That is exactly why it stays shipped.

Nothing here was a bug. Every one of these is a default, chosen so the first tutorial works without anyone configuring anything.

What could a stranger actually do?

All four of the things you would least like. The audit does not read settings and infer; it makes the request and reports what came back:

 1. [CRITICAL] Can a stranger add rows to your classes?
      yes — created a row in Patient, Appointment, Settings
 2. [CRITICAL] Can a stranger delete your rows?
      yes — deleted from Patient, Appointment, Settings
 3. [CRITICAL] Can a stranger edit someone else's row?
      yes — the backend accepted a write to Patient.name
 4. [CRITICAL] Are any of your third-party keys readable by a stranger?
      yes — Settings.value (STRIPE_SECRET_KEY), Settings.value (SENDGRID_API_KEY)

The fourth one deserves its own sentence. Those keys came back in the same request that fetched the patient list, because somebody once asked an assistant to “store the API key” and a row is where rows go.

Where were the permissions, and what did they say?

In a screen most people never open, saying “everyone” eighteen times:

 5. [HIGH] Can a stranger read your data?
      Patient: 5 rows, Appointment: 5 rows, Settings: 2 rows
 6. [HIGH] What do your class permissions actually say?
      18 of 18 operations are open to everyone

Three classes, six operations each — find, get, count, create, update, delete — and every one of them public. This is the single most useful thing to look at, because it is one place that explains all four criticals above.

Two questions did come back clean, and they are worth naming so the list is honest. The schema is not readable without the master key, and user rows are hidden from an anonymous query — the query is allowed, but it returns nothing.

Questions that came back wrong
7 of 9on the backend as it arrives
→
0 of 9after one pass of fixes
1credential needed to find all of it: the app id from your own bundle
Each check is performed as an anonymous client, not inferred from configuration. Identical across two clean runs.

What does fixing it cost?

Something real, and you should know what before you start. We closed the permissions, moved the keys out of the database and turned off client class creation, then asked the same nine questions again:

  0 thing(s) nobody asked about

Then we checked the app still worked, because zero findings is also what a completely broken app reports:

ana logs in:                        yes
ana reads patients:                 5 rows
a stranger reads patients:          refused
ana writes an appointment directly: no — Permission denied for action create

Read those four lines together. A signed-in person still sees everything the app displays. What stopped is the browser writing to the database directly — so every write in your app has to move into a server-side function.

That is the honest price. It is an afternoon of moving code, not a checkbox, and it is why the default is what it is.

What makes this findable at all?

Being able to open the thing. Every answer above came from an ordinary HTTP request against a documented API, which is the only reason a script could ask on your behalf.

That is the real distinction worth caring about when you pick a tool. Not “did it generate something” but “can I inspect what it generated” — the data model, the permissions, the server functions, each one separately, afterwards.

What should you do first?

Open your front-end bundle and find your app id — it is in there, and finding it yourself is the fastest way to internalise that it is not a secret.

Then make one request with it and nothing else: ask for every row of your most sensitive class. Whatever comes back is what a stranger gets, and that single result will tell you whether the rest of this list applies to you.

The lab is in the repo — point client.mjs at your own backend and the nine questions run against it. It only deletes rows it created itself.

Tagssecuritypermissionsauditbackendvibe-codingacl

Frequently asked questions

How do I check whether my app is secure if I am not a developer?

Stop asking whether it is secure and start asking what a stranger can do, because that question has an answer you can test. Take the app id out of your front-end bundle, make requests with it and nothing else, and see what comes back. We turned nine of those questions into a script; on a default backend, seven of them came back wrong.

Can anyone read my database if they have my app id?

On a default setup, yes. The app id is not a secret — it ships inside every front-end bundle and anyone can read it. We used nothing else and got 12 rows back across three classes, including patient names, diagnoses and phone numbers, plus two provider API keys someone had stored in a settings row.

Why can strangers delete data from my app?

Because delete is open by default at the class level, so the first tutorial works without anyone configuring anything. We confirmed it by creating a row as an anonymous client and deleting it again. The permission is per class rather than per row, so real rows sit in exactly the same position as the test one.

What are class-level permissions and where do I look at them?

They decide who may find, get, count, create, update, delete and add fields on a whole class, and they are the screen most people never open. On our default backend all 18 operations across three classes were open to everyone. Reading them is one API call, and the audit prints them for you.

Does locking down permissions break my app?

Partly, and you should know which part before you start. After closing ours, a signed-in person still read every row the app displays. What stopped working was the browser writing to the database directly, so each write has to move into a server-side function. That is real work rather than a toggle.

Where should API keys live if not in the database?

In server-side configuration, where no client query can reach them. A key in a row is readable by anyone who can read that class, and our audit pulled two of them out in the same request that fetched the patient list. Moving them is also the only fix that works retroactively, since a key that has been exposed has to be rotated.

Further reading

Reviewed & verified by Back4app Engineering, Editorial review at Back4app

Tested Oct 27, 2026 — Local: Docker 29.4.3 on macOS, arm64 · Parse Server 7.4.0 with MongoDB 7 · Node 22.21.1, no dependencies · Back4app, free plan.

Changelog

  • Nov 4, 2026 — The companion repository is not published yet, so the link to it and the button were removed; they come back when it is.
  • Oct 28, 2026 — The companion repository is published, so the button and the inline link to it are back.

More from Back4app Engineering

Backend · tutorial

Your Frontend Talks Straight to the Database. Here Is How to Lock It Down [Full Repo]

Backend · report

Why Vibe-Coded Apps Break: 13 Problems From 130,000 Posts, Ranked, With the Fix for Each

Backend · tutorial

How to Ban and Unban Users in Your App, and Make the Ban Stick [Full Repo]