Security

A tool that holds your credentials deserves bank-grade walls.

BugVilla stores persona credentials and replays authenticated requests against your API. That obligation shaped the architecture: a dedicated database per workspace, AES-GCM on every stored secret, and captures that keep the evidence but never the keys.

0
dedicated database per workspace
0
of stored secrets AES-GCM encrypted
0
secrets returned by the API
0
login per persona per run
Tenant isolation

Your workspace gets its own database — not its own rows

Most multi-tenant leaks are one missing WHERE clause. BugVilla removes the clause entirely: there is no shared table for your test data to leak across.

No shared tables. Nothing to filter.

Every workspace lives in its own MongoDB database on the platform — endpoints, personas, suites, runs, results. Isolation is a property of the connection, not a query convention.

  • A real database boundary. Your data sits in bugvilla_tenant_<yourslug>. Nobody else's data is in the same database, so there is no tenant_id filter to forget.
  • Resolved per request. Middleware identifies your workspace, opens its connection, and hands controllers models bound to that database alone.
  • Structurally impossible leaks. Controllers never import tenant models directly — they can only touch data through the request's resolved connection. A cross-workspace query can't even be written.
  • A minimal control plane. The shared master database holds a workspace registry and an email → workspace index. No credentials, no test data.
mongodb — tenant layout
show dbs
bugvilla_master
└─ workspace registry · email → workspace index · no secrets
bugvilla_tenant_acme
└─ acme's endpoints, personas, runs, results
bugvilla_tenant_globex
└─ a different database — not a different row filter
db.testruns.find({ tenant: "globex" })
✕ no such path — controllers only see the request's resolved connection
Secrets handling

Encrypted at rest. Masked everywhere else.

Persona credentials and environment auth are the most sensitive things you hand a testing tool. Four rules govern them — at write, at read, and in every stored capture.

Four rules for stored credentials

A credential enters BugVilla once, when you set up a persona or an environment. From that moment it is ciphertext, and nothing in the product hands it back.

  • AES-GCM at rest. Persona credentials and environment auth are encrypted before they reach the database. A database dump alone reads as ciphertext.
  • Masked on read. The API never returns a stored secret — reads get a mask. The UI can show that a credential exists without ever holding it.
  • Scrubbed from captures. Stored request/response captures have passwords and tokens removed. A report proves the finding without shipping a working login.
  • Never shared between personas. Each persona authenticates with its own credential set — no persona can borrow another's token. Run-scoped variables share created resource ids, never secrets.
persona — stored vs. returned
personas show admin
role Admin · auth mode: login
email admin@staging.acme.io
password ••••••••••••
stored as AES-GCM ciphertext · returned: never
captures show run-218 "POST /auth/login"
request.body.password → [scrubbed]
response.accessToken → [scrubbed]
✓ evidence kept, keys removed
Design choices

Small decisions that remove whole failure modes

Security that lives in the architecture, not in a policy document.

Sign-in that keeps passwords local

You sign in with email and password — no workspace name to remember. A master directory maps the address to candidate workspaces, but every password check runs against that workspace's own user record. Same email in two workspaces with two passwords? Each unlocks only the one it matches. The directory holds no credentials, so a stale entry can widen a search — never grant access.

Deletion with a retention window

Deleting a workspace never drops its database on the spot. The workspace is marked archived, its database is backed up, and the drop happens only after a retention window has passed. An account closed by mistake is a restore, not a disaster.

Auth without drama

Sign-in sessions are JWTs. Against your API, each persona logs in once per run — not once per test case. Four hundred endpoints would otherwise mean four hundred logins, which your rate limiter would rightly read as an attack. Personas that fail to authenticate report as errored instead of aborting the run.

Our posture

We assume someone will try

A platform that stores credentials and replays authenticated requests is worth attacking — pretending otherwise would be the real risk. So the design assumes the attempt: isolation that is structural rather than procedural, secrets that exist as ciphertext at rest and masks in transit, captures that keep findings but not keys, and deletion that stays reversible through its retention window. If you find something we should know about, write to hello@bugvilla.app — a human reads it.

Put your API on trial. Your keys stay locked up.

Upload a collection, confirm your personas, and read your first access matrix — no agents, no SDKs, nothing to install.