architecture · access · isolation

Security

You are being asked to hand over credentials to the database your business runs on. This page is what we do with them, in enough detail to check.

The path a question takes

There is exactly one route from a question to your data, and it is narrow by construction.

query pathone route · 4 gates
The path a question takes A single vertical route. You send a question to Evalyst, which passes it to the agent. The agent runs with no shell, no file access and no network — none of the three are in its tool surface. Its one route to your data is the run_sql tool, and that route passes through four gates in series: resolve, which scopes the query to your workspace only; guard, which parses the statement in your engine's own dialect and refuses anything that is not a single read-only SELECT; route, which picks the host holding that date range; and driver, which connects using read-only credentials under row, time and scan caps. Only past all four does the query reach your database. you agent not in its tool surface: shellfilesnetwork run_sql resolve your workspace only guard one read-only SELECT, parsed in your engine's dialect route which host for that date range driver read-only credentials, plus row / time / scan caps refused your database

The agent cannot run a command, read a file, or open a socket. Its entire tool surface is the set we expose to it, and shell access is not in that set — not disabled by policy, not guarded by a prompt, simply not present.

Read-only, proven when you attach

Most tools check permissions by asking politely and believing the answer. We treat grant text as a claim to be tested: each driver reads the engine's own authority on effective privilege — has_table_privilege on Postgres, SHOW GRANTS on MySQL and Snowflake, testIamPermissions on BigQuery — and runs a probe that writes nothing but makes the server reveal what it would have allowed. If either says the credentials can write, the source does not activate.

The SQL guard stays in place regardless, as the second line: every statement is parsed in your engine's dialect and rejected unless it is a single read-only SELECT, with a per-engine table of functions that read the filesystem or reach the network blocked by name. But a guard is code, and code has bugs. On a read-only account the worst case of a guard bug is a failed query; on a writable account it is your data. That asymmetry is why the credential check exists at all.

where this is honest

The gate is acknowledgeable, not absolute. An admin can accept write-capable credentials for a single source — recorded with who, when and why — because a hard refusal has its own failure mode: an organisation whose DBA has not yet created a reader cannot onboard at all, and the pressure that creates is to switch the check off everywhere. When it is accepted, the source's badge keeps saying read-only unverified, on the card, in the API, and in what the agent is told. It changes what we allow. It never changes what we claim.

Credentials

  • Entered in an admin-only form and encrypted at rest. They are never typed into chat and never appear in a conversation.
  • The model never sees a value. When a connector needs a credential the agent declares the field name — AWS_SECRET_ACCESS_KEY — and the value goes from your browser to the vault without passing through it.
  • Driver and connection errors are scrubbed of secret values before they can reach a log, a transcript, or your screen.
  • For SSH tunnels we generate the keypair and give you only the public half, with a ready-to-install line that restricts it to forwarding to that one database and nothing else. A key you paste has already been through a clipboard, a browser and a form, and is usually a key that opens other things — so we would rather not be holding it.

Tenant isolation

Every row belonging to a workspace carries its workspace id, and that is enforced twice: in every query the application makes, and again by row-level security in Postgres, which defaults to denying. The second one exists because the first one is a discipline, and disciplines have off-days.

Retrieval is scoped the same way. Past conversations are searched within your workspace only — a leak there would put one company's history into another company's prompt, which is the single most dangerous path in a system like this, so it gets the same treatment as the data itself.

Generated connectors run sandboxed

When the agent writes a connector for an API, that code is untrusted by default. It is validated inside a container with a read-only root filesystem, dropped capabilities, no privilege escalation, memory and CPU and process limits, a hard timeout, and no network at all unless the connector declared it needs one. Credentials are injected as environment variables at run time and are not written to the image.

A connector is registered only if it passes the gate — test() reporting ok and discover_schema() returning fields. One that fails is stored as broken, with the error, rather than left half-installed.

where this is honest

A connector that has been granted network access can currently reach any host, not just the API it was written for — per-host egress allow-listing is built but not yet enforced. Until it is, granting network to generated code is a decision worth making deliberately, and the plugin factory stays limited to workspaces we have talked to rather than being open to every new sign-up.

What we store, and for how long

  • Your rows stay in your database. We hold query results long enough to answer the question, plus the snapshots behind any dashboard you pin — that is the data that makes a saved chart render without re-querying.
  • Conversations, saved charts, semantic models and audit records live in our control plane.
  • Not used to train models. Inference runs through Anthropic's API under commercial terms that exclude training on inputs and outputs.
  • Deleting your workspace deletes its sources, credentials, conversations and snapshots.

Subprocessors

The current list, with what each one can see, is on the subprocessors page and changes there first.

What we don't claim

We are pre-certification. There is no SOC 2 report, no ISO certificate, and no compliance badge on this site, because we do not have one and a logo is not a control. What we have is the list above, which you can verify against the product during a trial: attach a source with write permissions and watch it refuse to activate.

Found something wrong? security@evalyst.ai — we will answer, and we will not argue about whether a report was in scope.