Access Control
AES-256-GCM wallet-derived encryption enforces access cryptographically — no server policy, no override key.
How access works
MNEMOS does not have an access control list or server-side permission model. Access to a memory is equivalent to possessing the AES-256-GCM key — and that key is only derivable by signing with your wallet's private key.
The server stores only ciphertext. It is structurally incapable of decrypting your memories because the key is never transmitted or stored anywhere outside your browser session.
- ✓The wallet that signed the encryption key
- ✓Anyone you share a vault with (shared vault members)
- ✓MNEMOS servers
- ✓Database administrators
- ✓Other wallets
- ✓Anyone without your private key signature
Key derivation
The encryption key is derived once per session when you sign the fixed domain-separation message. The same wallet always derives the same key — deterministic but non-extractable.
Fixed signing message (SIGN_MESSAGE constant):
"MNEMOS_ENCRYPTION_KEY_v1
Signing this message derives your personal encryption key.
It does not create a transaction or cost any gas."
Derivation steps:
1. signature = wallet.signMessage(SIGN_MESSAGE)
2. hex → Uint8Array(sigBytes)
3. keyMaterial = await crypto.subtle.digest("SHA-256", sigBytes)
4. cryptoKey = await crypto.subtle.importKey(
"raw", keyMaterial, { name: "AES-GCM", length: 256 },
false, // non-extractable
["encrypt", "decrypt"]
)non-extractable — once imported into WebCrypto it cannot be read back out of the browser, even by JavaScript in the same tab.Memory sources and encryption
The source field determines how a memory's access is controlled:
| Source | Encrypted | Access model |
|---|---|---|
| vault | Yes — AES-256-GCM (wallet key) | Wallet signature required to decrypt |
| api-plain | No — plaintext in Neon Postgres | Bearer API key |
| mcp | No — temporary session cache only | Active AI Vault Bridge session (60 min TTL) |
api-plain source). It is stored as readable plaintext — use it only for non-sensitive external data.Shared vaults
Shared vaults use ECDH key exchange so multiple wallets can read the same encrypted memories without any member's private key being shared.
Shared vault key exchange:
1. Vault owner generates a random symmetric vault key (AES-GCM, 256-bit)
2. Owner encrypts vault key for each invitee using ECDH:
- Owner's vault key is wrapped with AES-GCM(ECDH shared secret)
- Invitee registers their P-256 ECDH public key
- Result: wrappedVaultKey + ephemeralPubkey stored per member
3. On accept, invitee derives ECDH shared secret and unwraps vault key
4. Shared memories are encrypted with the vault key (not wallet key)
5. All members can decrypt — none see each other's wallet keysRevoking MCP access
From the vault UI
Navigate to API Gateway → AI Vault Bridge and click Revoke. Clears the session cache immediately — Claude loses access instantly.
Via API
const timestamp = Date.now()
const message = `mnemos:revoke-session:${walletAddress}:${timestamp}`
const signature = await wallet.signMessage(message)
await fetch("/api/vault/session", {
method: "DELETE",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ walletAddress, timestamp, signature }),
})API key security
API keys grant read/write access to api-plain memories and the MCP session cache. They do not grant access to wallet-encrypted memories.
- →Never commit API keys to source control — use environment variables
- →MNEMOS stores only the SHA-256 hash — the raw key is shown once at generation
- →Rotate immediately if you suspect exposure — go to API Gateway → Generate new key