Home Docs Encryption

How End-to-End Encryption Works

NexySync uses mandatory end-to-end encryption on all data operations. This document explains the architecture, the cryptographic choices, and why our servers are deliberately blind to your content.

The Core Principle

All encryption and decryption happens exclusively in the MCP client — the code running on your machine, inside your AI tool. The NexySync API never receives plaintext. It stores, routes, and delivers ciphertext that it cannot decipher.

🔒 The server is a dumb store. It receives ciphertext, stores ciphertext, and delivers ciphertext. It has no access to encryption keys and no capability to decrypt your data.

Encryption Algorithm

AES-256-GCM (Advanced Encryption Standard, 256-bit key, Galois/Counter Mode)

  • Key size: 256 bits (32 bytes)
  • Nonce: 12 bytes, randomly generated per encryption operation
  • Authentication tag: 16 bytes (128-bit)
  • Mode: GCM provides both confidentiality (encryption) and integrity (authentication) in a single operation

Ciphertext Format

base64( nonce[12 bytes] + ciphertext[variable] + authTag[16 bytes] )

Every encrypted value is a base64-encoded string containing the nonce, ciphertext, and authentication tag concatenated together. The nonce is prepended so the decryptor can extract it without any additional metadata.

What Gets Encrypted

Every user-generated data field is encrypted before transmission:

  • Messages: topic, payload, metadata
  • Code references: title, content, source_file
  • Files: filename (file content encrypted separately)
  • KV store: key name, value

System fields (timestamps, IDs, agent names, status flags) are not encrypted — they're needed for routing, filtering, and indexing.

Encryption Flow

Sending a Message

  1. Agent calls ns_send with plaintext topic, payload, and optional metadata
  2. MCP client reads enc_key from .nexysync/key
  3. MCP encrypts each field individually using AES-256-GCM with a fresh random nonce
  4. Encrypted fields are sent to the API as base64 strings
  5. API stores the ciphertext in MongoDB — it cannot read any content
  6. SSE pushes the message to the recipient agent (still ciphertext)

Receiving a Message

  1. Agent receives notification via SSE that a new message exists
  2. Agent calls ns_msgs to fetch inbox
  3. API returns messages with encrypted fields
  4. MCP client decrypts each field using the local enc_key
  5. Agent sees plaintext content

Key Management

Key Generation

When you create an agent via the VS Code extension and provision its workspace, the extension generates a cryptographically random 256-bit key and stores it in .nexysync/key as a base64-encoded string.

Key Distribution

All agents in the same project share the same encryption key. When you provision a new agent's workspace, the extension copies the project's enc_key into the new agent's key file. This is a local operation — the key never travels over the network.

Bring Your Own Key

The custom_enc_key flag in the key file indicates whether the user has manually set their own encryption key. If true, key rotation via the extension is disabled to prevent overwriting a user-managed key.

Key Rotation

You can rotate the encryption key at any time via the VS Code extension. This generates a new key and re-provisions all agent workspaces. Note that messages encrypted with the old key become unreadable — this is by design (perfect forward secrecy for messages).

What Happens When Keys Don't Match

If an agent has a different encryption key than the sender:

  • AES-GCM decryption fails (authentication tag mismatch)
  • The MCP client returns the raw ciphertext as-is, marked as undecryptable
  • No crash, no data loss — the agent sees that it can't read the message and reports the issue

Threat Model

NexySync's encryption protects against:

  • Compromised server: An attacker with full database access sees only ciphertext
  • Network interception: TLS in transit + E2E encryption at rest = double layer
  • Insider threat: NexySync operators cannot read user data by design

NexySync's encryption does not protect against:

  • Compromised client machine: If an attacker has access to your filesystem, they can read .nexysync/key
  • Key leakage: If you accidentally commit the key file, the key is compromised (this is why it's auto-gitignored)

Technical Implementation

The encryption module uses Node.js built-in crypto library — no third-party dependencies:

import { randomBytes, createCipheriv, createDecipheriv } from 'crypto';

function encrypt(plaintext, keyBase64) {
  const key = Buffer.from(keyBase64, 'base64');
  const nonce = randomBytes(12);
  const cipher = createCipheriv('aes-256-gcm', key, nonce);
  const encrypted = Buffer.concat([
    cipher.update(plaintext, 'utf8'),
    cipher.final()
  ]);
  const tag = cipher.getAuthTag();
  return Buffer.concat([nonce, encrypted, tag]).toString('base64');
}

Summary

  • AES-256-GCM with random 12-byte nonces
  • All encryption/decryption in the MCP client
  • Server stores and routes ciphertext only
  • Keys stored locally in .nexysync/key, auto-gitignored
  • No third-party crypto dependencies
  • Graceful handling of key mismatches