Local gateway security
Run the loopback Codex bridge with approved roots, exact browser authority, and a scrubbed child process.
Outcome
The macOS personal bridge can operate inside an approved local project without exposing Codex authentication, local credentials, or a cloud-reachable listener.
Prerequisites
Use Node 24.18.0, the workspace-pinned @openai/codex@0.144.6, the exact Codex executable you
intend to launch, at least one browser origin, and at least one canonical project root. Build the
package with pnpm --filter @lumen/local-gateway build.
Steps
-
From the repository root, start the built CLI with an absolute executable and root:
node packages/local-gateway/dist/cli.js --codex /absolute/path/to/codex \ --origin http://127.0.0.1:5173 --root /absolute/project/rootThe defaults are
127.0.0.1:32147;--hostaccepts only127.0.0.1or::1. Repeat--originand--rootto add exact authorities, and use--rotate-secretonly for an explicit Keychain secret rotation. -
Copy the single-use pairing code from the startup record into the workbench. The code expires in five minutes. The approved browser origin posts it once to
/v1/pairand keeps the returned origin-bound capability only for the current browser session. That capability expires after eight hours or when the gateway process exits. The Keychain installation secret never enters the browser, terminal output, HTTP response, cloud bridge, or product database. -
Send the exact
Host, approvedOrigin, and paired bearer capability on every other route. The service exposes/health/live,/health/ready,/v1/diagnostics, authenticated fetch-based resumable SSE at/v1/events, requests at/v1/codex/request, and decisions at/v1/approvals/{approval_id}. -
Use only
thread/start,thread/resume,turn/start,turn/steer,turn/interrupt,model/list, andmodelProvider/capabilities/read. Unknown methods and fields fail closed. -
Keep every thread root inside a startup-approved
realpath. The adapter rechecks file-bearing paths, rejects symlink escapes, scrubs the App Server child environment, and keeps the child on stdio. -
Preserve the adapter's normalized events and user approval states. Filesystem, shell, process, auth/config mutation, MCP, plugin, skill, marketplace, destructive-thread, account, and feedback methods are not exposed.
Verify
Run pnpm --filter @lumen/local-gateway proof:real-app-server on the reviewed macOS/Node host. It
uses an isolated empty Codex home and a credential-free loopback Responses fixture to prove the
actual locked App Server child, HTTP/SSE boundary, approval denial, child death/recovery, and
fresh-child thread resume without invoking a paid provider. Then run
pnpm --filter @lumen/local-gateway test and
pnpm --filter @lumen/local-gateway bindings:check. Confirm the binding fixture still matches Codex
0.144.6, readiness becomes 503 if the child is unavailable, a cursor resumes the SSE stream, and
unknown methods, replayed or expired pairing codes, expired or wrong-origin browser capabilities,
bad origin/host/token, unapproved roots, symlink escapes, oversized bodies, and scrubbed secret
canaries are rejected. The HTTP limit is 120 requests per minute and 1,100,000 bytes per request
body.
Recover
Send SIGINT or SIGTERM to close the listener and child process group. Rotate the install secret if
its authority is uncertain, restart with the same approved roots, and resume a saved thread only after
readiness returns. Never expose the App Server experimental network transport as a shortcut.