> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sovseal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Zero-Knowledge Guarantees: What the Server Can and Cannot See

> sovseal's replication server is permanently blind to plaintext. The formal threat model, what actually reaches the server (no path hashing, no content-hash chain), dual verification, and fail-closed behavior.

sovseal is architected on a zero-knowledge security model: cryptographic keys and plaintext payloads never cross the local device boundary. The replication endpoint — whether the managed platform or a self-hosted node — acts purely as an opaque ciphertext store. This is not a policy; it is a mathematical constraint enforced by client-side encryption. The server is structurally incapable of reading your data.

***

## What the server sees vs. cannot see

```text theme={null}
                  ┌─────────────────────────────────┐
                  │  Replication Server's View      │
                  ├─────────────────────────────────┤
SEES         ►    │  • AES-256-GCM ciphertext bytes │
                  │  • client_payload_hash (SHA-256)│
                  │  • agent_id, sequence_number    │
                  │  • byte size, timestamp         │
                  ├─────────────────────────────────┤
CANNOT SEE   ►    │  • plaintext content            │
                  │  • the fact's semantic meaning  │
                  │  • embedding vector             │
                  │  • the encryption key           │
                  └─────────────────────────────────┘
```

## Formal threat model — four attacker profiles

### 1. Passive network observer (MITM)

* **Attacker goal.** Intercept sync packets on the public network to read agent memory.
* **Mitigation.** All replication traffic runs over HTTPS. Even if TLS is terminated or compromised, the observer only sees AES-256-GCM ciphertext bytes and non-secret metadata (`agent_id`, `sequence_number`, `client_payload_hash`) — nothing recoverable without the client key.

### 2. Malicious or compromised replication server

* **Attacker goal.** Read stored memories or inject false state to poison the agent's context.
* **Mitigation.** The server does not hold the decryption keys. Payload integrity and chronological substitution are both closed by [Verified Semantic Recall (VSR)](/platform/core-concepts/verified-semantic-recall) — a check you run on restore, not one the SDK runs for you (see "Fail-closed behavior" below).

### 3. Local host machine compromise

* **Attacker goal.** Extract encryption keys and cached database records directly from the client device.
* **Mitigation.** The master key lives in the OS keychain (not a plaintext file), and memory text is encrypted at rest in local LanceDB under an HKDF-derived `k_rest`. A stolen disk or cold backup yields ciphertext, not memories. A *fully* compromised live host with root or code-execution access as your user can still read the running agent's process memory or unlock the OS keychain. Zero-knowledge protects transit and storage — it cannot protect a live, fully-owned device.

### 4. Wholesale ciphertext substitution

* **Attacker goal.** Swap a valid ciphertext record with a different valid ciphertext from an older write to replay stale state.
* **Mitigation.** `client_payload_hash` — `sha256(canonicalize(payload))` — covers the entire payload, including its `sequence_number` and `parent_snapshot`, so a substituted (older or different) snapshot's re-derived hash will not match the one issued at its original write. This is combined with the server's strict `sequence_number` enforcement (must equal `latest confirmed + 1`, or `409 sequence_gap`) — see [Deterministic Lineage](/platform/core-concepts/deterministic-lineage) for the full ordering model. Neither check runs automatically; you implement the hash comparison on restore (below).

***

## What actually reaches the server

Semantic memory (`store`/`recall`) never leaves the device at all — there's no replication step for it. For state replication (`snapshot`/`restore`/`lineage`), the server receives exactly:

