Only the latest commit on main is supported. There is no signed release binary
yet.
Use GitHub's Report a vulnerability / private security advisory flow when it is available on the public repository. Do not put pairing URLs, cookies, task identifiers, prompts, local paths, or raw diagnostic dumps in a public issue.
For ordinary setup bugs, open an issue with macOS version, phone/browser, Codex
version, the failing control, and redacted output from make diagnose.
- OpenAI credentials and Codex authentication state
- task contents and internal identifiers
- permission approval decisions
- control of the Codex desktop app
- paired phone sessions
| Risk | Control |
|---|---|
| Phone reaches raw Codex IPC | The phone can reach only the project-owned HTTP protocol. The same-user Unix socket remains Mac-only and mode 0600. |
| Prompt or task leakage | The phone schema contains generic task slots and controller state, not titles, IDs, turns, or raw events. |
| Pairing URL leaks | The one-time secret lives in the URL fragment, is not printed to the terminal, and is removed from browser history before exchange. |
| Session-file theft | Only SHA-256 token hashes persist. The directory is 0700; the file is 0600; the raw token stays in an HttpOnly cookie. |
| Cross-site action request | SameSite=Strict cookie plus exact Origin/Host checks on every POST. |
| Updated or unknown Codex schema | Runtime validation, a versioned adapter boundary, and fail-closed action results. |
| Wrong UI target | Named semantic Accessibility controls plus post-conditions. No screen coordinates. |
| Shim affects unrelated apps | NODE_OPTIONS is set only for the Codex executable launched by make serve-shim; child build and companion commands explicitly clear it. |
| Unexpected synthetic device traffic | Closed action allowlist, private mode-0700 runtime directory, local Unix sockets, framed messages, and request acknowledgements. |
| Static-file traversal | Decoded paths reject traversal and backslashes; resolved symlinks must remain inside the built web root. |
| Diagnostic leakage | Home paths, UUID-shaped task IDs, and sensitive values are redacted. |
The controller uses authenticated HTTP, not app-level TLS. A hostile Wi-Fi
observer could capture traffic or the session cookie. Use trusted Wi-Fi or a
private Tailscale tailnet. Never expose port 48321 through router forwarding,
Tailscale Funnel, a reverse proxy, or a public hostname.
A future public binary needs a deliberate local-TLS or native-shell decision. “Local-only” is not a substitute for encryption on an untrusted network.
Native Shim intercepts Codex's local node-hid module in the Codex process it
launches. This is more invasive than Standard Bridge and is why setup explains
the choice before starting it. The shim does not alter the installed Codex app
or its data on disk. A Codex update may invalidate the device contract; the
launcher and tests must fail visibly instead of silently falling back.
The interception layer is adapted from Marcel Pociot's MIT-licensed Codex Micro Stream Deck emulator, with its license retained in the repository.
Standard Bridge uses macOS Accessibility because the Codex desktop app does not offer a public API for every control. Native Shim uses Codex's synthetic hardware path instead. Neither needs Full Disk Access, screen recording, contacts, camera, or OpenAI credentials. Missing permissions disable controls instead of weakening verification.