All pages
On this page

What OAR exposes, and what it does not

This page collects, in one place, what OAR exposes and what it does not. Each fact has its home on another page; every section ends with a link to it. The short version: a relay acts as you, the access token is full control of it, and a few links you create are public on purpose.

The trust model #

A relay runs as an operating-system user, and its agents run as that user with that user's rights. Whatever you can do on the machine, an agent can be asked to do. Nothing confines an agent's shell. An agent can read the config file (and with it the access token), the database (with the provider keys and the tokens of paired relays) and the login files of the providers. The access token gives full control of the relay, and so of what its agents can do: whoever holds it can have an agent run commands on the host. OAR adds reach to those agents. It adds no sandbox.

The one exception is Claude Cloud, whose agent works on a clone of a GitHub repository in a sandbox at Anthropic, not on your machine (see What leaves your machine).

What an agent may touch #

The working folder is where an agent works. It is not a wall. This is what OAR enforces and what it does not:

OAR enforces OAR does not enforce
workspaceRootAllowList limits which folders a conversation can be started in, and moved to with Change CWD. Unset, any existing folder is allowed. Nothing confines an agent's shell to the working folder. It can read and write wherever the relay's user can.
Relay modes tell the agent how freely to act. Some providers enforce part of it: the SDK engine of GitHub Copilot and OpenAI refuses anything that is not read-only in plan and asks you first in ask. Claude, and Added in 0.9.17 DeepSeek, run every tool without asking you, in all modes. Grok's permission requests are all approved. On the extension engine OAR checks no permissions. A mode there is an instruction the agent follows.
A static preview can only serve a folder inside the working folder. The allow list does not check the Default folder, and it does not limit what you can browse.

Details: Limiting where chats may start, Relay modes and Agents and the token.

Reachable without signing in #

Everything that reads or changes your conversations, files, settings or agents needs the access token. These are the exceptions:

What What it exposes How to switch it off
The sign-in page and the static app The web app and its sign-in box. It holds none of your data. It cannot be switched off. Keep the relay off the internet (localhostOnly) or put access rules in front.
A share link (/shared/…) The conversation's transcript, read only, with the model of each message. The relay host's paths are filtered (file names only, by default), and messages you hid are not sent. Each open is logged. Stop sharing or Renew link in Settings → Sharing, or delete the conversation. The old address then answers a plain 404. A link never expires.
A preview link The previewed dev server or folder. The link's random token is its only protection. Close the preview, or /preview close. The lane is off until you configure it. A preview survives a relay restart, and ends when you close it or delete its conversation.

