Skip to content
Not released yet: version 0.1 is being built. See what works today.

Security

Report a vulnerability privately, through a GitHub security advisory. Do not open a public issue or pull request for it. The policy in full is SECURITY.md in the repository; this page summarises it.

  • what you found and which part it is in: the api, the CLI, the runner, the compose file or an image
  • the version, or the commit if you built from main
  • the steps to reproduce it, and what an attacker gains
  • whether you plan to publish, and when

Test against your own local stack (mb dev up) with sample data. Never test against a deployment you do not run.

These are targets, not guarantees. This is a small team.

Step Target
We confirm we received your report 3 working days
We tell you whether we accept it as a vulnerability 7 days
A fix for a confirmed high-severity issue 30 days
A fix for a confirmed lower-severity issue the next minor release

We fix the issue in private, release a patch version and publish a GitHub security advisory, crediting you unless you ask us not to. The fix is listed in the changelog.

The core: the api, the CLI, the runner and its warehouse modules, the stack definition (stack/compose.yml, the Postgres roles and the container hardening), and the images and package it publishes.

Out of scope: an organisation’s own project (its pipelines, models, metrics, access policy and deployment belong to it), flaws in dlt, dbt, DuckDB, anfra, Better Auth, Cerbos or another dependency (report those to their makers, and tell us if our configuration makes one reachable), findings that need access an attacker already has, and scanner output with no demonstration.

Only the latest minor release gets security fixes. Until 0.1 is released, only main does.

  • Every request runs as the person asking. Agents sign in over MCP with OAuth; service accounts with their own key pair. There is no shared warehouse key.
  • Cerbos decides before the query engine sees a request, and refuses when it cannot answer. A dataset you may not read gets the same refusal as one that does not exist.
  • Every decision is in the audit log, refusals included. The log is append only, and a request whose audit row cannot be written gets no answer.
  • Definitions and policies change only in git, through a pull request a person reviews. mb check compiles and tests the policies.
  • Credentials are stored as digests or public keys only. A project’s secrets.yml holds only the names of its secrets, never their values.
  • The query engine sits on an internal network that only the api reaches, through an allowlist of operations. Every container drops its Linux capabilities, and all but Postgres run with a read-only root filesystem.

Access is decided per dataset. Rules per row, such as each market seeing only its own orders, are not in 0.1: put those rows in a dataset of their own. Security, in depth explains each control, and the changelog says which are built.