Level 04 · Airworthiness
Other people’s data is in it now, and you have never had that thought before.
This is the level where a mistake stops being yours. Everything before it costs you time; from here a mistake costs someone else their data. The good news is that most of what goes wrong at this level is four or five specific things, and they are all checkable in an afternoon.
You are here if
- There is a login, and you are not certain what it actually prevents.
- You are not sure whether one user could read another user’s rows.
- Someone asked where the data is stored and you had to guess.
- A key or a token is in a place you would rather not think about.
The client is not a security boundary
Hiding a button hides a button. The request behind it can still be sent by anyone who opens the network tab, and everything your interface knows how to ask for, a stranger can ask for too. Every rule that matters has to be enforced on the server, or in the database itself.
The test takes two minutes: open the network tab, find a request that fetches something of yours, change the identifier in it to another account’s, and send it again. If you get data back, you have found the most common serious bug in AI-built software. It is worth doing on every endpoint that takes an id.
Tenancy is a data question, not a UI one
As soon as there are two accounts, every query needs to answer “whose row is this?”, and the answer cannot come from the request. A user id sent in a request body is a claim, not a fact: it is whatever the caller typed. The identity has to come from the session or token the server verified.
The strongest version is to enforce it in the database with row-level rules, so a forgotten filter in one query cannot leak anything. Failing that, one shared, audited path that every read and write goes through. What does not work is remembering to add the filter each time, because one day nobody does.
What the API returns is what you published
Interfaces routinely show three fields from a response that contains thirty. The other twenty-seven are published too. Look at what your endpoints actually return, particularly anything built from a query that selects everything, and particularly on user and account records, where password hashes, internal flags and other people’s email addresses like to hide.
The same goes for error messages. A stack trace in a production response tells an attacker your file layout, your framework version and often your query structure.
The boring hygiene, and where to stop
Run your package manager’s audit and update what it flags. Confirm no service key or admin credential is reachable from the browser. Confirm every key that has ever been committed has been rotated. Confirm you can delete a user and their data when asked, because in the EU that is not optional.
Then stop, and be honest about the line: none of that is a penetration test, a certification, or legal advice. If you handle health data, payments or children’s data, the right move at this level is a specialist and a lawyer, not another checklist. Knowing where the checklist ends is part of the level.
Run it yourself
The checklist we would run.
There is nothing held back in it. If you work through this list and nothing on it is open, you have left this level, and you did not need us to do it.
- 01
Change an id in a request and try to read another account’s data
Do it on every endpoint that takes one. This is the single highest-value hour on this page.
- 02
Identity comes from the verified session, never from the request body
Anything the caller sends is a claim. Anything the server verified is a fact.
- 03
Look at what your endpoints actually return
Compare it with what the interface shows. Delete the difference.
- 04
No service key, admin credential or database URL reaches the browser
Search the built bundle for the first six characters of each key.
- 05
Every key that has ever been in a commit is rotated
History is public even when the current file is clean.
- 06
Dependency audit run, and the flagged ones updated
Then set a reminder to do it monthly, because it is only useful as a habit.
- 07
You can find and delete one person’s data on request
Practise it once. The request arrives eventually, and it has a deadline.
- 08
Errors in production do not print stack traces
Log them where you can read them, return something that says nothing.
What done looks like
- You have tried to break your own tenancy and failed.
- You can say where the data lives and who can reach it.
- Nothing sensitive is reachable from the browser, and nothing leaked is still valid.
Where it usually goes wrong
Hiding the control instead of blocking the route
The most common one, and the easiest to demonstrate to yourself in the network tab.
Trusting an id from the request body
It is the same bug as above, wearing a different hat. It is worth grepping your own code for.
Treating a login as security
Authentication says who someone is. Authorisation says what they may touch. Most incidents are the second one missing.
If you want company
Auth and tenancy that hold for the second user, permissions enforced where they cannot be bypassed, the dependency and secret audit, GDPR basics for an EU product, and the security review before someone else runs it for you.
A review at this level is a few days and ends in an ordered list. Plenty of people take the list and do it themselves, which is a good outcome.
It starts with a conversation and innovate@isyncso.com, subject Hangar. Tell us the level you landed on and what is in front of you. If the answer is on this page, we will say so.