Skip to content

feat(remote): require bearer-token handshake on WebSocket upgrade (M1.3)#4

Merged
wusijian007 merged 1 commit into
mainfrom
sec/m1.3-remote-token-handshake
May 14, 2026
Merged

feat(remote): require bearer-token handshake on WebSocket upgrade (M1.3)#4
wusijian007 merged 1 commit into
mainfrom
sec/m1.3-remote-token-handshake

Conversation

@wusijian007

Copy link
Copy Markdown
Owner

myagent remote serve previously accepted any local TCP client on the WebSocket port. Anything that could reach 127.0.0.1:8765 could drive the agent. Closes that hole:

  • ensureRemoteAuthToken(cwd) creates .myagent/remote/auth.json on first launch (mode 0o600 best-effort -- POSIX enforces; Windows no-op) with a 256-bit URL-safe token, and reuses it across restarts.
  • createRemoteAgentServer now requires authToken. The upgrade handler rejects requests whose Authorization: Bearer <token> header is missing, malformed, or wrong with HTTP 401 + a WWW-Authenticate: Bearer realm="myagent-remote" challenge -- before any WebSocket framing is negotiated.
  • Token comparison uses crypto.timingSafeEqual to avoid timing side-channel leaks on local-shared hosts.
  • connectRemoteClient accepts an authToken option that injects the matching header.
  • remote sessions (the metadata listing subcommand) is unchanged -- it reads JSON files directly off disk and never opens a socket.

The existing three remote tests now pass authToken: "test-token" through. Six new tests in packages/core/test/security/remote-auth.test.ts pin the invariants: missing header rejected, wrong token rejected, non-Bearer scheme rejected, correct token reaches ready, token file persists and round-trips through JSON, and the metadata API does not need the auth file.

Catalog row added under "Remote WebSocket auth" in packages/core/test/security/README.md. CLAUDE.md updated.

Multi-client session ownership and a dedicated myagent remote client CLI stay deferred to v2.0 per the M1 plan.

`myagent remote serve` previously accepted any local TCP client on the
WebSocket port. Anything that could reach 127.0.0.1:8765 could drive
the agent. Closes that hole:

- `ensureRemoteAuthToken(cwd)` creates `.myagent/remote/auth.json` on
  first launch (mode 0o600 best-effort -- POSIX enforces; Windows no-op)
  with a 256-bit URL-safe token, and reuses it across restarts.
- `createRemoteAgentServer` now requires `authToken`. The upgrade
  handler rejects requests whose `Authorization: Bearer <token>`
  header is missing, malformed, or wrong with HTTP 401 + a
  `WWW-Authenticate: Bearer realm="myagent-remote"` challenge --
  before any WebSocket framing is negotiated.
- Token comparison uses `crypto.timingSafeEqual` to avoid timing
  side-channel leaks on local-shared hosts.
- `connectRemoteClient` accepts an `authToken` option that injects
  the matching header.
- `remote sessions` (the metadata listing subcommand) is unchanged --
  it reads JSON files directly off disk and never opens a socket.

The existing three remote tests now pass `authToken: "test-token"`
through. Six new tests in `packages/core/test/security/remote-auth.test.ts`
pin the invariants: missing header rejected, wrong token rejected,
non-Bearer scheme rejected, correct token reaches `ready`, token
file persists and round-trips through JSON, and the metadata API
does not need the auth file.

Catalog row added under "Remote WebSocket auth" in
`packages/core/test/security/README.md`. CLAUDE.md updated.

Multi-client session ownership and a dedicated `myagent remote client`
CLI stay deferred to v2.0 per the M1 plan.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@wusijian007 wusijian007 merged commit 19dfc58 into main May 14, 2026
3 checks passed
@wusijian007 wusijian007 deleted the sec/m1.3-remote-token-handshake branch May 14, 2026 07:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant