Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.murmur.dev/llms.txt

Use this file to discover all available pages before exploring further.

Murmur uses multiple encryption layers to protect your credentials. This page explains what is encrypted, when, and how — from initial setup through agent execution to secret storage.

Profile encryption

When you run murmur setup or murmur install, your developer credentials are encrypted immediately:
  1. Credential collection — your Anthropic API key and other sensitive configuration are gathered.
  2. KMS encryption — the credentials are encrypted using the tenant’s Cloud KMS key via an authenticated encrypt call.
  3. AAD binding — Additional Authenticated Data (AAD) is included in the encryption, binding the ciphertext to your tenant and identity. This prevents cross-tenant profile reuse.
  4. Local storage — the encrypted blob is stored in .murmur/murmur.local.yaml as the encrypted_profile field.
The encrypted profile is opaque — it cannot be decrypted without the tenant’s KMS key and correct AAD context. Even if someone copies your murmur.local.yaml, they cannot decrypt it without access to your tenant’s KMS infrastructure.
# .murmur/murmur.local.yaml
developer: jdoe
encrypted_profile: |
  eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTI1NkdDTSIsImVway...
  <base64-encoded KMS-encrypted blob>

Transport encryption

When an agent is spawned, the encrypted profile travels from your local config through the control plane to the agent VM:

Step 1: Control plane transport

The encrypted profile is transmitted to the control plane as an opaque byte array. It passes through the orchestration layer without modification — no intermediate system can decrypt the profile.

Step 2: Control worker re-sealing

Before the profile reaches the VM, the control worker re-seals it:
  1. The control worker retrieves the VM’s ephemeral X25519 public key (generated at VM boot).
  2. The original KMS-encrypted profile is decrypted within the control worker’s trusted environment.
  3. The decrypted credentials are immediately re-encrypted using NaCl box (Curve25519-XSalsa20-Poly1305) with the VM’s public key.
  4. The KMS-decrypted plaintext is zeroed from memory.
  5. The NaCl-sealed blob is sent to the VM.
This re-sealing step ensures that:
  • The profile can only be decrypted by the specific VM it was sealed for
  • Even if the sealed blob is intercepted in transit, it requires the VM’s private key to decrypt
  • The control worker holds plaintext only for the duration of the re-sealing operation

Step 3: Secure delivery

The NaCl-sealed blob is delivered to the VM through an authenticated API channel, not through a network filesystem or metadata service.

VM decryption

On the agent VM, credentials are decrypted in process memory only:
  1. Ephemeral key pair — at boot, the VM generates an X25519 key pair. The private key exists only in memory and is never written to disk.
  2. NaCl box open — the sealed blob is decrypted using the VM’s ephemeral private key and the control worker’s public key.
  3. In-memory storage — the decrypted credentials (API keys, tokens) are held in process memory for the agent session’s duration.
  4. No disk writes — credentials are never written to any file, environment file, or temporary storage. They are passed to Claude Code through in-memory channels.
  5. Destruction — when the agent session ends, the VM is destroyed. The ephemeral private key, decrypted credentials, and all process memory are gone.
VM boot

Generate ephemeral X25519 key pair (in memory)

Publish public key to control plane

Receive NaCl-sealed profile

Decrypt with private key (in memory)

Inject credentials into agent process (in memory)

Agent runs...

VM destroyed → keys and credentials gone

Per-tenant KMS keys

Each tenant has a dedicated Cloud KMS key used for all encryption operations within that tenant:
PurposeKey usage
Profile encryptionEncrypt developer credentials during murmur setup
Secret encryptionEncrypt tenant secrets stored in the catalog
AAD bindingBind encrypted data to the correct tenant context

Additional Authenticated Data (AAD)

Every KMS encryption operation includes AAD that binds the ciphertext to its intended context:
  • Tenant ID — prevents a profile from one tenant being used in another
  • Resource type — distinguishes profiles from secrets
  • Identity — for profiles, the developer’s identity is included
If any AAD field does not match during decryption, the operation fails. This means:
  • A profile encrypted for tenant A cannot be decrypted for tenant B
  • A developer’s profile cannot be used by a different developer
  • A secret cannot be confused with a profile

Session cookies

Dashboard sessions use ECIES (Elliptic Curve Integrated Encryption Scheme) with P-256:
  1. Key pair — the API server holds a P-256 key pair for cookie encryption.
  2. Encryption — when a session is created, the OAuth tokens and session metadata are encrypted using ECIES with the server’s public key.
  3. Cookie storage — the encrypted payload is stored in the browser cookie.
  4. Decryption — on each request, the API server decrypts the cookie with its private key to extract the session.
This ensures that:
  • OAuth tokens are never exposed to client-side JavaScript
  • Cookie contents cannot be read if intercepted (e.g., by browser extensions)
  • Session tampering is detected and rejected (ECIES provides authenticated encryption)

Tenant secrets

Secrets stored in the catalog (kind secret and user-secret) are encrypted at rest:

Encryption

# Setting a secret encrypts it with the tenant KMS key
murmur set secret npm-token --value "npm_abc123..."
  1. The secret value is sent to the API server over TLS.
  2. The API server encrypts the value using the tenant’s KMS key with appropriate AAD.
  3. The encrypted value is stored in GCS. The plaintext is never persisted.
  4. The plaintext_value field is write-only — it is accepted on set but never returned on get.

Decryption

Secrets are decrypted only when injected into an agent VM’s environment:
  1. The control worker determines which secrets the workspace requires (from secret_refs in the workspace config).
  2. Encrypted secret values are retrieved from the catalog.
  3. The control worker decrypts them using the tenant’s KMS key.
  4. Decrypted values are sealed with the VM’s ephemeral key (same NaCl box process as profiles).
  5. On the VM, they are decrypted in memory and set as environment variables (MURMUR_SECRET_*).

User secrets

User secrets (user-secret kind) work the same way but include the developer’s identity in the AAD. This means a user secret encrypted by developer A cannot be decrypted for developer B, even within the same tenant.

Commit signing

Agents sign their Git commits using ed25519 SSH signing keys:
  1. Key generation — during murmur setup, an ed25519 key pair is generated.
  2. Encryption — the private key is encrypted as part of your developer profile (KMS + NaCl box chain).
  3. On-VM usage — the signing key is decrypted in memory on the agent VM and configured in Git.
  4. Commit signatures — every commit made by the agent is signed with this key.
  5. Verification — GitHub can verify the signatures against the public key registered to your account.
This provides:
  • Provenance — every agent commit is cryptographically linked to the developer who spawned the agent
  • Tamper detection — modified commits will have invalid signatures
  • Accountability — the commit signature chain traces back to a real developer identity