Skip to content

Security model

  • PostgreSQL
  • MySQL
  • MariaDB
  • MongoDB
  • Redis / Valkey
  • Elasticsearch
  • CLI

Querybara holds credentials to your databases and can change their data, so its design limits what each part can reach. This page describes the protections in the desktop app and the CLI: how the app is isolated, where secrets live, how connections are verified, what asks before it writes, and how exported files are encrypted.

The interface runs as a sandboxed web page without Node.js: context isolation on, Node.js integration off in the page, its workers and frames, web security on, and no <webview>. Developer tools are off in packaged builds. The preload exposes nothing but platform and version strings and a way to receive RPC ports; no ipcRenderer method is reachable from the page.

Database drivers and secrets never load into the page. Drivers run in a separate process per connection; see How Querybara works.

The page is served from Querybara’s own app://querybara/ origin with a Content Security Policy that allows nothing remote:

default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline';
img-src 'self' data: blob:; font-src 'self' data:; worker-src 'self' blob:;
connect-src 'self'; object-src 'none'; base-uri 'none'; form-action 'none';
frame-ancestors 'none'

The two relaxations are for the editor and the grid: style-src 'unsafe-inline' (they inject style elements) and worker-src blob: (the editor can start workers from blob URLs). There is no unsafe-eval.

Beyond the policy:

  • Every request except those for the app’s own files and data:, blob: and devtools: URLs is cancelled before it leaves the machine. The spellchecker’s dictionary download is turned off.
  • The app never navigates away from itself and never opens a window. A link opens in the system browser only when it is a plain https URL to a named host, without credentials.
  • Every permission request from the page (camera, notifications, clipboard reading and so on) is refused.

The packaged binary has these Electron fuses set: running as Node.js off, cookie encryption on, the NODE_OPTIONS variable and inspector arguments ignored, ASAR integrity validation on, the app loaded only from its ASAR archive, and no extra privileges for file://.

Each password and secret in a profile has its own policy, chosen in the connection dialog:

Option Where the secret lives
Save in the OS keychain Sealed by the OS keychain and stored in the local store
Remember for this session In memory until Querybara quits
Ask every time Nowhere; Querybara asks when it connects

Sealing uses Electron’s safe storage: the Keychain on macOS, DPAPI on Windows, and libsecret on Linux. On Linux without a secret service such as GNOME Keyring or KWallet, there is nothing to protect the key, so Querybara reports that saving is unavailable rather than storing a weakly sealed value. Remember for this session and Ask every time keep working.

The local store keeps only sealed values. Plaintext never reaches the database file, error messages, or the logged or serialized form of any object. Each sealed value records the scheme that sealed it; a value sealed elsewhere (another machine, another user, a new keychain) is reported as unreadable, and Querybara asks for it instead.

The CLI cannot open the desktop app’s keychain. It seals the passwords it saves with a passphrase from QUERYBARA_PASSPHRASE: AES-256-GCM with a key derived by scrypt, and a fresh random salt and nonce for every value. See querybara profiles.

Secrets travel only from the main process to the process that opens the session. The CLI’s --verbose output never includes them.

Connections offer four TLS modes, chosen on the connection dialog’s TLS tab:

Mode In the dialog What it does
disable Disable TLS Plain TCP
require Require TLS, no verification Encrypted, but any certificate is accepted
verify-ca Verify certificate only The certificate must be signed by a trusted authority
verify-full Verify certificate and host name The certificate must be trusted and name the host

A new connection starts with TLS off, because most servers people add first, local ones or ones in a private network, have none. A URI turns TLS on when it says so: sslmode, ssl-mode, ssl or tls in its query string, or the rediss://, https:// or mongodb+srv:// scheme. Choosing an SRV record or an Elastic Cloud ID in the dialog turns it on too. The CLI follows the same rules for connection URIs.

