roster-v2 canonical socket_name accepts empty string — tmux socket-boundary isolation validation gap #854

Open
opened 2026-07-20 08:26:04 +00:00 by jason.woltje · 1 comment
Owner

roster-v2 canonical socket_name accepts empty string — tmux socket-boundary isolation validation gap

3-source primary-verified @ main 11d281845376eb5910a74403300956d8edcc93a8 (builder lane ms-m3002-build + MS-LEAD + homelab W-jarvis, independent primary-source reads all concordant).

Defects — packages/mosaic/src/fleet/roster-v2.ts

  • (a) Schema L176: socket_name: { type: 'string', pattern: '^[A-Za-z0-9_.-]*$' } — uses * (zero-or-more) with no minLength. The sibling holder_session L177 correctly uses +.
  • (b) Const L276: TMUX_SOCKET_IDENTIFIER = /^[A-Za-z0-9_.-]*$/ uses * vs TMUX_IDENTIFIER L277 /^[A-Za-z0-9_.-]+$/ (+). An empty string passes; requiredTmuxSocket (L478–486) trims then accepts "".
  • (c) Minor: error message L480 "...is required and must be a string." vs the non-empty wording at L465.

The asymmetry with the adjacent holder_session / TMUX_IDENTIFIER (both +) confirms this is an unintentional gap, not a deliberate design choice.

Fix spec

  • *+ on L276 (TMUX_SOCKET_IDENTIFIER).
  • Add minLength: 1 to the schema socket_name on L176.
  • Align the error message wording on L480 with the non-empty phrasing (L465).

Security

Socket-boundary / session-isolation surface: an empty socket_name can collapse to a default tmux socket, creating a cross-session boundary risk. This is validation-hardening on a config-supplied canonical field (severity ~medium; not an active exploit).

Merge gate for the fix: independent CODE review (author ≠ builder) + OPUS SECREV (isolation-boundary surface — SECREV tier NOT downgradable) + exact-head CI green + named-executor merge clearance.

Discovered-by

FCM-M3-002 acceptance test (packages/mosaic/src/fleet/fleet-reconciler.acceptance.spec.ts). The test is CORRECT — do NOT weaken it. The test asserts an empty canonical roster-v2 socket_name must be rejected; production currently does not.

Scheduling

Prod-fix lane is PARKED for the Opus window (Opus quota-blocked until 2026-07-23; SECREV tier not downgradable). At Jul-23: one bounded lane — builder authors the roster-v2.ts fix + red-first regression → independent CODE → OPUS SECREV → exact-head CI green → named-executor merge → then the FCM-M3-002 test refresh rides green on top.

Blocks: FCM-M3-002 (#758 sub-gate). Cross-ref #758.

## roster-v2 canonical `socket_name` accepts empty string — tmux socket-boundary isolation validation gap **3-source primary-verified** @ main `11d281845376eb5910a74403300956d8edcc93a8` (builder lane `ms-m3002-build` + MS-LEAD + homelab W-jarvis, independent primary-source reads all concordant). ### Defects — `packages/mosaic/src/fleet/roster-v2.ts` - **(a)** Schema L176: `socket_name: { type: 'string', pattern: '^[A-Za-z0-9_.-]*$' }` — uses `*` (zero-or-more) with **no `minLength`**. The sibling `holder_session` L177 correctly uses `+`. - **(b)** Const L276: `TMUX_SOCKET_IDENTIFIER = /^[A-Za-z0-9_.-]*$/` uses `*` vs `TMUX_IDENTIFIER` L277 `/^[A-Za-z0-9_.-]+$/` (`+`). An empty string passes; `requiredTmuxSocket` (L478–486) trims then accepts `""`. - **(c)** Minor: error message L480 `"...is required and must be a string."` vs the non-empty wording at L465. The asymmetry with the adjacent `holder_session` / `TMUX_IDENTIFIER` (both `+`) confirms this is an unintentional gap, not a deliberate design choice. ### Fix spec - `*` → `+` on L276 (`TMUX_SOCKET_IDENTIFIER`). - Add `minLength: 1` to the schema `socket_name` on L176. - Align the error message wording on L480 with the non-empty phrasing (L465). ### Security Socket-boundary / session-isolation surface: an empty `socket_name` can collapse to a **default tmux socket**, creating a cross-session boundary risk. This is validation-hardening on a config-supplied canonical field (severity ~medium; not an active exploit). **Merge gate for the fix:** independent CODE review (author ≠ builder) + **OPUS SECREV** (isolation-boundary surface — SECREV tier NOT downgradable) + exact-head CI green + named-executor merge clearance. ### Discovered-by FCM-M3-002 acceptance test (`packages/mosaic/src/fleet/fleet-reconciler.acceptance.spec.ts`). **The test is CORRECT — do NOT weaken it.** The test asserts an empty canonical roster-v2 `socket_name` must be rejected; production currently does not. ### Scheduling Prod-fix lane is **PARKED** for the Opus window (Opus quota-blocked until 2026-07-23; SECREV tier not downgradable). At Jul-23: one bounded lane — builder authors the `roster-v2.ts` fix + red-first regression → independent CODE → OPUS SECREV → exact-head CI green → named-executor merge → then the FCM-M3-002 test refresh rides green on top. **Blocks:** FCM-M3-002 (#758 sub-gate). Cross-ref #758.
Author
Owner

Supersedes #794 (allow-empty proposal, provenance PR#793) — contract reversed on socket-boundary security grounds.

#794 was closed superseded-by-#854 with its title/body/PR#793 provenance retained unchanged. #794 (Low) proposed accepting a literal-empty socket_name; the 3-source analysis @ main 11d2818 established the socket-boundary/isolation impact (empty→default-socket collapse→cross-session risk), reversing the contract to reject-empty (medium/security). Bidirectional audit trail established.

**Supersedes #794** (allow-empty proposal, provenance PR#793) — contract **reversed on socket-boundary security grounds**. #794 was closed **superseded-by-#854** with its title/body/PR#793 provenance retained unchanged. #794 (Low) proposed accepting a literal-empty `socket_name`; the 3-source analysis @ main `11d2818` established the socket-boundary/isolation impact (empty→default-socket collapse→cross-session risk), reversing the contract to reject-empty (medium/security). Bidirectional audit trail established.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#854