Security
Rivets is built so that your code and your model access stay on machines you control. This page describes how accounts and workers are authenticated, what data reaches Rivets, how GitHub credentials are handled, and what Rivets does not protect against.
Accounts
- Sign-in uses email and password. There is no external identity provider. Repeated failed sign-in and two-factor attempts are rate limited and slowed down.
- Two-factor authentication uses a TOTP authenticator app. Turn it on in the web app under Settings › Security › Two-factor authentication. When you enable it, Rivets shows backup codes once. Save them somewhere safe.
- Sessions. Active sessions, under Settings › Security on the web and in the apps’ settings, lists everywhere your account is signed in, and you can sign any of them out. Changing or resetting your password signs out every other session.
- Native devices. A Mac, iPhone, or iPad session is bound to a signing key created on that device, and every request from the app carries a signature from it, so a copied session token is useless on its own. These sessions are listed under Settings › Security › Native devices on the web, and under Trusted devices in the Mac and iOS apps’ settings, with when each was last used. Choose Revoke to sign a device out.
- Browser protections. The web app sends a strict content security policy, and Rivets refuses changes made with your session cookie from any other site.
- Organization isolation. Every request is scoped to one organization, and membership is checked on each one.
Worker authentication
A worker proves its identity with two factors, both kept in the operating system’s credential store (Keychain on macOS, Secret Service on Linux, DPAPI on Windows):
- A worker token starting with
rvw_. Rivets stores only its hash. A new token must be activated within 15 minutes or it expires. - A P-256 signing key the worker generates when it first connects. Enrollment permanently binds the key’s public half to the token.
After enrollment, every request and connection must carry a fresh ES256 signature over the method, the exact URL, the token’s hash, the time, and a one-use ID. Rivets rejects signatures more than 60 seconds old, records each ID, and rejects any reuse, so a captured request cannot be replayed. A stolen token alone is not enough to impersonate a worker.
Neither secret is written to config.json, a service definition, command-line arguments, or environment variables. On macOS and Windows, if the credential store is unavailable, the worker refuses to start rather than fall back to a file.
A Linux machine without a Secret Service, such as a server reached over SSH, is the one exception. There, the worker keeps both secrets in ~/.rivets/auth/credentials.json, readable only by its OS user (mode 0600) but not encrypted. This protects against other users on the machine, not against root, backups, or someone with the disk. rivets status shows where a worker’s credentials are stored.
Network
- Outbound only. Workers open an outbound TLS WebSocket to Rivets, which runs on Cloudflare. They never listen on a port, and no inbound connectivity is required or possible.
- Clients connect to Rivets over HTTPS and secure WebSockets.
- Previews of a worker’s dev server are served from their own origin, separate from the app, and never see your Rivets session. Each one is opened with a one-use ticket and checks your repository access again as you use it. The worker only ever contacts the loopback port a task registered, never a host or URL from a browser. See Previews.
- iOS Simulator viewing in the Mac app runs on a private loopback address on that Mac, with a random path per session. Its video and input never pass through the worker or Rivets’ servers.
- Optional direct paths. The same-machine path listens only on
127.0.0.1. The opt-in Tailscale path uses your existing tailnet, and every connection still needs a one-use Rivets ticket that expires after 60 seconds. See Terminals and scripts.
What Rivets stores
| Stored by Rivets | Stays on the worker |
|---|---|
| Account, organization, team, and repository records | Repository clones and task worktrees |
| Conversation event logs (prompts, agent messages, and tool activity) and team chat | Your Claude Code and Codex logins |
| Snapshots of each task’s git status and diffs | Terminal scrollback, encrypted |
| Cached file contents viewed in the apps | Worker token and signing key |
| Prompt attachments | Service logs |
Snapshots are pruned over time. Rivets keeps the newest five per task and everything younger than 30 minutes.
Rivets runs no models. Commit messages, pull request descriptions, and task names are generated on the worker by your own agent, and the diff used to write them does not leave the machine for that purpose.
GitHub credentials
The Rivets GitHub App is the only GitHub credential Rivets uses. Workers never read your personal access tokens, SSH keys, or existing credential helpers.
When a job needs GitHub, Rivets issues a short-lived installation token scoped to that one repository and to only the permissions the job needs. The app never requests the Workflows permission, so a task cannot push changes under .github/workflows. The worker passes the token to each git command through a local credential helper over a Unix socket. It is never written to disk and never appears in a process listing. See GitHub.
Worker hardening
- Sandboxed file reads. When a client asks for a file, the worker resolves the path strictly inside the task’s worktree. Paths that lead outside it, whether absolute, through
.., or through a symlink, are rejected. Text files over 1 MB and binary files are not sent, except images up to 5 MB for preview. - Guarded file saves. Saving a file from the editor goes through the same path checks. The worker refuses to write inside
.git, through a symlink, to a hard-linked or binary file, or to a file that changed since you opened it. - No shell interpolation. The worker runs git and the agent CLIs with argument lists, never a shell command line built from your branch names, prompts, or paths.
- Validated input. Every message the worker receives is validated against the protocol schema. Anything invalid is dropped.
- Redaction. Rivets tokens, GitHub tokens, and credentials embedded in URLs are stripped from logs and agent events before they leave the worker.
- Terminal clipboard. In the Mac and iOS apps, a program in a terminal cannot read your clipboard, and must ask before replacing it. Rivets shows what would be copied and waits for you to allow it.
MCP tokens
Personal rvp_ tokens are shown once and stored hashed. Each is bound to one user and one organization, carries only the scopes you choose, can expire, and can be revoked at any time. MCP cannot manage tokens, members, settings, or workers. See MCP server.
What Rivets does not claim
- No filesystem isolation between repositories. Agents and terminals run as the worker’s OS user. A shell on a worker can reach other repositories’ checkouts and any credentials that user can read.
- Teams are not an isolation boundary for people who do not trust each other on a shared worker. They control what Rivets shows and allows, not what a process on the worker can touch. Use separate workers, in separate OS accounts or machines, for real separation.
- Checked-in scripts run automatically. A repository’s
setupscript runs when a worktree is created, before anyone reviews the branch. Turn scripts off with--no-scriptson workers that build untrusted code. See The .rivets directory. - Revoking access stops further access. It cannot take back content someone already copied.