* **AES-256-GCM ciphertext** — the encrypted `active_context`.
* **`client_payload_hash`** — a SHA-256 integrity anchor over the whole payload, used for idempotency and as the tamper/substitution check's comparison target.
* **`agent_id` and `sequence_number`** — used for auth scoping and ordering. `agent_id` is a value you choose (a common convention is `sha256(project_id + ":" + some_stable_identifier)`, but it's not a mandated derivation — see [Authentication](/api-reference/authentication)).

There is no path-based addressing anywhere in the system — no `path_hash`, no per-key hashing scheme. Records are flat content strings (semantic memory) or `agent_id`-scoped sequences (state replication); see [Memory Model](/platform/core-concepts/memory-model) for the full record shapes.

## Dual verification strategy

sovseal uses two complementary cryptographic primitives on every restore, each closing a different attack surface:

| Cryptographic primitive                 | Verification level  | Purpose                                                                                                                                                                                  |
| --------------------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **AES-256-GCM Auth Tag (128-bit)**      | Payload integrity   | Verifies the ciphertext has not been modified, truncated, or corrupted in transit. `decryptJson` throws automatically on a tag mismatch.                                                 |
| **`client_payload_hash` re-derivation** | Lineage consistency | Verifies the returned snapshot matches the exact record expected — not a valid-but-wrong-point-in-time substitute. **Not automatic** — you re-derive and compare it yourself; see below. |

***

## Key custody

Your keys never leave your device. The table below documents where each piece of key material lives and who can access it:

| Property              | Location / Boundary                                                     | Access control                                                                                                                                                             |
| --------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Master Key**        | Client device — OS keychain (Keychain / Credential Manager / libsecret) | Held by the platform credential store. Subkeys (`k_rest`, `k_sync`) derived via HKDF, non-extractable. Opt-in `0600` file fallback only under `SOVSEAL_KEY_FALLBACK=file`. |
| **Plaintext Memory**  | Client RAM only                                                         | Memory text is encrypted **at rest** in local LanceDB under `k_rest`; decrypted only inside active local agent processes.                                                  |
| **Ciphertext Memory** | Sync gateway (Supabase + Object Bucket)                                 | Opaque bytes, unreadable without the client key.                                                                                                                           |
| **Auth Tokens**       | Sync gateway / environment variables                                    | Bearer API token (`sov_proj_<uuid v4>` or `sov_live_*`).                                                                                                                   |

***

## Fail-closed behavior

<Warning>
  **The VSR check is not automatic.** `decryptJson` throwing on an auth-tag mismatch is automatic. Re-deriving `client_payload_hash` and comparing it is a pattern **you** implement — there is no `VsrFailureError` class the SDK raises for you. This is deliberate: your incident response is yours to own.
</Warning>

```typescript theme={null}
import {
  AgentStateClient,
  CryptoService,
  canonicalize,
  decryptJson,
} from "@sovseal/sdk";

const client = new AgentStateClient({
  endpoint: process.env.SOVSEAL_ENDPOINT!,
  apiKey: process.env.SOVSEAL_API_KEY!,
});

try {
  const { receipt, ciphertextUrl } = await client.restore({ agentId });
  const ciphertext = await fetch(ciphertextUrl).then((r) => r.text());

  // Throws if the AES-256-GCM auth tag fails — tampered or truncated bytes.
  const state = await decryptJson(ciphertext, key);

  // Re-derive the VSR anchor and compare before trusting the payload.
  const expected = await CryptoService.sha256Hex(
    new TextEncoder().encode(canonicalize(state)),
  );

  if (expected !== receipt.client_payload_hash) {
    // Fail closed — valid ciphertext, wrong lineage. Do not hand it to the agent.
    alertOncall({ agentId, expected, got: receipt.client_payload_hash });
    return;
  }

  useConfiguration(state);
} catch (err) {
  // Decrypt failure or transport error. Never fall back to partial state.
  alertOncall({ agentId, err });
  return;
}
```

See [Verified Semantic Recall](/platform/core-concepts/verified-semantic-recall) for the full pattern and why it's structured this way.

***

## Technical limitations

<Note>
  Zero-knowledge is a strong guarantee, but it does not defend against every condition. Understand these boundaries before deploying in high-assurance environments:

  * **Passphrase entropy.** If you configure key derivation from a weak or guessable passphrase, the derived AES-256 key is vulnerable to offline brute-force attacks. Use high-entropy secrets.
  * **Metadata traffic analysis.** A server-side observer can still analyze request frequency, sync volume, packet timings, and total ciphertext size to infer general activity levels — even without reading content.
  * **Device loss.** Losing your keychain master key (or, under `SOVSEAL_KEY_FALLBACK=file`, the fallback key file) without a backup makes remote snapshots permanently unrecoverable on the Hobby/Starter tiers and the local/MCP tier. Growth, Pro, and Enterprise plans include opt-in Managed Key Recovery — see [Account & Device Security](/security/account-security) for the plan-by-plan breakdown.
</Note>

***

## Next steps

<CardGroup cols={2}>
  <Card title="Verified Semantic Recall" icon="shield" href="/platform/core-concepts/verified-semantic-recall">
    The full two-check pattern and a ready-to-use implementation.
  </Card>

  <Card title="Cryptographic Trust Center" icon="shield-halved" href="/platform/trust">
    Consolidated threat model, honest compliance posture, and the unforgiving key-recovery boundary.
  </Card>

  <Card title="Deterministic Lineage" icon="timeline" href="/platform/core-concepts/deterministic-lineage">
    How sequence numbers make substitution structurally detectable.
  </Card>

  <Card title="Memory Model" icon="layer-group" href="/platform/core-concepts/memory-model">
    The full record schema — which fields replicate and which stay local.
  </Card>
</CardGroup>
