Skip to main content
← Back to list
01Issue
BugShippedSwamp CLIPublicTeam
Assigneesstack72

Relationships

#2383 serve: minting a token for an unsupported principal kind (e.g. agent:) succeeds, then every connection 500s in parsePrincipal

Opened by randybias · 9/22/2026· Shipped 9/23/2026

Problem

swamp access token mint accepts any <kind>:<id> principal string, but a connection made with such a token crashes serve's upgrade handler, which accepts only user and worker. The token is minted, stored, and authenticates — and then every request with it fails.

Measured (serve 20260922.011324.0)

A token minted for agent:swamp-resumer:

Server log, per connection attempt:

system │ Authenticated token "swamp-resumer" as "agent:swamp-resumer"
Error: Invalid principal kind "agent": expected "user" or "worker"
    at parsePrincipal (src/domain/access/principal.ts:47:11)
    at src/cli/commands/serve.ts:4222:31
    at async mapped (ext:deno_http/00_serve.ts)

Client side, the WebSocket upgrade returns HTTP 500:

$ curl -s -o /dev/null -D - --http1.1 -H 'Connection: Upgrade' -H 'Upgrade: websocket' \
    -H 'Sec-WebSocket-Version: 13' -H 'Sec-WebSocket-Key: ...' \
    -H "Sec-WebSocket-Protocol: bearer.<agent token>" https://<serve>/
HTTP/1.1 500 Internal Server Error

Control, same call with a user: token on the same server: HTTP/1.1 101 Switching Protocols.

  • PrincipalKindSchema is z.enum(["user", "worker"]) (src/domain/access/principal.ts:22).
  • access_token_mint.ts passes principalId: principal through (lines 146 and 225) with no validation against that enum, locally or via access.token.mint.

Impact

  1. Mint succeeds for a principal that can never connect. Nothing fails until a client tries to use the token, and the error it gets is misleading: the CLI reports "Authentication failed — run: swamp auth server-login", because classifyConnectionError (src/cli/remote_run.ts:756) maps any non-101 to that message. Authentication in fact succeeded; the crash is after it.
  2. No principal kind for automation. Naming a non-human client agent: is the natural way to keep human and machine identities apart in the audit log, and grants are commonly written per group of such principals. Today every automation must masquerade as user:, which weakens exactly the distinction an audit log exists to make.

Ask

  1. Reject an unsupported principal kind at mint time, with the valid kinds named.
  2. Never let a bad principal produce a 500: return 401/403 with a reason on the upgrade.
  3. Consider an agent (or service) principal kind for non-human clients, first-class in grants and audit records.
  4. Make classifyConnectionError stop reporting a server-side 500 as an authentication failure.
02Bog Flow
✓OPEN✓TRIAGED✓IN PROGRESS✓SHIPPEDTRIAGE+ 5 MOREREVIEW+ 10 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

9/23/2026, 1:46:49 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack729/22/2026, 11:21:12 PM
Editable. Press Enter to edit.

stack72 commented 9/23/2026, 1:47:00 PM

Thanks @randybias for reporting this! We shipped: Fix asks 1, 2 and 4 of the issue; ask 3 (an agent principal kind) is out of scope. Enforce the Principal value object at the ServerToken mint boundary (model mint plus a fast CLI check), reject a stored token whose principal does not parse at authentication time with 401 invalid-principal instead of a 500 crash in three post-auth call sites, and stop classifyConnectionError reporting 5xx and other non-auth statuses as an authentication failure.. The fix has been merged and a release is on its way. We appreciate your contribution to swamp.

Sign in to post a ripple.