Security and privacy
Local-first and security model
- Repository contents are read from and written to their existing local paths.
- The renderer has no direct Node.js, filesystem, or process access.
- Git, filesystem, persistence, AI, and GitHub operations run through one typed, validated WebSocket command boundary in both desktop and browser clients. Requests have correlation IDs, cancellation and timeouts; interrupted operations are rejected rather than replayed after reconnect.
- The private server transport binds to loopback by default, requires an owner session for commands and image bytes, validates exact mutation/WebSocket origins, and blocks static-file traversal and symlink escape. Enabling Settings → Network access persists a desktop-only setting and restarts that same backend on
0.0.0.0; disabling it returns to127.0.0.1. OpenTig never starts a second Web Access server. - New browsers pair through a five-minute, one-use URL fragment displayed as a link and local QR code; the fragment is cleared before exchange. Paired browsers receive a cookie and server session lasting 30 days, renewed automatically when the app connects, resumes in the foreground, and hourly while visible. Renewal extends both the cookie and server session without another pairing code or interrupting connected tabs; temporary network failures retry. Closing the browser or restarting the server preserves access. After 30 days without a successful renewal, the server rejects the expired credential and disconnects expired browser connections. Expiry, clearing site cookies, or revoking access requires a new code; renewal cannot restore expired or revoked access. Desktop bootstrap cookies remain session-only. Steady-state credentials use host-only
HttpOnly,SameSite=Strictcookies, only credential hashes are persisted, and revoking all sessions disconnects paired browsers while replacing the private desktop session. Network access grants owner-level file, Git, GitHub, and AI CLI authority as the OS user: use only a trusted LAN or VPN, an HTTPS reverse proxy, or an SSH tunnel, and never expose the raw port publicly. - Headless
pairauthenticates over a same-host-only administrative route using a separate private file under~/.opentig/server;runtime.jsoncontains PID/address/version identity but no credential. Pairing secrets remain memory-only and appear only in the deliberate one-time terminal output/URL fragment, never in arguments, environment variables, routine logs, query strings, or persisted state. - Electron starts the backend after readiness on preferred port
6767, scanning a bounded range upward only when that implicit port is occupied. Dev instead scans6867–6876, while production scans6767–6776; each keeps its selected port when Network access is toggled. Distinct session-cookie names let both profiles stay paired in the same browser on the same host, and revocation affects only that profile. If its range is full, startup fails rather than switching to the other profile. Its one-use desktop bootstrap secret crosses the private parent/utility message port exactly once; it is absent from process arguments, environment variables, renderer JavaScript, and redacted rotating logs. Unexpected exits restart one utility process on the same selected port. - The narrow preload bridge contains only proven desktop capabilities such as folder selection/relocation, file clipboard import, Explorer reveal, title-bar theming, and zoom. Text clipboard access stays in the renderer's browser API.
- Git commands use argument arrays with
shell: false, bounded output, timeouts, path validation, and per-repository write serialisation. - External links are allowlisted to
http(s)://andmailto:before Electron's window-navigation interception opens them in the system browser. - HTML previews execute the file's scripts inside a sandbox with an opaque origin, so they cannot read OpenTig cookies, storage, or the parent page. External resources and network requests remain available; forms, popups, and top-level navigation are blocked. Rendered Markdown is sanitised before display.
- Connected CLIs manage their own authentication. For every GitHub operation, OpenTig obtains the selected account's token from
ghand verifies its user identity. Only backend child commands receive the token in their environment; explicit and verified SSH accounts override backend token variables without changing the globalghaccount. Tokens never travel to renderers/browsers, command arguments, settings, status files or logs; credential-command output is discarded and operation errors redact the token. In-memory identity caches retain only a one-way fingerprint and the login.github-status.jsoncontains allowlisted installation and account metadata, never raw CLI output, credential paths or tokens. SSH checks require existing trusted host keys, use batch mode and do not create keys or update known hosts. The guided account flow copies official commands for the user to run; it does not execute authentication or change Git/SSH configuration. OpenTig does not read or persist AI API tokens.
Desktop Web access is off by default and is separate from the LAN listener. When off, only authenticated desktop sessions can use backend operations; browser pairing, renewal, HTTP data access and WebSocket commands/events are blocked even through a same-PC tunnel. Turning it off pauses browser access, disconnects browsers and invalidates pending pairing codes without restarting the desktop session. Saved browser credentials remain valid until expiry or explicit revocation; enabling Web access again lets those browsers reconnect. The standalone CLI remains browser-enabled. The optional saved public URL only constructs the pairing link and QR; it is not an authentication allowlist. Closing the QR display does not revoke a copied code. Static assets and health endpoints may still be served while browser backend access is disabled.
AI privacy
For commit-message generation, OpenTig sends the selected local AI CLI only a bounded staged diff, its summary, staged paths, the branch name, and up to ten recent commit subjects. It does not include unstaged content; untracked files are included only after you stage them.
Multi-commit proposals are accepted only when they partition every staged path exactly once. OpenTig preserves its generous, fairly distributed patch budget for large staged changes; a trimmed individual diff can still be grouped from the complete path list and summary. Proposals remain blocked when the complete file set cannot be trusted, such as partially staged files or staged renames, and OpenTig verifies that the staged snapshot has not changed before preparing the first group. Preparing a group changes only the Git index; every commit still requires an explicit review and confirmation.
For pull-request drafting, it sends a bounded comparison between the current branch and the selected base branch. If the context is truncated, the interface tells you to review the result carefully.
Generated content remains editable and pending. No commit is created and no pull request is published until you explicitly confirm the corresponding action.
Grok Build runs in a private temporary directory with an isolated profile, using the existing CLI authentication path or API-key environment without reading or copying credentials. Generation disables tools, subagents, web search, and memory; OpenTig checks grok inspect --json first and refuses profiles with hooks, plugins, MCP servers, or project instructions. Custom CLI models and user configuration are excluded. Prompt files and temporary sessions are removed after generation, errors, and cancellation. Grok may make an auxiliary session-title request in addition to the requested generation.
Commit and PR generation uses a temporary working directory outside the repository. Codex uses a disposable home and disables project instruction discovery, shell execution, web search, bundled skills, apps and subagents; it accesses only the CLI-owned auth.json through a temporary hard link, without reading or copying credentials. The working directory remains in system temporary storage; a separate private Codex profile is created beside the resolved credential file so its hard link stays on the same filesystem, even when system temporary storage uses another volume. Both temporary directories are removed on completion, error and cancellation. Codex requires accessible file credential storage and permission to create the private profile in its authentication directory; keyring-only authentication and custom provider configuration are not supported in this generation profile. Claude Code uses safe mode with no built-in or MCP tools, no user/project setting sources, disabled hooks and no session persistence; its native authentication remains available. Administrator-managed Claude policy still applies. OpenCode uses private home, configuration and cache roots while retaining its CLI-owned authentication database. It refuses databases with registered remote configuration (or unverifiable configuration metadata), so remote plugins and rules cannot be imported through authentication. Custom CLI configuration and custom model/provider definitions are excluded; select an available built-in provider/model explicitly when needed. Private OpenCode sessions are deleted after generation.
Repository writing conventions are opt-in under Settings → AI assistance → This repository. The backend stores one preference per Git common directory, shared across worktrees and clients; it is disabled by default. When disabled, instruction files are not separately read or loaded as instructions. Changes to these files can still appear in a staged or branch diff, where they are treated as untrusted data. When enabled, only root AGENTS.md, CLAUDE.md and GROK.md regular UTF-8 files are included, up to 32 KiB combined. Parent/global/nested instructions, symlinks, imports, referenced URLs and CLI configuration are not loaded. The selected provider receives this text along with the diff. Conventions may refine terminology, writing style and structure, but English, Conventional Commits, OpenTig's required output schema, length limits, factual accuracy, privacy and staged-file coverage remain mandatory. Text generation cannot make instructions executable. If the setting or text changes during generation, OpenTig rejects the stale result. Optional instruction contents are never saved in OpenTig's settings or diagnostic history.
Browser access and pairing
Connect a browser to your running OpenTig instance through SSH, a trusted network, or an HTTPS proxy. Manage pairing, sessions, and access.
Contributing
Contribute to OpenTig with focused changes, local setup, quality checks, documentation updates, and reviewed pull requests.