Security
Security model: the server stores only ciphertext
How Crunu encrypts environment variables on your devices, what the server can and can’t see, how keys and signatures work, and how to report a vulnerability.
On this page
Crunu encrypts the contents of each environment in your browser or in the crunu agent before anything is sent. The server keeps ciphertext, public keys and signed records, and at no point in the protocol does it hold a key that could decrypt them.
On app.crunu.com, Crunu runs that server. If you host Crunu yourself, you run it. Either way, the server can’t read your values. Crunu is in early access, so we describe only what the current release does and update this page when that changes.
The short version
- Your environments are encrypted on your devices. The server stores only ciphertext and has no key to read it.
- Your password and Secret Key never leave your device, so a stolen database doesn’t help anyone guess them.
- Each environment has its own key. People, machines and CI tokens get only the environments they’re given.
- Access lists and versions are signed, so the server can’t add itself as a recipient or change your data unnoticed.
- The server still sees metadata: names, email addresses, the audit log, and when each version was saved.
- The main remaining risk is a tampered web page. Known limitations lists it with every other limit we know of.
- We don’t publish a SOC 2 report or an external audit. Found a problem? Email security@crunu.com.
How a secret travels, step by step
Follow STRIPE_SECRET_KEY from the moment Priya saves it to the programs that read it.
- Priya’s browser encrypts and signs. Her password and Secret Key, 26 random characters created on her device, are combined into her account key, and neither is ever sent. When she saves, the browser encrypts the whole new version of the environment, every file and variable in it, as one record with that environment’s key (AES-256-GCM). It pads the record to whole 4 KB blocks so the exact size doesn’t show, and signs the version as Priya (Ed25519).
- The server stores what it can’t open. It keeps one encrypted record per version, not one per value, along with the signed access list that says who may read it. It decides whom to hand the ciphertext to, but it has no key to decrypt it.
- A teammate gets only the environments they’re given. Jonas receives the environment keys for development and staging, each sealed to his own public key (X25519). Production isn’t in his access list, so he never gets its key. His browser checks every signature and version number before it decrypts.
- A server gets its environment the same way. The agent on
api-prod-1receives the production key sealed to that machine, checks what the server sent, and keeps the decrypted environment in memory. Your program gets it throughcrunu run, or as files where you ask withcrunu pull. - A CI job gets exactly its share. The service token for GitHub Actions can read only
web-app / staging. With a CI binding (OIDC), it works only from the repository and branch you chose.
On app.crunu.com, the server runs on Cloudflare. The Subprocessors page lists every company that handles data for the service and what each one can see.
In the docs: How encryption works
Keys and algorithms
Crunu uses standard building blocks: AES-256-GCM to encrypt, X25519 to seal keys to a recipient, Ed25519 to sign, and HKDF-SHA256 and PBKDF2-SHA256 to derive keys. The browser uses its built-in WebCrypto and the agent uses the Go standard library. Both are tested against the same test vectors.
| Key | What it does | Where it lives |
|---|---|---|
| Password | One half of your account key. Your device stretches it with PBKDF2-SHA256 and 1,000,000 iterations. | In your head. Never sent. |
| Secret Key | The other half: 26 random characters, about 128 bits, created on your device. | On your devices and in your printed Emergency Kit. Never sent. |
| Account keys | One receives environment keys (X25519). The other signs your changes (Ed25519). | On the server, encrypted with a key derived from your password and Secret Key. |
| Environment key | Encrypts every version of one environment (AES-256-GCM). Access to development gives no access to production. | Sealed separately to each person, machine and token allowed in. |
| Organization signing key | The root of trust. It certifies members and machines and signs the revocation list (Ed25519). | With owners and admins, sealed to their account keys. |
| Organization recovery key | Every shared environment key is also sealed to it, so owners and admins can restore access (X25519). | With owners and admins. |
| Machine keys | Identify a machine and receive its environment keys. Created on the machine when it enrolls. | In a file on the machine that only the agent and root can read. |
| Service token | The token is the key. It’s created in an admin’s browser and shown once. | In your CI’s secret store. The server knows only its public keys. |
| Share link key | Decrypts the files shared through one link. | In the part of the link after #, which browsers don’t send to servers. |
| Release key | Signs every release of the agent and the web app (Ed25519). | With Crunu, which publishes the releases. |
If a database copy leaks, guessing your password from it doesn’t work: each guess also needs your Secret Key, which was never on the server, so checking a single guess means searching about 2¹²⁸ possibilities. Tokens are stored only as keyed hashes.
In the docs: Emergency Kit and Secret Key · Recovery code
Each environment is sealed separately
- Organizations are kept apart by their own keys. One server can host many organizations. Each has its own signing and recovery keys, and its environment keys are sealed only to members and machines that organization has certified.
- Development access doesn’t open production. Each environment has its own key, and someone without the production key can’t read production.
- Specific files means specific files. A person with that role, or a machine set to Selected files, receives a sealed copy of only the chosen files.
- Operators set up machines without seeing values. They hold no environment key at all. A person who holds the key approves each machine’s access.
- Network rules limit where content goes. An environment can be served only to allowed IP ranges, for people, machines and tokens alike. Relaxing a rule waits 15 minutes with an alert, unless a second admin signs it. Tightening applies at once. This is a rule the server enforces, not encryption.
In the docs: Roles in organizations and environments · Network rules
What the server can see, and what it can’t
A blind server still needs some facts: whom to deliver ciphertext to, and what to write in the audit log. Here is the full list.
Readable to the server
- Names of organizations, projects, environments, machines, service tokens, access profiles and network lists
- Members’ names and email addresses, and the addresses invitations go to
- Who has which role in which environment, from the signed access list
- For each version: its number, who saved it, when, and its size rounded up to a multiple of 4 KB
- Which version each person, machine and token received, when, and from which IP address
- The audit log, your devices and sessions, and the IP addresses they use
- Your network rules: the IP ranges you allow
- Your authenticator app secret, if you use one. The server checks your codes, so it stores that secret encrypted with its own key.
Ciphertext only
- Everything inside an environment: variable names and values, file names, paths, contents and notes. Each version is one encrypted record of the whole environment, so the server doesn’t see individual variables or which one changed.
- Files you send through share links
- The private keys of accounts and of the organization
Never sent to the server at all
- Your password and your Secret Key
- Your recovery code. The server holds a copy of your account key that only the code can decrypt.
- Machine private keys, which are created on the machine and stay there
- The key in a share link, which sits after the
#that browsers don’t send - Service tokens themselves. The server knows only their public keys.
That’s what we mean by a blind server: it sees who and when, but nothing inside your environments. On app.crunu.com, the readable list is exactly what Crunu can see, and the Privacy Policy says how long we keep it. Keep secrets out of names: a project named after an unannounced deal tells the server about the deal, even though every value inside stays encrypted.
In the docs: What the server sees
Who can read your secrets
- People you give access to. Members get only the environments they’re given. Hiding values in the app is a display choice: whoever can decrypt a value can copy it.
- Owners and admins. They hold the organization recovery key, so they can open every shared environment. They can also open members’ personal environments while the organization’s personal environment recovery setting is on, which is the default.
- Machines and CI. Each machine and token reads only what it was given. Enrollment codes last 15 minutes by default and burn on first use, and you approve a machine only after matching the fingerprint that
crunu enrollprints on it. A revoked machine drops its environments within minutes while it’s online. - Not Crunu staff. On app.crunu.com, Crunu runs the server, and the server has no key. We see the metadata above. Reaching your values would take changing the code that runs on your device, for example a tampered web page. Known limitations explains that risk.
- Anyone trying to get into an account. Sign-in allows 10 failures per IP address and 5 per account in 15 minutes, and an unknown email and a wrong password get the same answer. A new device needs your second factor, an authenticator app or a passkey, once you turn one on. Sessions end after 12 hours idle and 7 days at most, and a stolen session can’t change your password, Secret Key or account keys.
In the docs: Machines and leases · Bind a service token to CI with OIDC · Sign in from the terminal
How releases are built and checked
- Every release of the
crunuagent and the web app is signed with an Ed25519 release key. - Agent releases are published at releases.crunu.com: binaries,
.debpackages,install.shand a signed manifest. The installer checks the SHA-256 of the agent binary, andcrunu self-updatechecks the release signature with a key built into the agent. The install command the web app shows carries checksums from the signed release. - Crunu publishes the signed manifest of the web app at app.crunu.com. When the app loads, it checks that signature and its own build against the manifest and shows Signed build in the sidebar. Select the mark to check every file of the site. If anything doesn’t match, the app tells you not to enter your password.
- That check runs in code the same server delivered. It catches a broken or mixed-up deployment, but not a server that changes the page and the check together.
- The web app’s build is reproducible: one source commit always produces the same files. The page allows no third-party scripts and loads its own code with integrity checksums (CSP and SRI).
- Few dependencies: the agent uses only the Go standard library, and the browser code includes a single npm package,
yaml.
In the docs: Update crunu with self-update
Backups, availability and leaving
- On app.crunu.com, the database keeps up to 30 days of restore history at Cloudflare. During early access we don’t promise any level of uptime. See the Terms of Service.
- Keep your own copy. The app can download an offline copy of every environment you can access. It opens with your password and Secret Key, without any server. Network-restricted environments aren’t included.
- Run it yourself, or move. The same server runs in Docker on your own machine, on Cloudflare Workers, Vercel and Google Cloud Run, and on AWS App Runner in accounts that still have access to it. One archive with no plaintext values moves it between them, and the same archive is your backup. See Self-hosting.
In the docs: Export and offline copy · Backups and restore
What’s kept and for how long
- Versions. Each environment keeps its last 100 versions, up to 64 MB. Restoring an old version saves it as a new one.
- Audit log. Sign-ins, invitations, role changes, saved versions, key rotations, machines, tokens, share links and denied requests go into a log whose entries form a hash chain. Editing, deleting or inserting an entry breaks the chain, and Verify integrity shows it. The log is kept for 365 days by default, and owners can extend that. Values never appear in it, because the server doesn’t have them.
- Delivery records and deletion. The record of who received each version is kept for 90 days after its last delivery, then merged into a summary. Deleting your account takes your password and Secret Key. A deleted organization is unavailable at once and removed in batches shortly after. The Privacy Policy has the full table.
In the docs: Audit log · Versions and history
If the server itself is compromised
We design for the worst case: a breached database, a rogue operator or a hijacked cloud account, after which the server can answer with anything it likes. Your devices check what it sends, so even then it can’t read your values, add itself as a recipient, swap a key, change a version, rename production, pass off an organization of its own, or slip a different key in when someone joins. Apps and agents also remember the newest state they’ve accepted and refuse anything older, so a replayed access list doesn’t bring back someone you removed. A brand-new device has nothing to compare with, so it can’t spot a rollback on its first visit.
What it can still do is refuse service, read metadata and serve a tampered web page. Alerts flag sign-ins from new devices, reused enrollment codes, replayed CI tokens and repeated refusals. When someone leaves, the app rotates the keys they held and lists the values to reissue. For a stolen device, Device compromised replaces your account keys and rotates every environment you held a key to.
If we learn that app.crunu.com has been breached, we’ll email the affected account holders without undue delay: what happened, which data was involved and what to do next. A breach of the service exposes ciphertext and metadata, not the values in your environments, which can’t be decrypted without your password and Secret Key. The Privacy Policy states the same commitment.
In the docs: Offboarding a teammate · Rotate environment keys · Alerts
What’s up to you
Encryption takes the server off the list of things that can read your secrets. A few things only you can do.
- Print your Emergency Kit when you sign up and keep it away from your devices. Nobody, including us, can reset your password or recover your Secret Key.
- Create a recovery code and store it apart from the Emergency Kit. It opens your account after a waiting period, one hour by default, without your second factor.
- Turn on a second factor, and keep the idle lock short. The app forgets your keys after 10 minutes without activity by default.
- Give each person and machine only what they need, and keep owners and admins few.
- When someone leaves, reissue the values they saw at each provider. Rotation protects new versions, not what they already saw.
- If the app warns “Build signature doesn’t match: do not enter your password”, don’t enter it, and tell your admin.
In the docs: Limitations · Lock and idle timeout
Audits and paperwork
Crunu is new and in early access. It has no SOC 2 or ISO 27001 certification, and no external audit has been published.
These documents cover how the service handles data:
- Privacy Policy: what we hold, why and for how long
- Subprocessors: who runs the service with us, and where
- Terms of Service and Acceptable Use Policy
For your own reviews, owners and admins can export the audit log as JSONL and check its hash chain outside Crunu. When someone leaves, the exposure report shows which versions of which environments they received, when and from where, and you can download it.
Report a vulnerability
Email security@crunu.com with the steps to reproduce the problem. Leave real secrets out of the report.
When you test, please:
- test only against accounts and organizations you created yourself, or with their owners’ permission;
- don’t access or keep other people’s data, and tell us if you reach it by accident;
- don’t run denial-of-service tests, send spam or use social engineering;
- keep automated scanning light enough not to affect other users.
We’ll confirm that we’ve received your report and keep you informed while we work on it. We’ll agree on a disclosure date with you, normally within 90 days of your report.
The Acceptable Use Policy has the full rules, including our promise not to take legal action over good-faith research. The same contact is in security.txt.