A Cloudflare Access application in front of the relay also stops viewers of a share link unless /shared/* and /api/shared/* are let through, which makes those two paths public on purpose (Cloudflare Access).

Details: Your shared links, what a viewer sees, Previews and What needs the token.

What a signed-in browser can reach #

A browser that holds the token can open every conversation on the relay, and it has the file browser. On Linux and macOS the drives root serves any file the relay's user can read, inside the working folder or not. Rename and delete act wherever that user may write, and a delete does not go to a trash. On Windows the browser is limited to the drives the relay lists. The media route that shows an agent's images works the same way: it serves any absolute path the relay's user can read, but only to a request that carries the token.

Details: The file browser, Images and media.

Secrets #

Secret Where it lives
The access token config.json, in plain text. The relay keeps the file owner-only. A browser also holds it, as the sign-in cookie.
A Cloudflare tunnel token config.json (cloudflaredTunnel.token) or the environment.
OpenAI, Cursor, Added in 0.9.17 DeepSeek and Added in 0.9.18 Claude API keys The database. They are never sent to browsers. Each reaches only its own provider's workers; the DeepSeek key leaves the machine only for the DeepSeek base URL, the Claude API key only for https://api.anthropic.com.
A paired relay's token The database. It is never sent to browsers or agents.
Share link tokens, push keys The database.
Claude, Grok and GitHub Copilot logins The providers' own folders on the machine (~/.claude, ~/.grok, the Copilot CLI's login). OAR stores none of them. DeepSeek chats use none of them. Added in 0.9.18 Claude API chats share the Claude folder but run on the saved key, not on the login.
A Claude login token in the relay's environment (CLAUDE_CODE_OAUTH_TOKEN) Added in 0.9.17 Handed only to Claude and Claude Cloud workers, on every platform. Before, other workers could get it too.
An Anthropic key or token in the relay's environment (ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN) Added in 0.9.17 Handed to no worker. Before, every worker got it, and a Claude chat ran on it instead of the Claude login. Added in 0.9.18 A Claude chat on the subscription that comes up on an API key from Claude Code's own settings is stopped too; see Claude.

Agents run as the same user as the relay. File modes that say "owner only" therefore do not keep an agent out: it can read config.json, the database and the provider folders. Nothing in OAR hides them from it. The relay's own workers and the tools that agents use to reach the relay read the access token from config.json. relay_tool never gives an agent the token of another relay: the call goes through your relay, which adds the token. An agent could still read that token from the database. A backup of the database holds the keys and tokens above, so keep it as private as the state folder.

Added in 0.9.17 A DeepSeek chat's agent can read the DeepSeek key from its environment. The relay replaces the key with [redacted] in whatever a session worker posts before it stores or shows it, which keeps it out of the transcript, but that does not stop an agent that wants the key. See Where the key is kept.

Added in 0.9.18 The same holds for the Claude API key in a Claude API chat. That chat shares the Claude folder where your Claude login lives, so the relay pins the saved key over any credential in its settings and stops a turn whose Claude Code reports another source for its key. Claude Code sends its first model request a moment after that report, so one model request may already have gone out on the other credential before the stop: the check limits a wrong credential to that one model request, it does not prevent it. See Claude API → Security.

Added in 0.9.18 In DeepSeek and Claude API chats, which run on a key the relay holds, Claude Code starts with all hooks and the status line off, yours and the chat folder's, so they cannot run with the key in their environment. Hooks in managed settings still run. Chats on your Claude login keep theirs.

Added in 0.9.17 A relay started from inside a Claude Code session (an agent's shell, for example) no longer hands that session's variables, its session id and messaging socket and token among them, to its workers. See A relay started from inside Claude Code.

Details: Where secrets live, Which variables reach the agents' workers.

Between relays #

Pairing can hand a token over: if the other relay needs a different token to call yours back, the introduction carries yours, and removing the pairing does not revoke it. The Agents may level (Read only, Read and prompt, Full; new pairings start at Full) and Accept prompts from other relays' agents limit what agents do through the tool, not what a token holder does directly. A paired relay is locked in a conversation until you mention it. A prompt that has crossed two relays is not passed on to a third, and after 30 prompts without a message from you the next one asks you on a card.

Details: Remote relays and pairing.

Between agents on one relay #

Agent sessions are off by default. When you turn them on, an agent must ask you before it starts its first session in a conversation, at most 4 of its sessions may be at work at once, and a session an agent started cannot start sessions itself. In the ask and plan modes every write action asks first.

Answer approval cards with their buttons. On OAR's own approval cards only the word Allow approves, in any capitals. Any other text you type denies, and the agent gets no reason from it.

Details: Agent sessions and Approval cards.

Network #

  • Who can connect. localhostOnly is true by default and binds the relay to 127.0.0.1. Any other value binds all interfaces, and the relay does not check where a request comes from. LAN access is plain http, so the token crosses your network unencrypted (Who can connect).
  • Tunnels. Beyond your network, use HTTPS through a tunnel or proxy: SSH tunnel, Cloudflare Tunnel, Reverse proxy.
  • Sign-in. Added in 0.9.11 Ten wrong tokens from one address within a minute lock that address out for the rest of the minute (429), and the refusal is logged. Requests from the relay's own machine that nothing forwarded are never locked out. The lockout slows guessing; a long random token is still the protection. The cookie is HttpOnly and lasts 30 days (Protections).
  • A token in an address. ?token= works on the page address only; the page signs in with a header and removes it. That first address can still end up in browser history and in the logs of a proxy or tunnel (Ways to present it).
  • The live connection. Added in 0.9.11 It accepts a browser only from the relay's own origin, so a page on another site cannot ride your sign-in cookie into it. Behind a proxy that rewrites the Host header, list the public origin in allowedOrigins.
  • Forwarded headers. Added in 0.9.11 X-Forwarded-For, X-Forwarded-Host, X-Forwarded-Proto and X-Real-IP count only from a proxy the relay trusts through trustProxy, by default one on loopback. The client address (lockout, rate limits, the share access log) and the host and scheme of new share links are read through it, so a direct client cannot choose them.
  • Restart and empty queue. Restart, cancelling a restart and Empty queue need only the token, from any device. If remote users must not use them, refuse them at the proxy (Endpoints only the relay's machine may use).
  • The session-worker path guard. The path your agents' workers use, and the run of image operations, answer only a loopback peer whose request carries no tunnel marker (cf-ray, or one in tunnelMarkerHeaders) and no X-Forwarded-For, Forwarded or X-Real-IP. A forwarder that adds none of these, such as an SSH reverse tunnel, looks local; then only the token protects the path (path guard).
  • The Cloudflare tunnel token. It is passed to cloudflared on the command line, so other users of the machine can see it in the process list (Cloudflare Tunnel).
  • SSH tunnel cleanup. autoReclaimPort (on by default) ends the process of your SSH login that holds the remote port; reclaimStaleSshSessions also ends your idle SSH sessions there (remote port taken).

What leaves your machine #

OAR has no telemetry. The relay sends no usage data to OAR or anyone else. It contacts these hosts, and only for these reasons:

  • oar.sh, only if you opt in. Check for updates automatically in Settings → General is off by default. When you turn it on, the relay asks https://oar.sh/latest.json at once, at each start and then about every 12 hours. The request is a plain GET with Accept: application/json and, once there is an answer, If-None-Match. It carries no version, token, account or machine information. The Check for updates button and oar update without --to read the same file. OAR_NO_UPDATE_CHECK=1 in the relay's environment stops all of it. See The update check.
  • npm, when you update. npm install -g talks to the npm registry.
  • Each provider, for every turn. Your messages and whatever the agent reads for the task go to the provider behind the conversation: GitHub Copilot, OpenAI (or the base URL you set), Claude, Claude API, Cursor, Grok or DeepSeek (or the base URL you set). Their terms apply, not OAR's.
  • DeepSeek. Added in 0.9.17 The relay sends the DeepSeek key to https://api.deepseek.com, or to the base URL set under Advanced in Settings → Providers → DeepSeek (https, or http on the same machine only), and to no other host: to list the models when you save the key or the base URL or refresh the list in 🤗 Select Models, and to read the balance (below). A DeepSeek chat's Claude Code sends its turns to /anthropic under that address, with the same session context as any Claude Code chat. OAR switches off Claude Code's own traffic to Anthropic (updates, telemetry). See DeepSeek.
  • Claude API. Added in 0.9.18 The relay sends the Claude API key to https://api.anthropic.com and to no other host: to list the key's models when you save it, switch Claude API on or refresh the list. A Claude API chat's Claude Code sends its turns there with the key. See Claude API.
  • Claude Cloud. The agent runs at Anthropic, on a clone of your repository. The relay sends the Claude login token to https://api.anthropic.com and to no other host. See Claude Cloud.
  • Plan usage, when you open Check Usage. The relay reads your accounts with the logins it finds on the machine: GitHub (api.github.com, with GH_TOKEN, GITHUB_TOKEN or the login of gh), Grok (cli-chat-proxy.grok.com, with the Grok CLI's login), Anthropic (with Claude Cloud on), Added in 0.9.17 DeepSeek (the balance, at the DeepSeek base URL with the saved key, while DeepSeek is on) and, only if you entered a dashboard session token, cursor.com. See Check Usage.
  • GitHub Actions. For the suspend check, the relay runs gh run list for the repositories of your working folders (Host suspend).
  • Paired relays. What an agent sends through relay_tool goes to that relay's address with its token (Remote relays).
  • Provider installers, when you confirm. Install for Claude or Grok runs the provider's own installer script (claude.ai, x.ai) as the relay's user (Claude, Grok).
  • Push notifications. They go through the push service of your browser's vendor, and the text is generic unless you choose otherwise (What a notification shows).

Your browser, not the relay, loads the Markdown, math and highlighting libraries from cdn.jsdelivr.net (Markdown, math, terminal) and cdnjs.cloudflare.com (highlighting), every time it opens the app. The terminal view of a tmux session loads its terminal library from unpkg.com when cdn.jsdelivr.net fails. Those hosts see the request of every browser that opens the app. See Images, media and formulas.

Logs #

The relay copies its console to logs/relay-console.log in the state folder, with a time stamp per line. It rotates at 5 MB and keeps three older files. Before a line is written, the relay replaces your access token, and any value after ?token= or &token=, with [token]. OAR_NO_CONSOLE_LOG=1 switches the file off. A single wrong token is not logged; an address that is locked out is, with a line starting [auth]. A preview is named by a short hash, never by its token. A shared read is logged with the viewer's address, or not stored when Store viewer IP addresses is off.

The worker logs (worker-<session>.log) hold the output of each session worker and are written by the workers, not through that masking. Files of deleted conversations stay. A reverse proxy or tunnel in front of the relay keeps its own logs, which can hold ?token= addresses, and the managed Cloudflare tunnel shows its token as <redacted>. Treat all logs as private, and read them before you post them anywhere.

Details: Logs.

Before you expose a relay #

  1. Keep the token random and out of addresses you share. If it leaked, run oar setup --new-token, which signs every device out and locks out paired relays.
  2. Reach the relay over HTTPS: a tunnel or a reverse proxy. Keep localhostOnly on when the proxy or tunnel runs on the same machine.
  3. Behind a proxy on another machine, set trustProxy to it, and allowedOrigins if it rewrites Host (A proxy on another machine). A forwarder that adds no header at all needs a marker header in tunnelMarkerHeaders. If remote users must not restart the relay, have the proxy refuse those endpoints.
  4. Run the relay as a user whose rights, files and logins you would give the agents. Set workspaceRootAllowList if conversations should start only in certain folders, and remember that it does not confine a shell.
  5. Share a conversation only after you read it with Preview as shared, and hide what must not be there. Path filtering is a best effort in free text. Stop links you no longer need in Settings → Sharing.
  6. Publish a preview only for something you can show to anyone with the link, and close it when you are done. It survives a relay restart.
  7. Leave agent sessions off unless you need them. For paired relays, choose the Agents may level on purpose and turn off Accept prompts from other relays' agents where you do not need it.
  8. Click the buttons on approval cards.
  9. If you want no contact with oar.sh at all, set OAR_NO_UPDATE_CHECK=1.