# One Track Privacy & Security

Your tasks are encrypted on your device with keys we never hold. Authorization is enforced by signatures, not database flags. This page tells you exactly what our servers can and cannot see.

## The Trust Boundary

Every task and comment is encrypted client-side before upload. What crosses the wire is ciphertext, signatures, and sealed keys. The server's job is not to read your data — it's to verify it.

### Your devices — The Plaintext Zone

- Tasks, comments, tags, and grant rules are readable here — and only here.
- Keys are generated on-device; secrets live in a vault sealed under your passphrase.
- All encryption and signing happens before anything leaves.

What crosses the wire to our servers: ciphertext, signatures, and sealed keys. What comes back: the verified log.

### Our servers — The Ciphertext Zone

- Every operation arrives cryptographically signed. We check the signature, the author's membership, and the author's capability chain before accepting a single byte into the log.
- We store ciphertext, sealed keys, and the signed operation log. We hold no content keys.

### The Publish Bridge

The one labeled gate out of the encryption boundary. Sharing a track beyond its encrypted membership is a per-track, explicit act. It never happens as a side effect.

The second deliberate exception is metadata: like every E2EE system, we see the shape of your activity even though we can't see its content. We enumerate exactly what below, instead of hoping you won't ask.

## What Our Servers Can and Cannot See

### Cannot See

- Task and comment content
- Any content-encryption key — DEKs or track KEKs
- Your identity's secret keys — the vault is sealed with a key derived from your passphrase
- Which repository or issue an automation watches — hidden behind an HMAC
- The rule defining what an agent's grant covers

### Can See

- Track IDs, member public keys, and roles — the membership graph
- Object counts, version counts, sizes, and timestamps
- Which members and agents hold keys to which objects — but never the keys themselves
- The signed operation log itself: who committed, when, and how much
- Which item IDs an agent's grant was materialized onto

That "Can See" column is our honest metadata disclosure. If your threat model requires hiding the membership graph itself, we're not there yet — and we'd rather tell you that here than in your pentest report.

## The Cryptography

Every AEAD invocation carries associated data pinning the ciphertext to its exact place in the system — a sealed key cannot be replayed across tracks, recipients, epochs, or purposes, because the AAD won't match.

| Area | Details |
| --- | --- |
| Content encryption | AES-256-GCM · fresh random 256-bit key per item version · random 96-bit nonces · associated data binds every ciphertext to its track, item, version, and key epoch |
| Signatures | Ed25519 with strict verification · malleable and mixed-order-point signatures rejected |
| Key sealing to members | ECIES: ephemeral X25519 → HKDF-SHA256 (domain-separated, bound to both public keys) → AES-256-GCM · contributory-behavior check on the shared secret |
| Identity vault (passphrase → key) | Argon2id · 64 MiB memory / 3 iterations · parameters frozen into the vault format |
| Hashing & integrity | SHA-256 · content-addressed ciphertext blobs, integrity verified on upload |
| Canonical encoding | Deterministic CBOR (RFC 8949 §4.2.1) for every signed or hashed structure — no signature ambiguity |

### The Key Hierarchy

1. **Identity keys** — Ed25519 + X25519, per user. Generated on-device. Secrets live in a vault encrypted under an Argon2id-derived key; the server stores the vault but cannot open it.
2. ↓ seals
3. **Track keys (KEKs)** — 256-bit, per track per epoch. Sealed individually to each human member's sealing key. Removing a member bumps the epoch and re-seals in the same operation — no lazy rotation.
4. ↓ wraps
5. **Content keys (DEKs)** — fresh per item version. A new random key for every version of every item, wrapped under the current track key — and sealed item-by-item to granted agents.
6. ↓ encrypts
7. **Your content** — AES-256-GCM ciphertext. The only form in which tasks and comments ever reach our servers.

## Who Can Decrypt What

An edge is a key you hold. A missing edge is ciphertext you can't read. Three tracks, three humans, one agent — trace any path yourself.

Member devices are the only place plaintext and unsealed keys exist; our servers hold sealed keys and ciphertext only.

The example ensemble:

- **deploy-bot** (service): own keypair · no KEK, ever
- **Alice** (admin): Ed25519 sign · X25519 seal
- **Bob** (member): Ed25519 sign · X25519 seal
- **Charlie** (member): Ed25519 sign · X25519 seal

Track keys on the server:

- **Launch — track KEK**: sealed to Alice + Bob
- **Compliance — track KEK**: sealed to Bob + Charlie
- **Alice / Private — KEK**: sealed to Alice alone

Items on the server:

- **Launch · task 2**: DEK2 wrapped by KEK · also sealed to deploy-bot
- **Launch · task 1**: DEK1 wrapped by Launch KEK
- **Compliance · task**: DEK3 wrapped by Compliance KEK
- **Private · task**: DEK4 wrapped by Private KEK

How access works: a member unseals a KEK (X25519 → HKDF → AES-GCM), then unwraps the DEK. An agent gets a per-item, per-version DEK grant only. A solid edge is a key you hold; a per-item grant is a narrower edge; no line means ciphertext you can't read.

- Charlie holds no edge into Launch — to him it's ciphertext.
- Bob holds no edge into Alice / Private.
- deploy-bot reaches one task — never a track key.

## Built for Agents — On Your Terms

For teams already deploying AI agents against real systems. You choose how much an agent sees — a full seat beside you or a single task — and either way, revoking it is one operation, not a key-rotation ceremony.

### A full seat — Design and Build With You

