# Security assessment: Orca at commit 7a06b65 **Bottom line:** I found no sign that this is malicious or that it quietly sends your data somewhere. The mobile-relay encryption, telemetry and local secret storage are reasonably well built. The real risk comes from what the tool is for: it gives AI agents, and optionally a paired phone, broad control of your machine as your user account. If you turn on mobile pairing, the QR code effectively hands someone remote control of your computer. **How I reviewed it:** I read about 35 security-relevant files on GitHub at this commit. I had no local clone, so each file went through a fetch tool that summarizes the page with a smaller model. I didn't run grep across the whole repo or read every line myself, so treat this as a targeted review, not an audit. ## Verified from the code **Phone ↔ desktop encryption (v2 protocol).** The relay server can't read your traffic. - Key exchange: the desktop has an X25519 keypair (via the `tweetnacl` library, `src/main/runtime/e2ee-keypair.ts`). Its public key is in the pairing QR code, and the phone checks it during the handshake, so the relay can't swap in its own key. - Session keys: derived with HKDF-SHA256 from the shared secret, a random 32-byte value from each side, and a hash of the handshake. Each direction gets its own key (`src/shared/mobile-e2ee-v2-node-key-schedule.ts`). - Messages: encrypted and authenticated with `nacl.secretbox`. Each message carries a sequence number, and the desktop only accepts the next expected one, so replayed or reordered messages are rejected (`mobile-e2ee-v2-framing.ts`, `mobile-e2ee-v2-desktop-session.ts`). - Device login: the phone's device token is sent inside the encrypted channel, after the handshake (`mobile-e2ee-auth-validation.ts`). **Relay design.** Per the `cloud/` README, both devices connect out to the relay, which forwards frames between them. With the encryption above, it only sees ciphertext plus metadata such as timing, sizes and IDs. **Local network listener.** The WebSocket server is plain `ws://` with no TLS, relying on the encryption layer above. It starts on loopback (127.0.0.1) and only opens to all network interfaces when you generate a LAN/QR pairing offer (`runtime-rpc-network-exposure.ts`). On Windows, a firewall rule is created only through an explicit "repair" action with a UAC prompt. It applies to Private networks but doesn't restrict remote addresses. **Telemetry.** It goes to PostHog (`us.i.posthog.com`) and is consent-gated: nothing is sent until you choose (`src/main/telemetry/consent.ts`). - It sends app version, OS, a persistent install ID and a session ID, with event fields checked against a schema. GeoIP lookup is turned off in the SDK. - `DO_NOT_TRACK=1` or `ORCA_TELEMETRY_DISABLED=1` disables it, and so does any CI environment. - Source and dev builds send nothing because there's no write key. **Secrets at rest.** Settings secrets (proxy URL, OpenCode cookie and similar) are encrypted with Electron's `safeStorage`, which uses the OS keychain. If encryption isn't available, they aren't written in plaintext (`protected-secret-persistence.ts`). The E2EE private key itself is stored as plain base64 JSON. Its file is written atomically and locked to your user (0600 on macOS/Linux, ACLs on Windows; `src/shared/secure-file.ts`). ## Weaknesses and caveats 1. **The QR code is a long-lived credential.** It contains the device token, the desktop public key, the address to connect to, and the relay details (`runtime-rpc-mobile-pairing.ts`). In `src/shared/pairing.ts` I found no expiry and no one-time-use check. Anyone who photographs it can pair. 2. **A paired phone has wide powers.** Allowed actions include `terminal.send`, `terminal.create`, `agent.launch`, `files.read`, `git.push`, `github.mergePR` and `ssh.connect`. That is effectively shell access as your user. 3. **The old v1 protocol is still accepted by default.** The `requireV2` flag defaults to false (`rpc/e2ee-channel.ts`). v1 has no handshake binding and no visible replay protection. I couldn't confirm whether production builds turn `requireV2` on. 4. **Minor:** the device token is checked with `===`, not a constant-time comparison. This happens inside the encrypted channel, so the impact is low. 5. **Inherent to the tool:** it runs coding agents with your full user permissions and offers "Computer Use" for desktop apps. Treat agent output and any repo you point it at as untrusted. ## What I couldn't verify - **Relay auth and back end:** the API and auth services are in a private repo (`stablyai/orca-cloud`), so server-side behavior and what it logs can't be checked. - **Binaries vs. source:** whether the released DMG, EXE, AppImage, Homebrew and AUR builds match this source, and how the auto-updater checks signatures. I didn't read `updater.ts` in depth. - **Mobile app:** I didn't review `mobile/`. - **Linux keychain:** whether a weak `safeStorage` backend (such as `basic_text`) is rejected. - **Electron hardening:** renderer settings (sandbox, contextIsolation, CSP) and the Design Mode and embedded-browser code. ## Recommendations - If you don't need the phone app, don't pair. The listener then stays on loopback. - If you do pair, treat the QR code like a password and revoke devices you no longer use. Prefer "This computer only" or relay mode over LAN exposure on untrusted networks. - Set `DO_NOT_TRACK=1` or decline the telemetry prompt if you want zero analytics. - Install from the official release or Homebrew cask and check the code signature. - Run agents only on repos you trust.