> ## Documentation Index
> Fetch the complete documentation index at: https://docs.concatflow.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Security model

> What the agent can reach, what Concatflow can ask of it, and what stays on your machine.

## Your database stays closed

The agent only makes outbound connections. It opens no port, so nothing on the internet can connect to it or through it. Your database keeps its firewall rules unchanged.

## The password never leaves your machine

You set `DATABASE_URL` on your machine. The agent uses it to connect to the database and sends it nowhere. Concatflow never receives, stores or forwards it. The dashboard never asks for it.

## The account can only read

The agent checks the database account before it serves anything, on your machine, and refuses to start if the account can write. The check covers the whole database, not only the exposed schemas. See [What the agent checks](https://docs.concatflow.com/private-databases/guides/read-only-account.md#what-the-agent-checks).

Queries are bounded on top of that:

* each query is a single statement, wrapped in a `SELECT` with a row limit;
* each query has a time limit;
* on PostgreSQL, the session itself is read-only.

## Enrollment

1. The dashboard issues a token. It works once and expires after 7 days. Only a hash of it is stored.
2. On first start, the agent generates its own key pair. The private key stays in its data directory.
3. The agent sends the token and its **public** key to `api.concatflow.com`.
4. Concatflow returns credentials signed for that public key, and burns the token.

A copied token is useless once used. A copied public key is useless without the private key, which never left your machine.

## Isolation

Every dataset gets its own isolated account on the Concatflow message broker. The isolation is enforced by the broker itself, not by application code.

An agent's credentials allow exactly two things:

* receive the requests of **its** dataset;
* answer them.

An agent cannot see another customer's traffic, another dataset's traffic, or send anything except answers.

## What Concatflow can ask

Concatflow sends requests of six kinds:

| Request | What the agent does |
| - | - |
| `verify_read_only` | Runs the read-only check. |
| `list_schemas` | Lists the schemas the account can read. |
| `introspect_schema` | Reads table and column definitions, keys and row estimates for the selected schemas. |
| `sample_values` | Reads a few sample values from selected columns. |
| `table_versions` | Reads a change marker for selected tables. |
| `run_query` | Runs a read-only query on the selected schemas. |

The agent rejects anything else. Each request carries the dataset's selected schemas, and the agent opens its connection with exactly those.

## Revocation

Revoking an agent in the dashboard adds its key to a revocation list that the broker enforces. The broker drops the connection immediately, and refuses it from then on. Nothing needs to happen on your machine.

## The image

* Signed with cosign from GitHub Actions. See [Verify the signature](https://docs.concatflow.com/private-databases/reference/configuration.md#verify-the-signature).
* Contains only the agent and the libraries it needs.
* Runs as a non-root user.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.