Trust and privacy
What is stored, what is not stored, what the relay can see, and where keys live.
Viewport's privacy claim is narrow. This page says exactly what is protected and what still requires trust.
The five invariants
- Live personal session transcripts are not persisted server-side. The daemon owns live session frames. Workflow runs are different: the platform stores run metadata and receipts, and only stores transcript/log/artifact content according to the run's data-capture policy.
- Team Context entries are HPKE-encrypted by a trusted edge. The platform stores ciphertext. The server API and database do not receive context plaintext.
- Relay frames are encrypted between the daemon and the active runtime endpoint. The relay sees envelopes (workspace, runtime target) but cannot decrypt payloads. In the hosted web app, the browser runtime is an endpoint for live session UX; the Viewport server is not.
- Per-org daemon identity prevents cross-tenant correlation. Each org binding has its own keypair + machineId; admins in org A cannot identify a machine as also belonging to org B.
- Trusted-edge plan bodies can be encrypted before save. Hook-created plan drafts use this path. Plaintext collaborative plans still exist, so plan mode matters.
Each invariant is implemented in code in the open-source daemon and relay.
What's stored, what isn't
| Object | Stored at rest? | Where? |
|---|---|---|
| Live personal session frames (prompts, tool calls, transcript) | No. | Daemon only, under ~/.viewport/. |
| Plaintext plans | Yes | Platform DB. They're normal collaborative artifacts. |
| Trusted-edge encrypted plan bodies | Ciphertext only | Platform DB stores the envelope and wrapped body-key grants. |
| Inbox items | Yes | Platform DB. They're decision queues. |
| Team Context entries | Ciphertext only. | Platform DB. Keys never sent. |
| Team Context candidates (proposed) | Ciphertext only. | Same. |
| User epoch recovery backups | Ciphertext only | Platform DB stores KDF parameters and an encrypted backup envelope. The recovery key is never sent. |
| Workflow definitions | Yes | Platform DB + mirrored to repo files. |
| Workflow run records and receipts | Yes | Platform DB. Includes route, policy, approval, worker, usage, and provider-action evidence. |
| Workflow run transcript excerpts | Policy-controlled | Default is none. If the workflow/run policy explicitly enables excerpts, selected assistant/user excerpts can be stored for replay. |
| Workflow run logs and artifact paths | Policy-controlled | Default is metadata-only. Content or local artifact references require explicit policy and are redacted for known secrets before storage. |
| Audit events | Yes | Platform DB. That's the point. |
| Daemon identity keypair | Local only | ~/.viewport/relay-identities/{workspaceId}.json, mode 0o600. |
| Per-binding install/runtime/machine ids | Yes (per org) | Platform DB. Different per org. |
| Relay frame payloads | No. | In-flight only. Lost on relay restart. |
| Pairing codes | Yes (until consumed or expired) | Short-lived, ULID, expires in 15 min. |
| API tokens | Hashed | Argon2 hash; raw token shown once on creation. |
| Pre-shared keys (PSK) for pair-time auth | Yes | Hashed. |
The daemon ↔ relay path
- Handshake: Noise IK or IKpsk2 (selected per workspace).
- Session crypto: AES-256-GCM with per-direction nonces.
- Envelope: workspace id, runtime target id, frame type. Visible to relay for routing.
- Payload: opaque ciphertext. Relay cannot read.
Conformance vectors for replay-testing the handshake: packages/daemon/docs/relay-noise-v3-conformance-vectors.json. Run npm run test:conformance in the daemon repo to replay them.
What "client decrypts" means
There are two different trust models:
- Team Context content decrypts on the trusted edge: the local daemon or a remote daemon reached through the encrypted command channel. Pairing only connects a daemon; device enrollment is what makes it decrypt-ready.
- Trusted-edge plan bodies decrypt through a trusted edge when the plan has an encrypted body envelope and the viewer has a valid user/team epoch grant.
- Recovery backups decrypt only on a daemon after the user enters their recovery key. The platform stores an encrypted backup blob and cannot recover the key for you.
- Plaintext plans are normal collaborative artifacts. The platform can read them.
- Live session payloads may decrypt in the active runtime endpoint so the user can view and approve a running session. If that endpoint is the hosted web app, the plaintext exists in the user's browser memory, not in the platform database.
That distinction matters. Browser-side decryption protects against database leaks, relay operators, backend logs, and server-side reads. It does not mean the user has zero trust in the web app code they loaded. A malicious or compromised web build could try to exfiltrate browser-visible plaintext. For the strongest model, keep highly sensitive decryption on local/approved edge clients and treat hosted-browser plaintext as a live UX surface, not a durable secret store.
For remote machines, the browser should not call a daemon's public network port directly for decrypt operations. The supported model is an outbound daemon connection plus scoped, short-lived command capabilities over the encrypted relay channel. A user unlocks a trusted edge for the web session with vpd unlock <id>, and the capability is bound to the runtime target that activated that unlock.
Auto-unlock is an explicit convenience layer for trusted machines. If you opt a machine into auto-unlock, the hosted app can create a short-lived unlock session for that online machine without asking you to paste the command each time. This stores trust-policy metadata and expiry state on the platform; it does not give the platform decrypt keys or plaintext. Turn it off for machines that are shared, unattended, or outside your trust boundary.
Workflow data capture
Declarative workflow runs have a separate data-capture policy from live personal session monitoring. The launch default is privacy-first:
{
"transcripts": "none",
"logs": "metadata",
"artifacts": "metadata"
}That means the platform still stores the run ledger: route, policy hash, approval decisions, worker claim/cleanup state, usage/cost metadata when available, provider receipts, denial codes, and redacted failure summaries. It does not store transcript excerpts, raw node log chunks, or local artifact paths unless the policy explicitly allows that category.
When content capture is enabled, the runtime and API still apply redaction before platform storage. Known token-like values, lease/claim material, provider credentials, runtime secret env/file metadata, context node bodies, and context receipt raw bodies are removed or replaced with metadata receipts. Treat any raw secret appearing in replay, logs, proof files, or support packets as a security bug.
Current launch proof covers the defaults and redaction behavior. Formal enterprise retention windows, legal deletion/export controls, SIEM streaming, and data residency commitments are not part of the early-partner launch posture.
Data residency
The early-partner hosted path does not include a contractual data-residency
commitment. A self-hosted vpd worker keeps agent execution, local tools, local
model keys, and worktree files on your infrastructure. A self-hosted relay keeps
encrypted in-flight session frames on your network. Neither one moves the
hosted control-plane database into your region.
For hosted Viewport, expect the platform to store control-plane data described above: workspace/team records, workflow definitions, route/policy sync state, run ledgers, audit events, provider receipts, encrypted context vault envelopes, and any workflow-capture content explicitly allowed by policy.
If you need legal data residency, customer-managed storage, or a fully self-hosted control plane, treat that as an enterprise/pilot requirement before rolling out sensitive workflows.
What the relay sees
The relay is operationally stateless. Per-process state only:
- In-memory connection registry (workspace → connections).
- IP-level rate limit counters.
- Recent log buffer for
/logsadmin endpoint. - Prometheus metrics counters.
All of this is lost on relay restart. No payloads are persisted. The relay can identify the envelope of every frame. Which workspace, which runtime target. But not the content.
If you self-host the relay, the wire path stays in your network. You control TLS, rotation, and any IP allow-listing. See Self-host: Security posture.
What the control plane sees
The hosted server API and web app see:
- Plaintext: members, teams, machine metadata (name, OS, last seen), workflow definitions, plaintext plans, plan metadata, inbox items, audit events, run records, pairings, settings, integrations.
- Ciphertext only: context vault entries, context candidates, trusted-edge encrypted plan bodies, encrypted plan feedback bodies.
- Never: live personal session frames (no table), context plaintext, trusted-edge plan raw body keys.
Credential authority classes
Do not treat Viewport setup as one broad token. A production workflow should separate four credential classes:
| Class | Default authority | Where raw material should live |
|---|---|---|
| Runner credential | Claim a run, stream evidence, emit artifacts/proposals/context candidates, complete or fail. | Viewport stores a hashed runner credential. It cannot clone repos or mutate providers. |
| Repo checkout/write credential | Clone/read repos and optionally push branches for the assigned run/repo set. | Self-hosted runners can keep raw material local. Viewport-managed materialization is run-scoped. |
| Provider side-effect credential | Comment, open PR metadata, update status, post Slack, or mutate provider records after approval. | Viewport broker, scoped by provider install and credential binding, with idempotent receipt. |
| Agent/MCP/API secret | Model keys, package registries, MCP servers, cloud APIs, and internal tools selected by workflow/profile policy. | Runner-local where possible; otherwise run-scoped materialization with redaction and audit. |
The target BYO runner posture is stronger than the current run-scoped materialization path:
runner or runner pool registers public key / customer KMS reference
-> customer creates credential binding
-> Viewport stores ciphertext envelope plus policy metadata
-> authorized run requests handle
-> runner receives ciphertext envelope
-> runner decrypts locally
-> Viewport records delivery/unwrap metadata, not raw secret valuesUntil that public-key or customer-KMS envelope path is implemented, describe the current server-managed mode as run-scoped materialization, not zero-knowledge secret custody. Runner-local bindings remain metadata-only to Viewport.
In a worst-case scenario where the platform is compromised:
- The attacker can read members, teams, workflow definitions, plaintext plans, plan metadata, inbox items, audit history.
- The attacker cannot read context vault content. Decryption requires private epoch material held only on enrolled devices that have materialized the relevant user/team grant.
- The attacker cannot read trusted-edge encrypted plan bodies or raw plan body keys. They can still read surrounding metadata and any plans saved in plaintext mode.
- The attacker cannot use a stored recovery backup without the user-held recovery key. If the recovery key is stolen, it should be treated like a stolen enrolled device.
- The attacker cannot read live personal session frames from the platform database. There's no table to read from. Workflow run evidence follows the run's data-capture policy described above.
- The attacker can revoke pairings (effectively a DoS). The attacker cannot impersonate a daemon to a relay without the daemon's private key.
The cross-tenant story
Each tenant (workspace) is isolated through:
- Workspace scope at the data layer. Every tenant-owned row carries
workspace_id. Server reads and writes are scoped to the active workspace, and tests cover the common leak paths. - Per-org daemon identity. Different
machineId, different keypair, differentinstallId. A machine in org A is cryptographically indistinguishable from any other org A machine when viewed from org A's data, and is invisible from org B. - Workspace-scoped teams and share groups. A team or share group from org A cannot grant access to an org B resource. Enforced at write time (ACL entry validation) and read time (the
ResourceAccessservice double-checks). - Audit logs are tenant-scoped. Cross-org queries return nothing for non-Viewport-staff actors.
What's not yet enforced
- Schema-per-tenant or DB-per-tenant isolation. Single shared DB with row-level scope. Sufficient for SMB and mid-market. Some enterprise compliance contexts require harder isolation.
- HSM-backed crypto. Daemon keys are file-based with
0o600perms. HSM/TPM-backed signing is not available yet. - Customer-managed encryption keys (CMEK). Context vault keys are managed on trusted edges today. Bringing your own root key to wrap them is not available yet.
- Air-gapped operation. The daemon needs to reach the relay. Fully offline operation isn't yet supported.
How to verify the claims yourself
- Daemon is open source: github.com/viewportai/viewport/tree/main/packages/daemon. Read
src/server/for the relay bridge,src/core/for identity,src/session-manager.tsfor what gets emitted. - Relay is open source: github.com/viewportai/viewport/tree/main/services/relay. Read
relay-frame-validation.tsfor what's accepted,relay-state.tsfor what's stored in memory. - Wire protocol is documented:
packages/daemon/src/server/ws-protocol.tsis the source of truth for frame types. - Conformance vectors: run
npm run test:conformanceagainst the daemon to prove the handshake matches spec. - Session relay decryption: Security explained: Session relay decryption explains how the browser derives its temporary relay session key.
Reporting a vulnerability
We run a coordinated disclosure program. Email security@getviewport.com with details, expect a reply within 48 hours, and 90-day public disclosure unless we agree on a longer timeline. See Security policy.
Where to go next
- Security. Diagrams for context encryption, review, sharing, and revocation.
- Security explained: Session relay decryption. Where the browser's temporary decrypt key comes from.
- Self-host: Security posture. What self-hosting the relay changes.
- Concepts: Machines and pairing. The per-org identity story.
- Concepts: Team Context. The encryption details.
- Audit log. What's recorded.