Join doesn't enforce runner_id uniqueness — a reusable invite can impersonate a runner
PR #846 added per-sandbox token authorization that trusts the caller's mTLS cert CommonName (runner-<runner_id>) to decide which sandboxes a runner may mint identity tokens for. That check is only as strong as the uniqueness of runner_id, and right now Join doesn't guarantee it.
At Join the runner sends its own runner_id (validated as a UUID but otherwise trusted), and the node entity is written with EAC.Put keyed on ident node/<runner_id> — create-or-update, so a second Join with an existing id silently overwrites rather than rejecting. runner_ids aren't secret (they show up in m runner list, logs, etc).
So a holder of a reusable invite can Join as a known runner's id, receive a valid cert with that runner's CN, and mint workload identities for its sandboxes. Since those identities federate to external systems (AWS IAM, etc), this is an outward-facing impersonation, not just an internal-trust issue. One-time invites are mostly safe since they're claimed on first use; reusable invites are the exposure.
Fix: either reject a Join whose runner_id already has a live node, or stop letting runners choose their own id and assign it server-side.
Surfaced during review of #846 (mirendev/runtime#846).