Lumen
Security

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

  1. 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/root

    The defaults are 127.0.0.1:32147; --host accepts only 127.0.0.1 or ::1. Repeat --origin and --root to add exact authorities, and use --rotate-secret only for an explicit Keychain secret rotation.

  2. 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/pair and 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.

  3. Send the exact Host, approved Origin, 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}.

  4. Use only thread/start, thread/resume, turn/start, turn/steer, turn/interrupt, model/list, and modelProvider/capabilities/read. Unknown methods and fields fail closed.

  5. 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.

  6. 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.

Next task

Use the generated reference.

On this page