Security model

ApiVault is built for developers who read the security model. This page covers encryption, authentication, session management, and best practices across all integration surfaces.

Encryption

All API key values are encrypted at rest before storage. ApiVault supports two encryption modes, configured in Settings → Encryption Key.

Default mode

Secrets are encrypted using server-managed keys. No vault key is required to reveal keys — your authenticated session (or CLI/MCP token with appropriate scope) is sufficient.

Custom mode

You set a personal custom vault key that ApiVault never stores. Secrets are encrypted with a key derived from your vault key. Decrypt operations require the vault key via:

  • Web UI vault key prompt
  • CLI: --vault-key, APIVAULT_KEY, config vaultKey, or interactive prompt
  • MCP: vault_key parameter on reveal_key, add_key, update_key

You can switch between modes, change your vault key, or disable custom encryption from the encryption settings page. Changing or disabling custom encryption requires your current vault key and re-encrypts existing keys atomically. New or rotated custom keys use a unique salt and a memory-hard derivation. New custom keys must be at least 16 characters; legacy custom vaults remain readable with their existing derivation until you explicitly rotate them.

Authentication

The web app supports multiple authentication methods:

MethodDescription
Google OAuthSign in with your Google account. Manage linked accounts in Settings → OAuth Connections.
Email & passwordTraditional credentials with email verification and OTP password recovery. Set or change password in Settings → Security & MFA.
Email OTP Verification6-digit one-time password sent via email to verify account ownership and facilitate secure password resets.
PasskeysWebAuthn passkeys for passwordless sign-in (Touch ID, Face ID, Windows Hello, hardware keys).
TOTP 2FATime-based one-time passwords via an authenticator app. Can be required after initial setup.
Enable MFA early
Turn on TOTP or a passkey in Settings → Security & MFA as soon as your account is set up. MFA protects vault access even if your email password is compromised.

Passkeys can also serve as a second factor when MFA is enabled. The sign-in flow verifies the factor you actually use without exposing whether a particular email address has TOTP or passkey enrollment.

Email verification & OTP recovery

To prevent unauthorized account registration and enable secure self-serve password recovery, ApiVault implements cryptographically secure 6-digit One-Time Passwords (OTPs):

  • SHA-256 Hashed Storage: Plaintext OTP codes are never stored in the database. Only SHA-256 hashes are persisted at rest.
  • Time-Bounded Validity: OTP codes expire automatically after 10 minutes.
  • Rate Limiting & Anti-Spam: A strict 60-second cooldown is enforced between code dispatch requests.
  • Brute-Force Protection: Verification records automatically self-destruct after 5 failed attempts.

Sign-in attempt limits

Failed authentication attempts are counted per account and per source address, so a stolen password cannot be searched for and a six-digit second factor cannot be guessed exhaustively. A completed sign-in clears the counter, so ordinary use — including mistyping a password a few times — never reaches a limit.

AttemptLimitCounted per
Password sign-in10 failures per 15 minutesAccount and source address
Authenticator (TOTP) code5 failures per 15 minutesAccount and source address
Custom vault key (web, CLI, and MCP)10 failures per 15 minutesSigned-in user and source address
Email OTP code5 failures, then the code is destroyedIssued code

Vault-key attempts are counted per user rather than per project, so one member of a shared project cannot exhaust the allowance for their team-mates. Requests that exceed a limit are answered with 429 and a Retry-After header.

The vault-key limit applies wherever a vault key can be supplied — the web vault-key prompt, the CLI's --vault-key flag and APIVAULT_KEY, and the MCP reveal_key, add_key and update_key tools. All three resolve vault keys through the same throttled code path, so no client has a faster route to guessing one. A correct key clears the counter, so a scripted apivault run or env export that decrypts many secrets in a row is never throttled.

Sessions & tokens

ApiVault uses three independent credential types. Revoking one does not affect the others:

CredentialUsed byRevoke via
Browser sessionWeb dashboard, settingsSettings → Sessions & Devices, or sign out
CLI tokenapivault commandsapivault logout or Settings → Sessions & Devices
MCP OAuth tokenCursor, Claude, MCP clientsSettings → MCP Connections

CLI tokens issued by the browser approval flow expire 90 days after they are minted, so a token that leaks has a bounded lifetime even if nobody notices. The expiry date of each connection is shown in Settings → Sessions & Devices, where a token can also be revoked at any time before it expires. Reconnect with apivault login to obtain a fresh token.