A connection that crosses a network with TLS off, or with a certificate that is not fully verified, shows a warning that stays on the connection. A local server, reached at localhost, a loopback address, a Unix socket, or loopback at the far end of an SSH tunnel, shows no warning: its traffic does not leave the computer in the clear. A proxy without an SSH tunnel carries the traffic over the network, so it still warns.

Querybara checks every SSH server’s host key against a known_hosts file that the desktop app and the CLI share. Host keys are checked in the main process, for connection hosts and jobs alike.

  • A remembered key is trusted.
  • A new key opens Trust this SSH server?, showing its fingerprint, with Trust once, Trust and remember and Cancel. A question nobody answers in time counts as cancelled.
  • A changed key opens Warning: the SSH host key has changed, a blocking warning. Querybara does not connect. The only way forward is Remove the remembered key, which stays disabled until you tick The administrator confirmed that the host key changed; Querybara then asks about the new key.
A Trust this SSH server? prompt over the connection dialog during a connection test. It says Querybara has not seen bastion.larchwood.example before and shows its ssh-ed25519 SHA256 host key fingerprint, with Cancel, Trust once and Trust and remember buttons.A Trust this SSH server? prompt over the connection dialog during a connection test. It says Querybara has not seen bastion.larchwood.example before and shows its ssh-ed25519 SHA256 host key fingerprint, with Cancel, Trust once and Trust and remember buttons.
New SSH host keys are shown for you to check before Querybara connects.

On the command line, a new key is asked about in a terminal and otherwise refused unless you pass --ssh-accept-new. A changed key is always refused.

When a tunnel reaches every node of a MongoDB replica set or a Redis cluster, it opens a local SOCKS5 endpoint that needs a user name and password, random for each route, so other programs on the computer cannot use the tunnel through it.

  • UPDATE or DELETE without WHERE, DROP and TRUNCATE ask for confirmation before they run.
  • A profile whose Environment is Production asks before every write. Confirm every write does the same for any profile.
  • Read-only refuses writes outright.

Read-only and Confirm every write are on the connection dialog’s Advanced tab.

Elasticsearch writes follow the same rules. In the CLI, --yes answers the confirmations; without a terminal, nothing that needs confirmation runs without it.

For jobs, the main process refuses an import into a read-only profile before it starts, and asks for confirmation for the replace and delete modes and for any import into a production or confirm-writes profile. Structure and data sync applies are checked in main and again in the job runner. An apply runs only the script you reviewed: the job runner generates it again and refuses to run a different one.

Scheduled runs go through the same checks. A scheduled SQL file on a production or confirm-writes profile is confirmed once, when you schedule it. A scheduled run never asks for a password: it runs only with passwords that are saved or were typed earlier in the session.

A job reads only files you picked in an open dialog, and writes only where a save or folder dialog pointed. The page cannot name other files for a job. The same rule covers a schedule’s folder or SQL file, checked when you save the schedule, a Redis dump file for Dump analysis, and an ER model file. Dump analysis reads the file on your computer: nothing is uploaded, and no connection is needed.

  • Backups: a .qbak archive can be encrypted with a passphrase: AES-256-GCM under a key derived with scrypt, an HMAC over the header, and frames sealed so that any change, reordering or truncation is detected. The passphrase is not stored, except for a scheduled encrypted backup, whose passphrase is kept in the secret store under the schedule and sealed like a saved password. See The .qbak archive format.
  • Profile export: querybara profiles export encrypts the file with a passphrase (AES-256-GCM, a scrypt key, a random salt and nonce, and the header authenticated). The file holds secrets only when you pass --include-secrets.

The CLI never reads a backup passphrase from the command line, where other users of the machine could see it.

The updater runs in its own session that may reach only GitHub, over https. Every download is checked against the SHA-512 in the release metadata; on Windows the installer’s Authenticode publisher is checked, and on macOS the new app must satisfy the running app’s code signature. See Updates and channels.

Documents Querybara 0.1.1 · built frombc9f5aa