# How Crunu works: encryption, keys, machines and CI

> How Crunu encrypts secrets on your devices, gives every environment its own key, and gets values to teammates, servers and CI without the server reading them.

URL: https://crunu.com/how-it-works
Language: en
Updated: 2026-10-31

Crunu is an end-to-end encrypted secrets manager for teams: `.env` files, API keys and cloud credentials are encrypted on your devices, and the server stores only ciphertext. This page explains how that works in plain language, from your first sign-in to a production server and a CI job, and where the design stops protecting you.

## The short version

- Encryption and decryption happen only in your browser and in the `crunu` agent, never on the server.
- Your account key comes from your password and a Secret Key that never leave your device.
- Every environment, such as `staging` or `production`, has its own key. You only receive the keys of environments you were given.
- People, servers and CI pipelines all follow the same rule: each decrypts for itself.
- Who may read an environment is a signed document, so the server can't add itself as a reader.
- When someone leaves, their access stops, the keys they held are replaced, and you get a list of the values they saw.

## Your account key stays on your device

When you create an account, your device generates a **Secret Key**, a random string of about 128.8 bits. Your account key is derived from that Secret Key and your password together. Neither is ever sent to the server, in any form.

That is why a stolen copy of Crunu's database doesn't help anyone guess your password: every guess would also need your Secret Key. It is also why nobody can reset your password for you, including us. Your **Emergency Kit**, a printable page with your Secret Key, and an optional recovery code are how you get back in.

Details: [Emergency Kit and Secret Key](https://crunu.com/docs/concepts/emergency-kit-and-secret-key).

## Every environment has its own key

Secrets live in **projects**, one per application, and each project has **environments** such as `development`, `staging` and `production`. Each environment is encrypted with its own random key, and every saved version is encrypted with it, using AES-256-GCM.

The environment key is then sealed separately to each person and machine allowed to read it, with their public key. A developer with access to `development` never receives the `production` key, so they can't read production even if the server sent them its ciphertext by mistake. Access is enforced by cryptography, not only by a permission check.

Details: [organizations, projects and environments](https://crunu.com/docs/concepts/organizations-projects-environments).

## What the server stores, and what it sees

The server keeps ciphertext, public keys and signed documents. It decides whom to send each environment to, but it holds no key that could decrypt it at any point in the protocol. Each version is stored as one record, padded to whole 4 KB blocks, so the server sees neither the names of your variables nor their exact size.

The server does see metadata: the names of organizations, projects, environments and machines, email addresses, the audit log, and when each version was saved and roughly how large it is. Keep that in mind when you name things.

Details: [what the server sees](https://crunu.com/docs/security/what-the-server-sees).

## Signatures keep the server honest

Encryption stops the server from reading values. Signatures stop it from changing who can read them. The list of people and machines that may read an environment is a document signed by an owner or admin, and every version is signed by the person who saved it.

Browsers and agents check those signatures before they trust anything. They also remember the newest state they've seen and refuse anything older, so a server can't quietly roll an environment back on a device that has already seen a newer version.

Details: [how encryption works](https://crunu.com/docs/security/how-encryption-works).

## Teammates join by invitation

An admin invites a teammate with a link that is valid for up to 7 days. When the teammate accepts, both compare a short **fingerprint** of the new account's key, so a server can't slip in a key of its own. From then on, the teammate receives the keys of exactly the environments their roles cover, as an Editor, a Reader, or for specific files only.

Details: [invite your team](https://crunu.com/docs/getting-started/invite-your-team) and [roles](https://crunu.com/docs/concepts/roles).

## Servers run the crunu agent

A server that needs secrets is enrolled as a **machine**. An admin creates a single-use enrollment code; on the server, `crunu enroll` shows a fingerprint, and the admin approves the machine after comparing it. The machine gets its own keys and only the environments granted to it.

The agent decrypts on the machine and keeps the values in memory. `crunu run` starts your program with its variables, and `crunu pull` writes files with safe permissions where a program needs them. If the server is unreachable, the agent keeps serving the last verified state until its lease runs out, 24 hours by default. If you revoke a machine, it wipes its environments from memory at its next check, within minutes while it is online.

Details: [machines and leases](https://crunu.com/docs/concepts/machines-and-leases) and [install the agent](https://crunu.com/docs/getting-started/install-the-agent).

## CI pipelines use service tokens bound to OIDC

A CI job signs in with a **service token** that an admin creates in the browser and sees once. The token gets only the environments it needs, for example `staging` and nothing else.

On GitHub Actions, GitLab CI and Bitbucket Pipelines, or any other OIDC issuer, the token can also require the CI provider's OIDC token for a given repository, branch and deployment environment. A leaked service token is then useless outside that pipeline. The runner receives ciphertext and decrypts it itself, so CI follows the same rule as people.

Details: [OIDC binding](https://crunu.com/docs/ci/oidc-binding) and [connect your CI](https://crunu.com/docs/getting-started/connect-ci).

## When someone leaves

Removing a person is handled as a security event. The server stops sending them anything at once, and every environment they could read gets a new key that is never sealed to them. Their service tokens, share links and pending invitations are revoked in the same step.

Encryption can't erase what someone already saw, so Crunu shows an **exposure report** of which versions they received and when, and a checklist of the values to reissue at the providers that issued them.

Details: [offboarding a teammate](https://crunu.com/docs/guides/offboarding-a-teammate) and the [offboarding feature](https://crunu.com/features/offboarding).

## What this design doesn't protect against

- **A tampered web app.** A server that has been taken over could serve a modified page. Signed releases, a reproducible build and a local `crunu.html` file reduce that risk; they don't remove it.
- **Malware on your devices.** Anything that can read your screen or memory sees what you see.
- **Values already seen.** Rotation protects new versions. Old values stay valid until you reissue them at the provider.
- **Metadata.** Names, email addresses and the audit log are visible to the server.

The full list is on [known limitations](https://crunu.com/security/limitations), and the [security overview](https://crunu.com/security) goes deeper into each part of the design.