Browser request protections

Cookie-authenticated state-changing requests are restricted to the app's own origin. CLI and MCP integrations use bearer tokens instead, so they do not depend on browser cookies or cross-site request behavior.

Anonymous CLI connection requests are limited to five per source address per ten-minute window. Production reverse proxies must overwrite, rather than append to, forwarded-IP headers before forwarding requests to ApiVault.

Content Security Policy

Every response carries a Content Security Policy in which scripts execute only if they carry a nonce — an unguessable value generated fresh for that single response. A script injected into a page through stored content, such as a key name, a project name or a note, has no valid nonce and the browser refuses to run it. strict-dynamic extends that trust to the bundles those scripts load and makes origin allowlists inert, so there is no host an injected script can be served from instead.

Because a nonce only exists once a request is being served, every page is rendered per request rather than prebuilt. Responses also set Strict-Transport-Security, so browsers refuse to reach ApiVault over plain HTTP, alongside X-Frame-Options, X-Content-Type-Options, Referrer-Policy and a Permissions-Policy that denies camera, microphone and geolocation access.

CLI security

  • Browser-based pairing — CLI auth uses a one-time browser approval flow. No passwords are typed in the terminal.
  • Local token storage — tokens are stored in ~/.apivault/token.json with owner-only permissions on Unix.
  • Dotenv isolation — apivault run temporarily hides local .env files so injected vault secrets take precedence.
  • No secrets in shell history — prefer config set vaultKey (hidden prompt) or APIVAULT_KEY over typing vault keys inline.
Prefer run over export
Use apivault run to inject secrets into a process instead of writing decrypted values to a .env file on disk. Fewer files means fewer leak paths.

Service tokens

A pipeline cannot complete a browser approval, so it authenticates with a service token instead — a credential owned by a project rather than a person.

  • Hashed at rest — only a SHA-256 hash is stored. The raw value is shown once at creation and cannot be recovered or re-displayed.
  • Scoped — listing keys, revealing their values and modifying them are three separate grants, capped by the role of whoever created the token.
  • Optionally pinned — to one environment, and to a set of IP ranges. A request whose source address cannot be determined is refused when an allowlist is set.
  • Always expiring — between 7 and 365 days, defaulting to 90. There is no never-expires option.
  • Confined to key endpoints — project settings, members, invitations, encryption configuration and token creation itself all reject them, so a leaked CI credential cannot add a collaborator, rotate your vault key, or mint a replacement for itself.
  • Separately audited — every request is logged under its own service source with the token's name, including refusals.

MCP security

  • Scoped OAuth — agents receive only the permissions you approve (keys:read, keys:write, keys:reveal).
  • Unverified clients are labelled — MCP clients register themselves, so the name and icon shown during consent are self-reported and are marked Unverified. The consent screen displays the redirect origin the authorization code would be sent to; verify it matches the tool you started the connection from before approving, especially for keys:reveal.
  • Isolated token boundaries — MCP OAuth tokens are strictly isolated to the /mcp endpoint and cannot be used to authenticate general REST APIs, enforcing cryptographic least privilege.
  • Least privilege — grant read-only scopes when agents only need to browse keys; avoid keys:reveal unless necessary.
  • Short-lived access tokens — MCP access tokens expire after 1 hour; refresh tokens last 30 days.
  • Revocable connections — each MCP client appears separately in Settings → MCP Connections.

See MCP Integration → Security practices for agent workflow guidance.

Best practices

  • Never commit ~/.apivault/, exported .env files, tokens, or vault keys
  • Add .env and .env.local to .gitignore
  • Use custom encryption mode for an extra layer of zero-knowledge protection
  • Enable 2FA and passkeys on your account
  • Review and revoke stale CLI and MCP connections periodically
  • Use apivault run instead of exporting secrets to disk when possible
  • Do not paste raw secrets into chat, commits, logs, or issue trackers
  • Request minimum MCP scopes for AI agents

Data storage

ApiVault stores encrypted key values, metadata (name, service, environment, notes), and account data in a MySQL database via Prisma. Secret values are never stored in plaintext. The CLI and MCP server communicate with ApiVault over HTTPS only — they never access the database directly.