---
title: The security model
description: What Dashies can and cannot see, who can read a published dashboard, and the controls that keep one organization's identity separate from another's.
updated: 2026-08-05
---

These pages explain how Dashies handles your data and your credentials. They
contain no steps. Where an action is involved, they link to the page that walks
you through it.

Start with the property that shapes everything else.

## Dashies holds a copy of your numbers

Most BI tools re-run your query every time somebody opens a view. Dashies does
not. Your dashboard's numbers are **computed once and shipped as static bytes**,
and a scheduled refresh recomputes them without any AI in the loop.

That is what makes a Dashies dashboard fast, shareable by link, and able to keep
working when your warehouse is busy. It also means the honest statement is:
**the aggregated results of your queries are stored on our infrastructure**, not
just streamed through it.

What that copy contains is entirely up to how you write the cube. A cube that
aggregates to `region` and `month` stores regional monthly totals and nothing
else. A `rows` dataset ships row-level records, because that is what it is for.
**Choosing the dataset mode is therefore a data-exposure decision as well as a
correctness one**, which is the part people miss. See
[Datasets and the four modes](/concepts/dataset-modes).

Your warehouse credential is handled completely differently from your data, and
that difference is the subject of
[Warehouse credentials](/trust/warehouse-credentials).

## What the authoring AI sees

Your own AI tool writes the dashboard, so it is worth being precise about what it
receives. During authoring it can see:

- **Your schema.** Table and column names and types, for the tables it
  introspects, plus an approximate row count on a warehouse table.
- **A sample of real results.** When it validates cube SQL before publishing,
  Dashies runs the query and echoes back the first rows so the AI can check the
  shape. That echo is capped at **200 rows and roughly 8 KiB**, whichever binds
  first.
- **The dashboard's own contents**, because it wrote them.

What it **never** receives, at any point:

- **Your warehouse credential.** No publishing tool takes a password, key, or
  token as a parameter, and the service that serves those tools has no ability to
  read stored credentials at all. The tool that lists your data sources returns
  ten descriptive fields: `id`, `kind`, `label`, `engine`, `status`,
  `last_verified_at`, `last_error`, and a `health_state` / `health_error` /
  `health_source` trio. No credential, and no host.
- **Anything from another account.** Every tool acts as the account that
  authorized it.

And after publishing, the AI is out of the loop entirely: scheduled refreshes
re-run your SQL server-side with no model involved.

:::note{title="The practical consequence"}
If your organization's rule is "no production data through an AI tool", the
surface to think about is the **validate step's sample rows**, not the refresh.
Validating against a table of real customer records means a few of those records
reach your AI tool the same way any other output would.

Aggregating in the cube rather than selecting raw rows keeps that sample
aggregated too.
:::

## Who can read a published dashboard

A dashboard is **public** or **private**.

- **Public** means anyone with the link. There is no crawler-only exception and
  no expiry. Treat a public dashboard as published on the open internet, because
  it is.
- **Private** means you, or, for a workspace dashboard, the workspace's members.

A private dashboard requested by anyone else returns a **404 that is byte for
byte identical** to the 404 for a URL that never existed. The check happens
before any redirect, so guessing at URLs cannot reveal which of your dashboards
exist. The page says only "This dashboard is private or no longer available",
which covers all three cases on purpose.

When a private dashboard's data is too large to inline, it is served as a
separate file behind a **signed, short-lived link** valid for four hours. That
link is only ever minted while serving the dashboard to somebody already
authorized to see it, so there is no way to obtain one without the access it
represents.

Dashies never returns another user's account identifier for a dashboard you can
see: the serving path computes only whether **you** are the owner.

## The domain bind

The single most important control in the enterprise surface, and the reason
[domain verification](/admin/domain-verification) exists.

A workspace can create sign-in sessions and add members **only for email
addresses on the domain it has proven it controls**. Without that rule, an
administrator of any workspace could type in another company's domain and start
creating Dashies sessions for that company's employees.

It is enforced in four independent places, so that removing any one of them does
not open the door:

- On sign-in started from Dashies, the asserted address must end with the
  workspace's verified domain.
- On sign-in started from your identity provider, the same check runs again.
- On every directory-sync event, the same check runs a third time.
- In the database itself, changing a workspace's email domain **automatically
  clears its verification**, and the verification field cannot be written by the
  application's ordinary user-facing permissions at all. Only the server-side
  path that has actually completed the DNS check can set it.

That last layer is what makes the first three hard to bypass: even a bug in the
web application cannot mark a domain verified.

A domain can be verified by exactly one workspace at a time. Two workspaces may
both name it, but only one can prove it.

## The rest of this section

- **[Warehouse credentials](/trust/warehouse-credentials)** - where the
  credential you enter is stored, what can read it, and what "read-only" is
  actually enforced by on each engine.
- **[Dashboard isolation](/trust/dashboard-isolation)** - why a published
  dashboard cannot reach your Dashies session, and what that costs.
- **[Privacy and data handling](/trust/privacy)** - what we collect, analytics,
  and deletion.

## Reporting a vulnerability

Security reports are welcome. We do not pay bounties, and we would rather say
that up front than have you find out afterwards.

Report **privately, by email, with `SECURITY` in the subject line**, to the
contact address on [dashies.xyz](https://dashies.xyz). Please do not open a
public issue or a support ticket for a suspected vulnerability.

**Ask us for the rules of engagement in your first email, before you test.** They
set out what is in scope, the constraints on how you may test, and the safe
harbor that covers research conducted within them. We will send them straight
back. Do not assume a protection applies to testing you have already done: this
page is not that document, and we would rather answer the question than have you
rely on a summary of it.

Two things to get right in a first email: include reproduction steps from a
clean account, and **do not send live secrets or anyone else's data**. Send the
smallest redacted proof that shows the behaviour.

What we most want to hear about, roughly in order: cross-tenant access, reading
a private dashboard or its dataset without authorization, dashboard content
escaping its isolation, warehouse credential exposure, reaching an unintended
host through a warehouse connection, and anything that writes to a connected
warehouse.

Denial of service is in scope but **do not test for it**. If you find one
through safe analysis, tell us how you found it without exercising it.