Through the CLI, an agent can hold the same read and write access a member has over their tracks in the browser. Members can fully leverage their agents. The org's granular RBAC defines which tracks the member and their agents work in.

### A single task — Scoped Down by Grant

Or, give agents fine permissions. A designated keypair, specific operations on specific items, read/write or read-only access. Content keys are sealed item by item, and the server rejects any commit that under- or over-shares them.

### Admin control — Your Org, Your Standards

Org admins set the ceiling: disable CLI access entirely, configure granular RBAC per track, and layer enterprise controls like browser automation allowlists to meet your compliance bar. Revocation stays one op, no key rotation.

### Every Chain Ends at a Human

**Human admin** (full track roles, self-issued root) → delegates → **Agent** (one grant, listed items, expiring capability).

Capability tokens can only narrow or stay the same at each hop — never widen — and are verified server-side on every operation. The root must be signed by a human — agent authority is always auditable back to a person.

## Two Ways Aboard

A human member and a service agent join by different doors. One receives the track key; the other never does — follow either protocol step by step.

### Adding a Human

`member.add.v1` · Dana joins, sealed the track key

| Step | What happens |
| --- | --- |
| Dana → Dana | Generates her Ed25519 + X25519 identity on her own device. |
| Dana → Server | Stores a passphrase-encrypted key vault — opaque to us. |
| Alice → Alice | Unseals the current KEK (epoch n) and seals it to Dana's public key. Older epochs are optional — including them is the explicit "does she get pre-join history?" decision. |
| Alice → Server | Signed commit: member.add — roster row, sealed KEKs, her capability. |
| Server checks | Envelope signature · Alice is an active admin · the capability chain roots and only narrows · Dana's current-epoch KEK is present, no future epochs · state-root compare-and-swap. |
| Dana → Server | Signs an HMAC challenge with her Ed25519 key → a 24-hour session token, then fetches her sealed KEKs and the encrypted objects. |
| Dana → Dana | Unseals the KEK → unwraps DEKs → reads the track. Plaintext exists only here. |

### Granting an Agent

`grant.create.v1` · deploy-bot gets in — no KEK, ever

| Step | What happens |
| --- | --- |
| Alice → Server | Signed commit: grant.create — the bot's public key, allowed op types, a read flag. The grant's selection rule stays encrypted; we never learn what it covers. |
| Alice → Bot | Delegates a capability scoped to the grant — chained from her admin capability, attenuate-only, 1-day TTL. |
| Server rule | From now on, any commit touching granted items must seal a DEK to the bot — and to no one extra. Under- or over-sharing is rejected. |
| Alice → Server | Her next write on a granted item: fresh DEK, wrapped by the KEK and sealed to the bot. |
| Bot → Server | Challenge/response → session token; fetches the item and its sealed DEK. |
| Bot → Bot | Unseals the DEK → decrypts that one item. It has no path to anything else. |
| Bot → Server | Writes back: encrypts under a fresh DEK, seals it to every active human — it holds no KEK to wrap with. The server verifies the capability chain, grant liveness, op-type scope, and that the sealed-DEK set is complete. |
| Alice → Server | Revocation: one grant.revoke commit. The bot's next request fails the liveness re-check — instant cutoff, no key rotation. |

### Removal Is the Mirror

Removing a human advances the track an epoch: a brand-new KEK is sealed to every remaining member, and the server verifies that re-seal batch is complete before accepting the removal — the leaver reads nothing written afterward. Removing an agent rotates nothing, because it never held the key.

## The Platform

A small, memory-safe surface served from EU infrastructure — the API, the crypto core, and the browser client share one memory-safe codebase.

- **No Data Processors, No Cookies** — No third-party data processors touch your data, and we set no cookies — no analytics, no trackers. Compliance reviews are fast and simple.
- **Small, Contained API** — One compact service, a hard 4 MiB request cap, per-uploader quotas with garbage collection, and content-addressed blobs verified on upload. Unauthorized blob reads return 404 — never confirming existence.
- **Guarded Egress** — Outbound webhooks pass an SSRF filter: HTTPS only, with loopback, private, link-local, CGNAT, and reserved ranges blocked across IPv4, IPv6, and IPv4-mapped forms — at registration and at send time.
- **Strict Browser Policy** — A Content-Security-Policy whose script allowlist is 'self' plus SHA-256 hashes of the exact shipped assets — no unsafe-inline, no unsafe-eval — alongside HSTS, nosniff, denied framing, and a strict referrer policy.
- **Supply Chain Analysis in CI** — Every change is checked against a security advisory database in CI, with strict lints (warnings denied) and the full test suite.
- **Memory-Safe, Top to Bottom** — A memory-safe language everywhere — the browser client compiles to WebAssembly from the same codebase. The class of memory-corruption CVEs behind most infrastructure exploits is off the table.

## What We Don't Claim

One Track is a project-management tool, not a dedicated security product — here is the honest ledger on the privacy and security claims above, current as of July 2026.

- **No third-party audit or certification yet.** No SOC 2, no ISO 27001, no external cryptographic review, and we do not sign BAAs. If you need those today, we're not ready for you yet — talk to us about timelines.
- **Metadata is visible.** Membership graphs, activity timing, and object counts are not hidden from us — see the disclosure table above.
- **Rotation is forward-only.** Member removal protects the future, not the past.
- **Found something?** See [/.well-known/security.txt](/.well-known/security.txt). We answer researchers.

[Talk to us about timelines](mailto:htn@dominic.computer)
