harden: reject whitespace-only tmux socket_name in roster-v2 (silently selects default server) #794

Closed
opened 2026-07-16 20:01:19 +00:00 by jason.woltje · 1 comment
Owner

Summary

requiredTmuxSocket() in packages/mosaic/src/fleet/roster-v2.ts trims socket_name before
validating it against a permissive regex that accepts the empty string, so a whitespace-only value
(e.g. socket_name: " ") is normalized to "" and silently selects the operator's default tmux
server instead of being rejected.

Detail (on main)

const TMUX_SOCKET_IDENTIFIER = /^[A-Za-z0-9_.-]*$/;   // '*' → empty string matches

function requiredTmuxSocket(value, label) {
  if (typeof value !== 'string') throw new RosterV2ValidationError(...);
  const result = value.trim();                         // " " → ""
  if (!TMUX_SOCKET_IDENTIFIER.test(result)) throw ...; // "" passes
  return result;                                        // returns ""
}

Consumption confirms the impact — comms-onboarding.ts:

if (rosterSocket) parts.push('-L', shellArg(rosterSocket));  // "" is falsy → -L omitted → default server

and the intended contract is explicit in tests: "omits -L only for the literal default socket."

So a whitespace-only socket_name bypasses the "explicit decision to use the default server" and can
point fleet tmux operations (message/session/runtime) at an unintended shared namespace.

Severity

Low. Requires an operator to hand-author a whitespace-only socket_name; no privilege escalation. This
is input-validation hardening, not an active exploit. (Flagged by an automated Codex pass whose
"medium/blocker" rating is inflated for this path.)

Proposed fix

  • Accept an empty socket only when the source string was exactly empty; reject any non-empty value
    whose trimmed form differs from the source (i.e. reject whitespace-only and whitespace-padded values).
  • Add YAML + JSON parser tests for whitespace-only and whitespace-padded socket_name, asserting
    RosterV2ValidationError.

Provenance

Surfaced as a byproduct of an independent review; pre-existing on main, not introduced by any
open PR (noted during PR #793 review, which it does not belong to). Filed to preserve the finding.

## Summary `requiredTmuxSocket()` in `packages/mosaic/src/fleet/roster-v2.ts` trims `socket_name` before validating it against a **permissive** regex that accepts the empty string, so a whitespace-only value (e.g. `socket_name: " "`) is normalized to `""` and silently selects the operator's **default** tmux server instead of being rejected. ## Detail (on `main`) ``` const TMUX_SOCKET_IDENTIFIER = /^[A-Za-z0-9_.-]*$/; // '*' → empty string matches function requiredTmuxSocket(value, label) { if (typeof value !== 'string') throw new RosterV2ValidationError(...); const result = value.trim(); // " " → "" if (!TMUX_SOCKET_IDENTIFIER.test(result)) throw ...; // "" passes return result; // returns "" } ``` Consumption confirms the impact — `comms-onboarding.ts`: ``` if (rosterSocket) parts.push('-L', shellArg(rosterSocket)); // "" is falsy → -L omitted → default server ``` and the intended contract is explicit in tests: *"omits -L only for the literal default socket."* So a whitespace-only `socket_name` bypasses the "explicit decision to use the default server" and can point fleet tmux operations (message/session/runtime) at an unintended shared namespace. ## Severity Low. Requires an operator to hand-author a whitespace-only `socket_name`; no privilege escalation. This is input-validation hardening, not an active exploit. (Flagged by an automated Codex pass whose "medium/blocker" rating is inflated for this path.) ## Proposed fix - Accept an empty socket only when the source string was **exactly** empty; reject any non-empty value whose trimmed form differs from the source (i.e. reject whitespace-only and whitespace-padded values). - Add YAML + JSON parser tests for whitespace-only and whitespace-padded `socket_name`, asserting `RosterV2ValidationError`. ## Provenance Surfaced as a byproduct of an independent review; **pre-existing on `main`**, not introduced by any open PR (noted during PR #793 review, which it does not belong to). Filed to preserve the finding.
Author
Owner

Superseded by #854 — contract REVERSED on socket-boundary security grounds

Closing as superseded-by-#854 (NOT a generic duplicate). This issue's title/body and PR#793 provenance are preserved unchanged for the audit trail.

Reversal rationale (Mos ruling, Option B): #794 (2026-07-16, Low) proposed to ACCEPT a literal-empty socket_name, rejecting only whitespace-only/padded values. Today's 3-source primary analysis @ main 11d281845376eb5910a74403300956d8edcc93a8 (builder ms-m3002-build + MS-LEAD + homelab W-jarvis) identified the tmux socket-BOUNDARY / session-isolation impact that #794 did not weigh: an empty socket_name collapses to the operator's default tmux socket → cross-session boundary risk. That REVERSES the contract to REJECT-empty (re-rated medium / security).

The FCM-M3-002 acceptance test (packages/mosaic/src/fleet/fleet-reconciler.acceptance.spec.ts) encodes reject-empty and is endorsed CORRECT — it must not be weakened.

Canonical tracker + exact fix spec (*+ L276, minLength:1 schema L176, msg align L480) + parked Jul-23 Opus-SECREV sequence: #854. Provenance retained here.

### Superseded by #854 — contract REVERSED on socket-boundary security grounds Closing as **superseded-by-#854** (NOT a generic duplicate). This issue's title/body and PR#793 provenance are preserved **unchanged** for the audit trail. **Reversal rationale (Mos ruling, Option B):** #794 (2026-07-16, Low) proposed to **ACCEPT a literal-empty** `socket_name`, rejecting only whitespace-only/padded values. Today's **3-source primary analysis** @ main `11d281845376eb5910a74403300956d8edcc93a8` (builder `ms-m3002-build` + MS-LEAD + homelab W-jarvis) identified the tmux **socket-BOUNDARY / session-isolation** impact that #794 did not weigh: an empty `socket_name` collapses to the operator's **default** tmux socket → **cross-session boundary risk**. That **REVERSES** the contract to **REJECT-empty** (re-rated **medium / security**). The FCM-M3-002 acceptance test (`packages/mosaic/src/fleet/fleet-reconciler.acceptance.spec.ts`) encodes reject-empty and is endorsed **CORRECT** — it must not be weakened. Canonical tracker + exact fix spec (`*`→`+` L276, `minLength:1` schema L176, msg align L480) + parked Jul-23 Opus-SECREV sequence: **#854**. Provenance retained here.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#794