Docs / Security

Security

A short, honest summary of how Dynv is built and where its limits are. The full design, including the cryptography, is in docs/DESIGN.md in the repository.

The model in four sentences

  1. Names and values are encrypted on your machine (CLI, MCP server or browser), with keys derived from tokens we never receive.
  2. We store ciphertext, plus opaque ids and timestamps. We hold no key that opens anything.
  3. Each variable document is signed with a key only you hold, so we cannot alter or swap your data without your services noticing and refusing it.
  4. A service token reads exactly one service. The server enforces that, and so does the cryptography: the keys of other services are never sealed to it.

The primitives are AES-256-GCM, HKDF-SHA256, SHA-256 and Ed25519, all of which browsers implement natively. Every ciphertext is bound to its account, service, token, version and key generation, so it cannot be moved to a different slot. Services only accept versions newer than the last one they saw.

Threat model

AdversaryCanCannot
Database or backup leakSee ids, counts, timestamps, padded sizes, token verifiers, the public signing key, audit IPs and keyed email hashes.Read any name, value or service name; derive a token; read a plaintext email. Our tests dump every collection and search for every name, value, email, code and token in several encodings.
Dynv itself, or someone who compromised our serversDeny service. Withhold updates. Serve a stale but validly signed version to a process that has never seen a newer one. See metadata: which token fetched when, from which IP. Delete data.Read your secrets. Forge or modify a document (signature). Swap documents between services or accounts. Substitute a key. Roll a client back below the newest version it has seen. Exception: see the dashboard caveat below.
Our email providerSee recipients and the contents of sign-up codes and notices; block or delay mail.Read secrets, passkey keys, recovery kits or invite links (never emailed). Sign in without your passkey or recovery token. A stolen sign-up code only lets someone create an account for an approved address that has none.
Network attackerNothing beyond what TLS allows. The client refuses plain http:// except to loopback.Read payloads even if TLS were broken; they are ciphertext. TLS still matters: a captured master credential could be replayed to make destructive writes.
One compromised service (for example, container RCE)Read that service's current env (it had it anyway). Use its token to fetch future versions until you revoke it.Read any other service. Write anything. Sign documents.
Revoked token holderKeep what it already saw.Fetch anything new (401, and the attempt is audited). Decrypt anything written after revocation, because the key rotates.
Leaked master tokenOwner token: everything in that account. Recovery token: read every secret and revoke other master tokens.Recovery token: write or sign anything.
Malicious AI agent using MCPOnly what you enabled. By default: list names and read the audit log.Read values back; set code-loading variables like NODE_OPTIONS or PATH; mint tokens. See MCP. Not preventable: an agent allowed to set PROXY_SERVER can point it at its own proxy, so scope what it may set.

Passkeys

You sign in with a passkey (WebAuthn). Where your device supports the PRF extension, the passkey also produces the secret that unlocks your keys, so there is nothing to type and nothing to phish: a look-alike domain gets neither the credential nor the key. Each passkey is internally a master token, so everything about tokens applies to it.

  • Sign-in needs user verification (biometrics or PIN) and a fresh, single-use challenge bound to our origin. Cloned authenticators are detected by their signature counter when the device reports one.
  • The passkey is tied to app.dynv.dev only, deliberately: another subdomain of dynv.dev can never ask for it.
  • If your browser or authenticator lacks PRF, the dashboard says so and you sign in with your recovery kit instead.

Email is identity, keys are separate

  • Sign-up is for approved email addresses. We send a 6-digit code (10 minutes, five attempts) to confirm you control the address. It proves who you are; it never unlocks data.
  • Your keys are created in your browser during sign-up. Email cannot decrypt anything, and neither can we or our email provider.
  • We store a keyed hash of your address to recognise it, not the address, and the code is stored only as a keyed hash. Sign-up and sign-in respond identically for any address, so they cannot be used to discover who has an account.
  • Routine sign-in is passkey only. There is deliberately no email code step on new devices: it would add the mail provider to your sign-in path without making your keys safer.

The recovery kit

At sign-up we hand you a file containing a master token generated in your browser. It is your way back in if you lose every passkey.

  • Save it offline (password manager or paper) before continuing. We never see it.
  • We cannot recover it, or your data, if you lose it and every passkey. That is what zero-knowledge costs. Make a spare with dynv admin master --out recovery.token.
  • It is a full-power owner key on purpose: a read-only key could not enroll a replacement passkey. Treat it as a break-glass, not for everyday use.

Members and writers

There is one writer by design, so that a malicious server cannot get two of your devices to sign conflicting histories. Invited members are viewers and can read every secret in the account, because their keys open all of it; revoking one stops access but does not un-leak, so rotate the upstream secrets. Per-service access for members and a multi-writer editor role are Coming soon. Details in Concepts.

Honest limits

  • Revocation does not un-leak. Dynv makes rotating an upstream secret a one-place edit, but you still have to rotate it.
  • Freshness is not guaranteed. A server can withhold updates. A process that has never seen a newer version, with no cache or a new machine, can be served an old, validly signed state once (trust on first use). Use --cache.
  • Metadata is visible to us: that a token fetched, when, and from which IP; counts of services and tokens.
  • Values an agent sets pass through that agent. That is unavoidable; what we prevent is plaintext passing through our servers.
  • Account-root rotation (invalidating a former master token's access to future data) is not built yet. Until then, revoking a master token cuts access but the holder has seen your account key. Coming soon

Supply chain and operations

The binaries are static; the server image runs as a non-root user with no shell on a minimal base. A release ships only with no known advisories in the Rust or JavaScript dependencies, a clean container scan, and a green zero-knowledge test. Failed authentication is rate limited by IP and by token. Server logs never contain secrets, email recipients, codes or links.

Reporting a vulnerability

Email [email protected] with “Security” in the subject, rather than opening a public issue. A dedicated security address is Coming soon.