Skip to content

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.

  1. 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.

  2. 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.

  3. 03

    Look at what your endpoints actually return

    Compare it with what the interface shows. Delete the difference.

  4. 04

    No service key, admin credential or database URL reaches the browser

    Search the built bundle for the first six characters of each key.

  5. 05

    Every key that has ever been in a commit is rotated

    History is public even when the current file is clean.

  6. 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.

  7. 07

    You can find and delete one person’s data on request

    Practise it once. The request arrives eventually, and it has a deadline.

  8. 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.