# APIs Security Report & Actions

> Scan an API Maker account for data leaks (unscoped collections, wide groups, weak auth providers, public APIs, leaks in the code itself in all eight languages), fix them with one click after seeing the change, or skip them with a reason, and keep the report in git for people and AI assistants.

Source: https://docs.apimaker.dev/v4/docs/apis-security/api-security-report.html

**Security › APIs Security Report & Actions** scans the account and tells you where a person could read or change data which is not theirs, then lets you fix it from the same page.

It reads your settings (groups, API users, auth providers, collection settings) and your code : the hooks, the custom APIs, the schedulers, the events and every other piece of code of the account, in each of the eight languages API Maker runs (TypeScript / JavaScript, Python, PHP, C#, Go, Rust, Java and Kotlin).

> Diagram : Scan, finding, one click, scan again : the loop of the security report
>
> The security report in four steps : it scans the settings and the code of the account, shows each finding with the request which proves it, fixes it in one click after showing the change, and scans again to update the score out of 100 and the grade.

## Quick start

1. **Open the report** **Security › APIs Security Report & Actions**, then **Scan**. The account gets a score out of 100 and a grade, and the overview shows where the risks are.
2. **Read the findings** Click **Review**, a severity, a category or a finding : the list opens, the worst first. Each finding says what a person could reach, and shows the request which proves it.
3. **Fix or skip** Most findings have an action : see the change, then apply it. A finding you accept is skipped, with a reason kept in git.
4. **Keep it fresh** The account is scanned again after every action, and on its own while a local client is connected. The report is in the repository for your team and your AI assistant.

## Two gates, one report

Every request carries two identities, and the report checks both :

| Gate | Header | Question | What the report checks |
|---|---|---|---|
| API gate | `x-am-authorization` | May this application call this API ? | Groups with broad flags (`allInstances`, `allCollections`, `allSystemApis` ...), sensitive system APIs, bulk update / delete grants, unused groups |
| Row gate | `x-am-user-authorization`, `x-aws-authorization`, `x-google-authorization`, `x-azure-authorization`, `x-custom-authorization` | Of the rows this API reaches, which ones belong to *this person* ? | For every collection the groups reach : whether an **active pre-hook** reads the person (`g.req.auth.authAMDB` ...) and limits **every family of APIs** (`query.find` for get-all and the *-by-id APIs, `body.find` for query, count, update-many, remove-by-query ...) to their rows, merges with `$and`, stamps the owner on writes and refuses aggregate / distinct |

The row gate is the point of the feature. The generated APIs are powerful : with `find`, `deep`, `find-join`, `query`, `update-many` and `remove-by-query` a caller who is allowed on a collection reaches every row of it unless a pre-hook narrows the request. The report reads the code of your pre-hooks (instance, database, collection and API level) and decides, per collection and per API, whether that narrowing happens.

It also reviews the **auth providers** (unhashed passwords, tokens of Google or Azure taken whatever application they were made for, no groups column, long lived tokens) and the **public APIs** (instance APIs, custom APIs and system APIs with `IS_PUBLIC`).

### A simple example

Diya and Kabir are customers of a shop. Its app calls `GET /api/schema/shop/mysql/sales/orders` with the token of the app (`x-am-authorization`) and the token of the person who signed in (`x-am-user-authorization`).

- **Without a row scoping hook**, Diya gets every order of the table : hers, Kabir's, everybody's. The groups say the app may call the API ; nothing says which rows are hers. The report finds this : *"orders" is not scoped to the rows of the caller* (critical).
- **With the row scoping hook**, API Maker adds her id to every filter before the query runs : `{ $and: [ <the filter she sent>, { customer_id: 2 } ] }`. Diya gets her two orders, and nothing she sends can widen that.

## What it checks

Each check, with what it looks for and how to fix it, is in the [reference](https://docs.apimaker.dev/v4/docs/apis-security/api-security-report-reference.html) : [how a hook is read](https://docs.apimaker.dev/v4/docs/apis-security/api-security-report-reference.html#how-a-hook-is-read), [what the report finds](https://docs.apimaker.dev/v4/docs/apis-security/api-security-report-reference.html#what-the-report-finds), [every language](https://docs.apimaker.dev/v4/docs/apis-security/api-security-report-reference.html#every-language) and [the code scan](https://docs.apimaker.dev/v4/docs/apis-security/api-security-report-reference.html#the-code-scan).

## The page

The page has two views, **Overview** and **Findings**, side by side in its header.

- **Overview** is where the page opens, in one narrow column in the middle of the page. It shows the score and the grade with the open findings by severity, one line per question of the scan (row gate, public access, code, API gate, auth providers, hygiene) with its open findings, the five findings to fix first, then what was scanned and the automatic scans on one line each.
- **Findings** lists the findings on the left, grouped by category, the worst category first, with the selected finding on the right. The summary above the list is folded to one line : the score, the grade and the open findings by severity, which filter the list. Click it to see what was scanned and the automatic scans.

A severity, a question or a finding of the overview opens the findings on it. A link to a finding opens the findings view on that finding.

## The score

Every open finding takes points off 100 (critical 20, high 10, medium 4, low 1). Skipped and fixed findings take nothing. The grade (A to F) and the trend over the last scans are shown on the overview and printed in the report.

## Actions

Each finding offers what fixes it : an action when the fix can be automated, otherwise a link to the page where the change is made. Nothing is changed behind your back : an action runs when you click it, goes through the same routes as the admin panel (validation, TypeScript compile, git sync), and the account is scanned again right after so the report shows the result.

| Action | What it does |
|---|---|
| Add a row scoping pre-hook | Installs a collection (or database) level pre-hook which merges `{ ownerColumn: personId }` into `query.find` / `body.find` with `$and`, stamps the owner on every write and refuses aggregate / distinct. The dialog has two tabs. On **Settings** you pick the owner column and the field of the token, name the hook, choose its level and can limit it to some groups of API users (the groups which reach the collection are listed first, with their API users). On **Code** you pick the language (see [Every language](https://docs.apimaker.dev/v4/docs/apis-security/api-security-report-reference.html#every-language)) and can edit the code before it is saved : what the report reads in it is shown as you type, and on the tab itself. The help of each field is behind its help icon. |
| Rewrite the hook as a row scoping hook | Replaces the code of a hook of the collection which scopes only part of the APIs, lets the owner be overridden or bypasses the scoping, by the row scoping hook, in the language of the hook. The hook keeps its name, its groups and its place. The owner column, the field of the token and the three behaviours sit on one band above the code. You see its code now and after, side by side, and can change the new code before it is saved. |
| Let the internal calls through | Adds the guard of the internal calls (`if (!g.req.isApiRequestFromUser) return;` in TypeScript, the same in the language of the hook) at the top of its `main` : custom APIs, schedulers and events which call `g.sys.db` are not scoped to a person they do not have. Nothing else of the code changes. |
| Run the hook for these groups too / for every group | Adds the groups which reach the collection without being scoped to the `groupNames` of the hook, or clears them so the hook runs for every caller. |
| Require a token | Turns `apiAccessType` from `IS_PUBLIC` to `TOKEN_ACCESS` in the settings of a collection, in the Basic Info of a custom API, or in the settings of a system API. Only that word of the code changes. |
| Apply the fix (code scan) | Makes the change of code a finding of the code scan proposes (the checks of TLS turned back on, the password column left out of the rows read ...), where the code is kept : in the version in use of a custom API, a scheduler or a listener with versions, in the hook of a version of a custom API. |
| Add "column" to the token of a provider | Puts a column of the users table into the `select` of a DB token generator, so the token carries it and the hook can compare it. Persons log in again to get the new token. |
| Require a person token on this collection | Writes collection settings naming the auth providers, so every API of the collection needs a person token next to the API user token. Settings which keep the collection closed (`NO_ACCESS`) keep it closed. |
| Activate the hook | Switches an inactive row scoping hook back on. |
| Freeze to an explicit allow-list / turn the flag off | Narrows a broad group flag. Freeze writes what the group reaches today as explicit grants first, so nothing added later is reachable through it. The dialog shows the flag and the two ways side by side : a flag which can not be written as grants (fields, system APIs, custom APIs, WebSocket events) can only be turned off. |
| Revoke grants | Takes sensitive system APIs, bulk APIs, or the APIs which write the users table, away from a group. The dialog lists them all checked : uncheck the ones the group keeps. |
| Skip | Marks a finding as acceptable, with a reason (type it, or pick a quick reason). It leaves the score, and the reason is kept in git. |

A finding which suggests code shows it in a read only editor, in its language, and links such as "Open the collection", "Open the group" or "Open the code" open the page of the target in a new tab, so the report stays where it is.

### See the change first

An action which changes code shows the change before anything is saved : the new hook, or the code now and after the change side by side, with what the report reads in a hook after it (whether it scopes rows, which families of APIs it covers, whether internal calls go through). Code which would not parse is not saved.

The code is then saved through the route of its own page, as if you saved it there : it is compiled and checked the same way (one language per API included), it goes to git and to the local client, and the account is scanned again. A fix is made only on the code the scan read : when the code changed since, the action says so and asks for a new scan.

## Automatic scans

While a **local client** is connected to the account, API Maker scans it on its own and keeps the report fresh, on the disk of the developer and in git, so an AI assistant working in the folder of the project always reads the current report.

- **The pace follows the account.** The next scan comes 100 times the duration of the last one later, never closer than 1 minute and never further than 30 minutes : a scan which takes 300 ms runs every minute, one which takes 20 s runs every 30 minutes.
- **Nothing runs when nothing changed.** Between two scans, only a fingerprint of the inputs is read (one count and one date per collection of API Maker : groups, API users, auth providers, hooks, settings of tables and of system APIs, schemas, instances, custom APIs, every other piece of code the code scan reads, the secrets and the admin user). When it is the one of the last scan, no scan runs. With the live catalog on, a scan still runs every 30 minutes, for the tables added to a live database.
- **Nothing is saved when the report did not change.** A scan which finds the same findings saves nothing, so the local client and git see nothing. A scan which finds a different report saves it, sends the folder to the local client and, when the account has a git repository, commits the folder `src/api_security_report/` alone (what you have not committed yet stays as it is), at most once every 5 minutes.
- **One at a time.** A scan runs in the process which holds the connection, one at a time per account.

The panel **Automatic scans** (on the overview, and in the summary above the findings) shows whether a local client is connected, what the last cycle did, when the next one is due at the earliest, and the last commit. Two switches, saved with the report, turn the automatic scans and the automatic commits off ; the play button runs one cycle right away.

## In the repository

The report is committed with the rest of the project as the folder `src/api_security_report/` :

| File | Content |
|---|---|
| `README.md` | What the folder is, for people and AI assistants : read only, work on the findings, rescan |
| `report.md` | The full report : summary, scope, every finding with its evidence, the request which exploits it, what to do, and how to fix it : every fix of the page written as the change of the repository it makes |
| `report.yaml` | The same, machine readable |
| `actions.yaml` | The skipped findings with their reasons, and the log of the actions taken from the page |

API Maker only ever **writes** these files. The one thing it reads back is the `skipped` section of `actions.yaml`, on a git pull, so the decisions of the team follow the project. An AI assistant working on the repository can read `report.md`, fix the hooks, groups, settings and providers in their own folders, commit, and the automatic scan (or you, from the admin panel) rescans.

### How to fix it, in the files

Under **How to fix it**, every finding lists the fixes its page offers, and writes each one as the change of the repository it makes : the files to create (the YAML and the code of a new hook, new settings), the lines of a file which change, the keys of a YAML file to set, the values to add to the lists of a group or to take out of them. Made in these files (by you or by an assistant), committed, pushed and pulled from the Git page (or saved while the local client runs), the change fixes the finding exactly as the button does : the same code, in the language of the hooks of the table, the same names and folders, the same grants. `report.yaml` holds the same changes as data (`actions[].repository`).

```md
**Fix 1 : Revoke these system APIs** (recommended)

In `src/groups/app/app.yaml` :

- remove from `queryParams.systemApiNames` : `EXECUTE_PLAIN_QUERY`
```

A fix which needs a choice first (the column which says who owns a row, when the report can not tell) says so, and the change of the default secret (`common.authProviders`) is made on the Secrets page : the secrets are not in the repository. The [`AGENTS.md`](https://docs.apimaker.dev/v4/docs/ai/llms.html#agents-md) API Maker writes at the root of the repository tells assistants how : read the finding, change the file it names, let the next scan show it fixed, and leave skipping to your team.

## Printing

The download menu of the page prints the report (A4, with or without the skipped findings) through the print dialog of the browser, where "Save as PDF" makes the file, and downloads `report.md`, `report.yaml` or `report.json`.

## Related reading

- [Handle role based permissions](https://docs.apimaker.dev/v4/docs/authorization/handle-role-based-permissions.html)
- [API group permission](https://docs.apimaker.dev/v4/docs/apis-security/api-group-permission.html)
- [Authorization of AM database user](https://docs.apimaker.dev/v4/docs/authorization/AMDB.html)
- [Pre-hook](https://docs.apimaker.dev/v4/docs/apis-all/hooks/preHook-api.html)
