<!-- Security guarantees -->
<!-- canonical: https://plainwater.ai/en/wiki/veiligheid/garanties -->
# Security guarantees

The rule of Plainwater AI: **a guarantee only counts if there is a test on it.** Below is what the platform promises, in
plain language. Every promise on this page is tested automatically on every change to the platform.

## What an agent never gets

- **No model vendor key.** An agent talks to models through the [AI gateway](https://plainwater.ai/en/wiki/concepten/ai-poort), never directly.
- **No customer database password.** An agent only gets a one-time bootstrap code to register with the platform.
  Connecting to a source is done by the platform itself.
- **No free internet access.** Agents run in isolated containers. Outbound traffic goes through an allowlist.

## Every model request, one decision

Every request to a model gets exactly one policy decision. A refused request does not reach the vendor. Rules are
enforcement in the gateway, not an instruction in the prompt: a model cannot "forget" them. Built-in vendor tools that
would work outside the platform are stripped from the request.

## No rows in "metrics only"

When a source is set to **metrics only**, the read tools answer with metadata, counts and aggregates. They return no
rows, no individual values and no business data. Counts below ten become "<10". The test database contains recognisable
marker values, and a test calls every read tool and proves that no marker ends up in the output.

## A name is data too

For a customer with real data, table and column names go to the model as pseudonyms. See
[pseudonymisation](https://plainwater.ai/en/wiki/concepten/pseudonimisering). Every text field in every tool call has a recorded meaning; a field
without that declaration makes the call fail. A customer with real customer data only runs with active
pseudonymisation. Otherwise the agent does not start, and every call is checked again.

## Secrets

- Source passwords are encrypted per source with a derived key of their own.
- The app never returns a secret, only a fingerprint and the moment it was set.
- Secrets never appear in a log, an error message or the audit.

## Customers are separated

If someone tries to reach another customer, the platform answers **404, not 403**. The difference between "does not
exist" and "not allowed" already gives away that something exists. A refusal sent to a model never names a customer's
source either.

## Permissions come from the database

What someone may do, the platform reads from the database on every call, never from the request itself. An unknown or
inactive user may do nothing. Nobody changes their own roles, an administrator included. See
[roles and permissions](https://plainwater.ai/en/wiki/beheer/rollen-en-rechten).

## Agent HTML runs separately

Dashboards and other HTML an agent creates run on a **separate domain**, never inside the application itself. Agent code
therefore cannot reach the user's session.

## The sandbox is a cage

Free SQL runs on a disposable copy, in a transaction that is always rolled back, with fixed limits on columns, rows, time
and number of calls. The copy's name comes from the platform, never from the agent. See
[the verification sandbox](https://plainwater.ai/en/wiki/concepten/sandbox).

## The platform watches itself

Every refused access becomes a data point. A security monitor recognises patterns such as probing, night work with no
history, a wave of deletions or a fast-burning budget, and turns them into an alert. An attempt to raise your own
permissions is critical immediately.

## Overview

| Guarantee | What happens if it breaks |
| --- | --- |
| Agent gets no keys | The test fails; the change does not go live |
| One decision per model request | A request without a decision is not forwarded |
| No rows in "metrics only" | The marker test fails |
| Cross-tenant 404 | The test fails |
| Agent HTML on a separate domain | The test fails |

## Example

In "metrics only" an agent tries to fetch the ten largest customers with a clever query. The read tool has no free query,
so that route does not exist. It tries via the sandbox. There the source is closed for rows, so the call is refused. The
refusal is in the audit. If the pattern repeats, an alert reaches the administrator.

:::tip Read on
- [Audit, transcripts and retention](https://plainwater.ai/en/wiki/veiligheid/audit)
- [European processing and hosting](https://plainwater.ai/en/wiki/veiligheid/europa)
:::
