Skip to content

v1.5.0

Choose a tag to compare

@mr-grj mr-grj released this 12 Oct 15:42
· 104 commits to master since this release

Security

  • The web UI and the CLI no longer receive the vault key. Unlocking now opens a session on the server: the key stays in the server's memory and the client keeps only a random session token, sent in an x-ciphermoth-session header (Authorization stays free for a reverse proxy's own login). A token that leaks (for example through a browser extension) stops working when the session ends and never reveals the key; previously a leaked key stayed valid until the master password changed. Until v1.6.0 the server still hands the key to clients that ask for it the old way, so v1.4.x clients keep working (see Deprecated).
  • Sessions end on the server. The server enforces the inactivity timeout from Settings itself, with 5 seconds of tolerance for request latency, and a 12-hour maximum, so a forgotten tab or a copied token can't keep the vault open. Only real use counts as activity: the web UI reports keyboard, mouse and touch input at most every tenth of the timeout (between 1 and 15 seconds), and checking a session's remaining time, background requests and hidden tabs never extend it. The UI's countdown is taken only from the server's answers (a heartbeat that fails doesn't extend it) and is re-read every 15 seconds while the tab is visible, so it never outlasts the server's, also after another device shortens the timeout. It locks after a suspended laptop wakes up past the deadline, and after a tab was hidden longer than the hidden-tab setting even if the browser froze its timers. An expired session is deleted and cannot be revived, even by raising the timeout. Logging out, auto-lock and closing the session from the CLI end it on the server too. Changing the master password ends every session, including those of other devices, and so does any change of the vault key made outside this server process.
  • The web UI may only connect to its own API. The frontend image's Content-Security-Policy allowed connections to any host (connect-src *). At start-up the image now allows only its own origin, the origin of CIPHERMOTH_API_URL, and the GitHub address of the optional update check, which makes it much harder for injected code to send the session token or vault contents elsewhere. It is not a complete barrier: a policy cannot stop navigation to another site or WebRTC, it ignores query strings on the allowed GitHub address, and with an IPv6 API address it can only restrict the scheme. The API URL is checked first: every value that worked before is still accepted (absolute http(s) URLs, //host URLs and relative paths, with a logged warning for a user name, query or fragment), and an unsafe value (another scheme, or characters that could rewrite the policy or the app) gets a page explaining what to fix instead of the app. Lint rules now reject the HTML and eval sinks such code would need.
  • Unlocking no longer stalls the server. The deliberately slow Argon2id and bcrypt steps run off the request loop, so other requests keep being answered while someone unlocks. Argon2id derivations still run one at a time, which keeps memory at one 64 MiB derivation however many unlocks arrive together.

Added

  • POST /api/master_password/unlock returns a session token, POST /api/master_password/lock ends one, GET /api/master_password/session reports how long it has left without extending it, and POST /api/master_password/session records activity. POST /api/master_password/create returns a session token instead of the vault key: a v1.4.x browser tab that creates a new vault during the update gets a working vault and asks for the master password once more; scripts that create vaults must read session_token (or call the deprecated /check). /api/meta lists the vault-sessions feature, and legacy-key-auth while that is accepted.
  • CIPHERMOTH_LEGACY_KEY_AUTH=false refuses clients that still use the vault key (see below) before v1.6.0 does. Existing installs keep their own docker-compose.prod.yml, which does not pass this variable on: add CIPHERMOTH_LEGACY_KEY_AUTH: ${CIPHERMOTH_LEGACY_KEY_AUTH:-} to the backend's environment, then check that /api/meta no longer lists legacy-key-auth.

Changed

  • Everyone is asked to unlock once after updating. Sessions live only in the server's memory, so restarting or updating the server also locks every open tab and the next request returns to the unlock screen. The backend must keep running a single worker process (the shipped images do).
  • The CLI opens a session for each command and locks it when the command ends, even on errors. If a session expires while you are still answering prompts, it unlocks again once with the password you already typed. Against servers older than v1.5.0, which have no unlock route, it still uses the vault key, as those releases expect; it never falls back to that because of another error.
  • CIPHERMOTH_API_URL is checked when the UI starts. Any value that worked in v1.4.7 keeps working. A value the check refuses shows a "CipherMoth cannot start" page that names the problem; the backend and your vault are unaffected, and a one-click update still reports success because the updater checks only the backend, so open the UI once after updating. An IPv6 address works, but the policy can then only restrict the scheme, so prefer a host name.
  • Settings: the inactivity warning must now be shorter than the inactivity timeout on the server too (the UI already required it).

Deprecated

  • POST /api/master_password/check and the x-ciphermoth-key-derivation header, which hand the vault key to clients and accept it back, are kept so that v1.4.x CLIs and browser tabs that were open during the update keep working. They behave exactly as in v1.4.7 (the key must match the vault, under the same locks) and /check answers with a Deprecation header. They will be removed in v1.6.0. Update scripts that call the API directly to use /unlock and send the token in x-ciphermoth-session.