API Maker

The backend engine for the AI era

Security

APIs Security Report & Actions

Find where a person could read data that is not theirs, and fix it in one click.

API Maker reads your groups, API users, auth providers, settings and the code of your pre-hooks, and shows where a person could read or change rows that are not theirs. A leak comes with the request that proves it, and many findings with an action that fixes them in one click. The report lives in your Git repository, where your AI assistant can read it too.

See it live

Step through it, slow it down, or open the full canvas.

api-maker/features/api-security-reportLive
  • Scan
  • Critical
  • High
  • Medium
  • Fixed
Score
–/ 100
Open findings
0to fix
Fixed
0by actions or git
Skipped
0with a reason

It reads the whole account. Groups, API users, auth providers, settings and the code of every pre-hook, read and never run. Each open finding takes points off 100: 20 for a critical one, 10 high, 4 medium, 1 low.

How it works

  1. It reads the whole account.

    Groups, API users, auth providers, settings and the code of every pre-hook, read and never run. Each open finding takes points off 100: 20 for a critical one, 10 high, 4 medium, 1 low.

  2. Allowed is not the same as scoped.

    The group lets the shop app read orders and alice signs in with her own token, but no pre-hook limits the rows: she gets the orders of every customer. The finding comes with the request that proves it.

  3. One click installs the fix.

    A row scoping pre-hook: the owner column goes into every filter with $and, the owner is stamped on every write, aggregate is refused. You can edit the code first. The account is scanned again right after.

  4. Only her own rows now.

    The same request returns the two orders of alice. Asking for the orders of customer 23 matches nothing: her filter is joined to the owner with $and. Aggregate, which no filter can scope, gets 403.

  5. Every finding has its action.

    Revoke a sensitive system API, or skip a finding with a reason, like reference data everyone may read. A skipped finding leaves the score and its reason is kept in git.

  6. It keeps watching while you work.

    With a local client connected, a change in the account is scanned within minutes and the report is committed to git. Your AI assistant reads it there, fixes the finding, and the next scan confirms it.

What you get

Groups that reach too far

Broad flags like all collections or all system APIs, sensitive system APIs such as EXECUTE_PLAIN_QUERY and GET_SECRET, bulk update and delete grants, and groups nobody uses.

Tokens and public APIs

Passwords inside tokens or stored in clear, providers without a groups column, tokens that live longer than 30 days, and APIs that need no token at all.

Actions that fix it

Add a row scoping pre-hook, add a column to a token, require a person token, freeze a group to an explicit allow-list or revoke grants. You see the code before it is saved.

An example

A shop with customer logins

Customers sign in with their own token and the app calls the generated APIs of orders. The report sees that no pre-hook limits orders to the rows of the caller, shows the request any customer could send to read every order, and installs the pre-hook in one click. The next scan confirms it.

The request that proves a findingterminal
# every row of "orders", with the token of any person allowed on it :curl "$BASE/api/schema/$ADMIN/shop/main/orders?limit=1000" \  -H "x-am-authorization: $APP_TOKEN" \  -H "x-am-user-authorization: $PERSON_TOKEN"

A finding about rows shows how it is exploited. Here any customer gets every order, because no pre-hook of orders reads the person behind the request.

The pre-hook that one click installsRow scope - orders.ts
const OWNER_COLUMN = 'customer_id';const IDENTITY_FIELD = 'id';async function main(g: T.IAMGlobal) {    // Custom APIs, schedulers and events run under their own rules : only real callers are scoped.    if (!g.req.isApiRequestFromUser) return;    const person = g.req.auth?.authAMDB;    const me = person ? person[IDENTITY_FIELD] : undefined;    // ... 401 without a person token    const scope = { [OWNER_COLUMN]: me };    // MERGE, never replace : $and keeps what the caller asked for and adds the owner on top    const merge = (existing: any) => (existing && typeof existing === 'object' && Object.keys(existing).length        ? { $and: [existing, scope] }        : { ...scope });    const apiId = g.req.reqInfo?.apiInfo?.id;    if (QUERY_FIND_APIS.has(apiId)) {        g.req.query.find = merge(g.req.query.find);        stamp(g.req.body); // update-by-id and replace-by-id : the owner of a row can not be handed over        return;    }    if (BODY_FIND_APIS.has(apiId)) {        g.req.body = g.req.body || {};        g.req.body.find = merge(g.req.body.find);        if (g.req.body.updateData) stamp(g.req.body.updateData); // update-many        return;    }    // ... save and master-save : the owner is stamped on every row    // Fail closed : aggregate and distinct can not be scoped generically, so they are refused.    g.res.statusCode = T.EStatusCode.FORBIDDEN;    throw new Error(`API ${apiId} is not available for row scoped users.`);}module.exports = main;

Generated for the owner column and the field of the token you pick, shortened here. Edit it before saving if you want: the report reads the code again on every scan.

Watch it

On the real admin panel, with real data.

Good to know

  • Nothing in a database says who owns a row: the owner column is a scored guess, from a relation to the users table, a column named after it, or names like user_id and created_by. Pick another column in the fix dialog when needed.
  • Aggregate and distinct can not be scoped by a filter: the generated pre-hook refuses them for row scoped callers. Serve those needs from a custom API.
  • Automatic scans run while a local client is connected, and commit only when the account has a Git repository.

Questions

How is the score computed?

Every open finding takes points off 100: 20 for a critical one, 10 for high, 4 for medium and 1 for low. Skipped and fixed findings take nothing. 90 and more is grade A, then B from 75, C from 60, D from 40, and F below.

How often do the automatic scans run?

While a local client is connected, the next scan comes 100 times the duration of the last one later, between 1 and 30 minutes. When nothing changed in the account, nothing is scanned, saved or committed.

Can an AI assistant work with the report?

Yes. It reads report.md in src/api_security_report/, fixes the hooks, groups or providers in their own folders and commits. The next scan shows the result.