Security
Security depends on how you run DBO Studio. A desktop app on your laptop is not the same as a container on the public internet.
Trust model
| How you run it | Assumption | If the port is on a network |
|---|---|---|
| Desktop, or local web with no login | The person at the keyboard owns the machine | Low locally. Do not expose the port. |
Web with login (local auth) | Each user has an account; connections belong to that user | Medium on a LAN. Use TLS on the internet. |
| Public server without login | Anyone who can hit the port | High. Bootstrap an admin and terminate TLS. |
Without login (none), the API issues an owner session to the first client that connects. That is intentional for local development.
The desktop app never shows login. The owner is always "desktop".
Warning: A Docker publish of port 9000 to 0.0.0.0 with auth mode none is a public unauthenticated database client. Set APP_ADMIN_EMAIL and APP_ADMIN_PASSWORD before you expose it. See Configuration.
Local authentication
When auth mode is local:
- Users sign in with email and password. The API sets an HttpOnly
dbo_sessioncookie. - Almost every
/api/*route requires that session (login and health are the exceptions). - CORS allows only
APP_ALLOWED_ORIGINS. Localhost is not auto-trusted in this mode.
Session cookie
- Name
dbo_session, HttpOnly, SameSite=Lax - Secure when the public URL is HTTPS
- Idle timeout 24 hours, absolute lifetime 7 days
- Logout deletes the server row; login and password change rotate the session
- A database error during session lookup returns 500 — it does not mint a new owner
First admin
APP_ADMIN_EMAIL and APP_ADMIN_PASSWORD create the first admin once. The password must be 8–40 characters and include a letter and a number. The user must change it before data APIs work.
Those variables are ignored after users exist. Passwords are bcrypt hashes and are never logged.
Roles
Accounts are admin or member. Settings → Administration → Users is admin-only.
DBO does not implement SQL GRANT. Restrict what a database user can do in the engine itself, and use Safe Mode for destructive UI actions.
OIDC, proxy header auth, 2FA, LDAP, and a shared static API token are not available.
Safe Mode
Safe Mode is an extra app password (bcrypt) that gates destructive SQL and grid edits. Turn it on in Settings → Security.
It is not the same as the login password. It is stored in the app database. Enable it when more than one person uses the same instance.
Secrets at rest
Connection passwords are encrypted with AES-GCM. The key file is created mode 0600, either at APP_SECRET_KEY_PATH or under the app data directory.
Passwords never appear in API responses or logs.
AI provider keys are encrypted when that key file exists. If encryption fails, the update is rejected rather than stored as plaintext.
Shared connections
On a web deploy with login, you can share a connection card (host, port, database, SSL, name) with other DBO users.
Catalog roles viewer and editor control who can use or edit the card. They are not SQL read-only, and they do not replace database GRANT.
By default each user types their own database password. The owner may also share a remembered password. Anyone who can read both the data volume and app_secret.key can decrypt that vault — treat it as a blast-radius choice.
The desktop app does not share connections.
MCP tokens
MCP access uses hashed tokens in the app database, compared in constant time. Configure MCP in Settings → AI. The public URL must match APP_PUBLIC_URL or APP_MCP_PUBLIC_URL from Configuration.
SQL and exports
- Guarded paths classify statements as read or write before they run
- Safe Mode blocks writes when it is on
- Grid filters and sorts use an allow-list of operators and quoted identifiers
- Web exports cannot write outside the
exports/directory - MCP execute is read-only AST validation with injected limits
- Job result downloads refuse paths outside that export directory
Logs
Fetching logs requires a valid session. In local mode that means the caller already signed in.
Hardening checklist
Use this before you put DBO on the internet:
- TLS at the reverse proxy
- Auth mode
local(bootstrap admin viaAPP_ADMIN_EMAIL/APP_ADMIN_PASSWORD) -
APP_PUBLIC_URLmatches the public origin -
APP_ALLOWED_ORIGINSlists only trusted frontends - Data volume backed up (
dbo.db,app_secret.key) - Safe Mode on if operators share the instance
- Database servers accept connections only from known hosts
- Shared-password vault off unless the team truly needs one database identity
Reporting issues
Send a minimal reproduction. Never include live credentials or production tokens.
Related
- Configuration — environment variables and auth bootstrap
- Docker — TLS at the proxy, volumes, upgrades