Source: https://docs.any.org/operations/security-model.html # Security model There are two boundaries. The HTTP socket is **localhost-only and currently has no per-caller authentication** — proper auth and access capabilities are planned — so anyone who can run a process on the machine can call it. The data is **end-to-end encrypted before it syncs**: sync nodes, coordinator, file nodes and the push node relay ciphertext they cannot read. Neither boundary covers the disk or outside providers — the data dir is not encrypted at rest, and an online embedder reads the text it embeds. Understanding which boundary protects what is most of operating `any` safely. ## The socket: loopback, no auth - The server binds `127.0.0.1` (or another loopback address) and refuses anything else with a clear error. There is no TLS, no auth token, no rate limiting on the API. - The trust model is the operating-system user: a local process that can open a TCP connection to the port has the same power as the CLI. That is the same trust a local database socket or a browser's local profile directory has. - Lifecycle is gated by **ownership, not authentication**: a standalone server refuses `POST /v1/shutdown`, `DELETE /v1/auth` and account switches outright (`403`), and a managed server accepts them only with the control token its host holds — so another local process cannot log it into a different account or sign it out over HTTP. Lifetime stays uid-bounded: any same-user process can still `any stop` or `kill` a server, token or not. Everything else on the socket stays open to any local process. > **Why it matters.** Because the server never listens off-host, the whole remote attack surface is the any-sync protocol, which carries ciphertext and signed ACL records. ## CORS: a fixed allowlist, not a hole Browsers enforce CORS on top of the socket. The server allows exactly the origins the bundled desktop-shell webview runs at: | Origin | Why | | --- | --- | | `tauri://localhost` | the desktop app's webview on macOS / Linux | | `http://tauri.localhost` | the same on Windows | | `http://localhost:5173`, `http://127.0.0.1:5173` | the desktop app's dev server | Custom schemes are unclaimable by web content and `.localhost` is pinned to loopback, so no remote web page can present these origins. Allowed headers are `Content-Type`, `Accept`, `Range` (ranged file downloads) and `X-Any-Control-Token` (the webview logging in a managed server). Requests without an `Origin` header — curl, the CLI, same-origin — are unaffected. The allowlist does not widen the trust model: local processes were never gated by CORS in the first place. ## The data: end-to-end encryption - Every space's content is encrypted with keys derived from the space's ACL; members receive the read key through signed ACL records. Sync and file nodes store and relay ciphertext only. - Identity is a keypair. The account key is derived from the mnemonic; each device holds its own device key. Membership, roles and invites are signed ACL records, so a node cannot grant itself access ([ACL](https://docs.any.org/collaboration/acl.md.txt)). - Profiles pushed to the identity directory are encrypted too — a contact's name resolves only once their key arrives through a shared space or a direct-space invite ([Identities](https://docs.any.org/auth/identities.md.txt)). - Push notifications are encrypted by the sender with keys derived from ACL state; the push node sees topics, not content ([Push](https://docs.any.org/notifications/push.md.txt)). - Files are encrypted as UnixFS DAGs before leaving the device ([Files](https://docs.any.org/files/index.md.txt)). - Search indexing is outside this boundary: with the default `index.embedder: auto` the text of indexed documents and search queries goes to the online embedding provider; `local` keeps it on the device ([Embedders](https://docs.any.org/search/embedders.md.txt)). What the network can observe: which peer ids sync which space ids, each space's ACL (member public keys and permissions), object and change ids, DAG shape, sizes and timing, and push topics. What it cannot: field values, records, file contents and names, space names, profiles or message text ([Encryption](https://docs.any.org/understanding/encryption.md.txt)). ## Models and external services Neither boundary covers an inference request. A model provider reads the prompt the harness sends it — selected history, recalled memories, tool results — and a connector's service reads its API calls; end-to-end encryption protects the data at rest and between members, not the copy you hand to a provider. Search embeddings are the other outbound path and are configured apart from agent inference: `index.embedder: auto` embeds through the online primary with a local fallback, `local` keeps it on the device ([Configuration](https://docs.any.org/operations/configuration.md.txt#local-embeddings), [Conversations](https://docs.any.org/agents/conversations.md.txt#the-message-model)). ## Secrets on this machine | Secret | Where | Notes | | --- | --- | --- | | mnemonic | standalone: inside `wallet.key`; managed: memory only — the host supplies it over `POST /v1/auth` on every boot | printed once by `any init`; back it up, it is the account | | `wallet.key` | `/wallet.key`, mode 0600 | standalone; holds the mnemonic and this device's key as plain JSON unless a passkey encrypts it (`ANY_WALLET_PASSKEY` or `--passkey-stdin`, never an interactive prompt) — whoever reads a plain file holds the account | | `device.key` | `/device.key`, mode 0600 | managed; the device key only — the host supplies the account key on each boot and the server holds it in memory | | control token | printed once as `CONTROL_TOKEN ` to the spawning host, or passed in-process | managed; never logged, never on disk; the CLI takes it from `ANY_CONTROL_TOKEN` | | embedder API key | `index.openai.apiKey` | sent as a Bearer header, never logged | | data on disk | `sdk/`, `index/`, `files/` | not encrypted at rest: records, the local store and indexed text are readable without the wallet; `files/` holds file content encrypted. Protect the directory like a key store ([Data directory](https://docs.any.org/operations/data-dir.md.txt)) | Error responses never carry file paths or internal types; stack traces go to the server log, not the body ([Errors](https://docs.any.org/reference/errors.md.txt)). ## Local-network peers LAN discovery (`p2p`) announces this device over mDNS. The space exchange proves membership per space and reveals only the set of spaces two peers share; a stranger on the LAN sees an empty list. Disable with `p2p.enabled: false`, or isolate a deployment with `p2p.serviceName` ([Networks](https://docs.any.org/operations/networks.md.txt)). ## What the server does not provide | Not provided | Consequence | | --- | --- | | remote access | no non-loopback bind, no TLS, no auth tokens | | several accounts per process | one server = one account; a second account is a second process | | install / service files | you run `any run` under your own supervisor | | API-level rate limiting | none; the socket is local | Programs and agents that run inside the data — the sandboxed Python runtime — have their own boundary, the effect system, which is described under [Programs and effects](https://docs.any.org/understanding/programs-and-effects.md.txt) and [Limits](https://docs.any.org/programs/limits.md.txt).