Skip to content

feat(bridge): vendor smux tmux-bridge as layer-2 agent comms#256

Open
lroolle wants to merge 1 commit intomainfrom
feat/smux-tmux-bridge
Open

feat(bridge): vendor smux tmux-bridge as layer-2 agent comms#256
lroolle wants to merge 1 commit intomainfrom
feat/smux-tmux-bridge

Conversation

@lroolle
Copy link
Copy Markdown
Member

@lroolle lroolle commented Apr 14, 2026

What

Vendor upstream smux tmux-bridge (github.com/ShawnPana/smux, MIT) as the
layer-2 agent-to-agent communication CLI inside deva container images. Sits
alongside the existing deva-bridge-tmux (layer 1, socat TCP tunnel to host
tmux server). Zero touches to deva.sh, auth wiring, or docker-entrypoint.sh.

Layer 1  deva-bridge-tmux       kernel boundary, socat TCP
         container tmux client -> host tmux server
         (existing, shipped)

Layer 2  tmux-bridge             semantic CLI
         read/type/keys/label/envelope/doctor + read-before-act guard
         (THIS PR, vendored byte-for-byte from smux@95bf0b6)

Why

The deva-v2 proposal (docs/devlog/260401-deva-v2-proposal.org) left the
agent-to-agent transport CLI as an open design question. Upstream smux shipped
almost exactly the primitives we sketched (list/read/type/keys/label + text
envelopes) in 403 lines of bash, MIT-licensed. Reinventing it would be waste.
Adopting it unblocks experiments on top (layer 3: coordinator/router,
scratchpad, state detection) without us having to own the transport layer.

The piece smux does not cover - the container-to-host kernel boundary - is
already solved by our existing deva-bridge-tmux. The two layers compose
cleanly: once the socat tunnel is up, TMUX_BRIDGE_SOCKET=/tmp/host-tmux.sock
lets tmux-bridge drive panes on the host tmux server from inside the
container.

What is in the commit

  • scripts/tmux-bridge (new, 403 lines, byte-identical to upstream commit
    95bf0b639e64a4c67b4f007b1bedc26395344e01, SHA256 ed66862b...)
  • scripts/tmux-bridge.VENDORED (new, provenance + refresh instructions)
  • scripts/THIRD_PARTY_LICENSES/smux-LICENSE (new, upstream MIT)
  • Dockerfile: COPY + chmod tmux-bridge into /usr/local/bin/ (4 lines)
  • docs/tmux-bridge-agent-comms.md (new, 85 lines): two-layer composition,
    security model, socket detection priority, read-before-act guard semantics,
    quick start, provenance
  • .github/workflows/ci.yml: new "Smoke tmux-bridge CLI surface" step under
    the existing smoke job. Builds an ephemeral tmux server inside the image,
    exercises list/name/resolve/read/type, and asserts the read-guard blocks
    a second type without re-reading.
  • CHANGELOG.md: [Unreleased] Added section
  • DEV-LOGS.md: dated entry covering the why/what/result

Test plan

Verified locally against real tmux 3.6a (same version container ships):

  • shellcheck -S error scripts/tmux-bridge scripts/deva-bridge-tmux scripts/deva-bridge-tmux-host -> clean (matches CI severity)
  • tmux-bridge version -> tmux-bridge 2.0.0
  • tmux-bridge --help -> contains "cross-pane communication"
  • tmux-bridge id outside tmux -> errors cleanly
  • tmux-bridge list against ephemeral tmux server -> shows smoke:0 pane
  • tmux-bridge name <pane> smoke-worker + resolve smoke-worker -> round-trip works
  • tmux-bridge read <target> 5 -> succeeds, sets guard
  • tmux-bridge type smoke-worker "echo hi" after read -> succeeds
  • tmux-bridge type smoke-worker "echo twice" without re-read -> fails with "must read the pane before interacting" (guard works)
  • CI smoke step reproduces all of the above against the built container image

Security

Both layers are privileged host bridges. If the host tmux bridge is running
and an agent in the container drives tmux-bridge, it can send-keys,
run-shell, and read scrollback on the host tmux server - effectively a
sandbox escape, which is the deliberate tradeoff for trusted dev workflows.
Documented loudly in docs/tmux-bridge-agent-comms.md and unchanged from the
existing deva-bridge-tmux trust model.

Non-goals

  • Layer 3 (coordinator/router with text envelopes, agent state detection,
    scratchpad) is tracked as an open design in
    docs/devlog/260401-deva-v2-proposal.org and explicitly out of scope here.
    This PR is additive transport only.
  • No changes to auth, docker-entrypoint, or the container lifecycle.

- scripts/tmux-bridge: byte-identical copy from smux commit 95bf0b6
  (github.com/ShawnPana/smux, MIT). 403-line bash CLI for cross-pane
  comms: list, read, type, keys, message, name, resolve, doctor.
- Read-before-act guard via /tmp/tmux-bridge-read-<pane_id> sentinel
  prevents agents from blindly writing to panes they have not inspected.
- Installed at /usr/local/bin/tmux-bridge in container images, sits
  alongside existing deva-bridge-tmux (layer 1 socat TCP tunnel).
- Provenance pinned in scripts/tmux-bridge.VENDORED (upstream commit +
  SHA256 ed66862b...); upstream MIT license shipped in
  scripts/THIRD_PARTY_LICENSES/smux-LICENSE.
- docs/tmux-bridge-agent-comms.md explains two-layer composition,
  security model, socket detection order, and read-guard semantics.
- CI smoke step builds an ephemeral tmux server inside the image and
  exercises the full CLI surface (list/name/resolve/read/type) plus a
  negative assertion on the read-guard.
- Zero touches to deva.sh, auth, or docker-entrypoint.sh; purely
  additive layer-2 adoption.
Copilot AI review requested due to automatic review settings April 14, 2026 15:26
@claude-yolo
Copy link
Copy Markdown
Contributor

claude-yolo bot commented Apr 14, 2026

Claude finished @lroolle's task in 2m 35s —— View job


Security Audit of tmux-bridge Integration

Performing paranoid security audit focusing on container boundaries, auth flows, shell entrypoints, privilege escalation, and permission bypasses.

Todo List

  • Read and analyze the main tmux-bridge script
  • Review Dockerfile changes and container integration
  • Analyze documentation for security model claims
  • Examine CI test coverage for security scenarios
  • Validate vendoring provenance and integrity (SHA256 matches: ed66862b...)
  • Perform line-by-line shell injection analysis
  • Check for privilege escalation vectors
  • Assess input sanitization and validation
  • Enumerate findings and risk levels
  • Provide final security assessment and recommendations

Critical Security Findings

🚨 BLOCKING ISSUES

  1. Directory Traversal in read_guard_path() (Line 15-19)

    • Pane ID sanitization only replaces % with _
    • Allows ../ directory traversal: %1/../../../etc/passwd_1/../../../etc/passwd
    • Could write/read arbitrary files in filesystem
    • Impact: Container escape via file system access
  2. Insufficient Input Validation in resolve_target() (Line 145-165)

    • Target validation only checks basic patterns
    • Targets with : or . are passed through without validation
    • No length limits or character restrictions
    • Impact: Command injection via tmux targets
  3. Environment Variable Injection in tmx() (Line 103-109)

    • TMUX_SOCKET from TMUX_BRIDGE_SOCKET env var passed directly to tmux -S
    • No validation of socket path
    • Attacker can point to arbitrary files, special devices (/dev/tcp/, /dev/stdin)
    • Impact: Full container compromise via malicious socket

⚠️ HIGH RISK ISSUES

  1. Potential Command Injection in cmd_type/message/keys

    • User input passed to tmux send-keys with minimal validation
    • While -l flag should be literal, still large attack surface
    • Race conditions between validation and execution
    • Impact: Arbitrary command execution in target panes
  2. Unsafe Temporary File Handling

    • Read guard files created in /tmp/tmux-bridge-read-* with world-readable permissions
    • No atomic operations, prone to race conditions
    • Could be exploited for TOCTOU attacks
    • Impact: Guard bypass, unauthorized pane access
  3. Missing Authentication on Socket Access

    • No verification that detected/provided socket is safe to use
    • Could connect to unintended tmux servers
    • Impact: Unauthorized access to other users' tmux sessions

⚠️ MEDIUM RISK ISSUES

  1. Shell Expansion in Socket Detection (Line 62-84)

    • Uses shell glob patterns on potentially attacker-controlled paths
    • Could be exploited if filesystem is compromised
    • Impact: Denial of service, unexpected behavior
  2. Information Disclosure in Error Messages

    • Error messages leak internal paths and environment details
    • Could aid in reconnaissance for further attacks
    • Impact: Information leakage

Assessment Summary

RECOMMENDATION: DO NOT MERGE without addressing blocking issues.

This PR introduces a 403-line bash script with multiple serious security vulnerabilities. While the PR description acknowledges this is a "privileged host bridge" and "sandbox escape," the implementation has exploitable flaws that go beyond the intended design:

Design vs Implementation:

  • Intended: Controlled bridge for agent communication via tmux
  • Actual: Multiple uncontrolled paths for container escape and privilege escalation

Critical Attack Scenarios:

  1. Container Escape: Via directory traversal in read guard paths
  2. Host Compromise: Via malicious socket environment variables
  3. Lateral Movement: Via insufficient target validation and command injection

Required Security Fixes

Before merge, fix blocking issues:

  1. Harden read_guard_path(): Use basename, validate against whitelist
  2. Validate socket paths: Check realpath, ensure in expected locations
  3. Strengthen target validation: Regex validation, length limits, character restrictions
  4. Secure temp files: Use mktemp, proper permissions, atomic operations

Additional Recommendations:

  • Add capability-based access controls
  • Implement audit logging for all tmux operations
  • Consider sandboxing the bridge itself (separate container, limited capabilities)
  • Add fuzz testing for input validation

Testing Requirements:

  • Security-focused integration tests with malicious inputs
  • Privilege escalation test scenarios
  • Container escape validation

The CI smoke tests are insufficient for security validation - they only test happy path functionality.

Context Notes

  • Architecture: The two-layer bridge design (socat + CLI) is reasonable
  • Vendoring: Proper provenance tracking and SHA256 validation ✅
  • Documentation: Security model clearly stated, but implementation doesn't match
  • Container Integration: Standard Dockerfile practices ✅

This code requires a security-focused rewrite of input validation before production use.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3a2276d240

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/tmux-bridge
Comment on lines +15 to +19
read_guard_path() {
local pane_id="$1"
# Sanitize: %66 → _66
echo "/tmp/tmux-bridge-read-${pane_id//%/_}"
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Scope read guard by tmux socket

The read-before-act sentinel is keyed only by pane_id (/tmp/tmux-bridge-read-...), but pane IDs are reused across different tmux servers. Because detect_socket chooses the server per invocation, a read against server A can leave a guard file that lets type/message/keys proceed against server B with the same %N without any read on B. In environments where both local and bridged host tmux servers are reachable, this defeats the safety guarantee and can send commands to an unseen pane.

Useful? React with 👍 / 👎.

Comment thread scripts/tmux-bridge
Comment on lines +170 to +171
result=$(tmx list-panes -a -F '#{pane_id} #{@name}' 2>/dev/null \
| awk -v lbl="$label" '$2 == lbl { print $1; exit }')
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Parse labels without whitespace splitting

resolve_label formats output as "#{pane_id} #{@name}" and matches with awk '$2 == lbl', so labels containing spaces are split and never match the full label string. Since name currently accepts arbitrary label text, users can create labels (for example, "worker one") that cannot be resolved by resolve, read, type, or message until renamed.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Vendors upstream smux’s tmux-bridge bash CLI into the deva container image as a “layer-2” agent-to-agent communication tool over tmux panes, designed to compose with the existing “layer-1” deva-bridge-tmux host tunnel.

Changes:

  • Add vendored scripts/tmux-bridge plus provenance + third-party license files.
  • Install tmux-bridge into the container image and document the two-layer bridge composition and safety model.
  • Extend CI with a smoke test that exercises the tmux-bridge CLI against an ephemeral tmux server inside the built image.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
scripts/tmux-bridge Vendored layer-2 tmux pane communication CLI with socket detection + read-before-act guard.
scripts/tmux-bridge.VENDORED Vendoring provenance (upstream commit + SHA256) and refresh instructions.
scripts/THIRD_PARTY_LICENSES/smux-LICENSE MIT license text for the vendored upstream script.
docs/tmux-bridge-agent-comms.md Explains layer-1/layer-2 composition, security model, socket detection, and guard semantics.
Dockerfile Copies tmux-bridge into /usr/local/bin and marks it executable.
.github/workflows/ci.yml Adds a smoke step validating installed CLI surface + guard behavior.
CHANGELOG.md Records the addition under [Unreleased].
DEV-LOGS.md Adds a devlog entry describing motivation, contents, and outcome.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


What it is:
- tmux-bridge is a 403-line bash CLI for cross-pane communication between
AI agents running in tmux. Read/type/keys/label/envelope primitives.
Comment thread scripts/tmux-bridge
Comment on lines +15 to +18
read_guard_path() {
local pane_id="$1"
# Sanitize: %66 → _66
echo "/tmp/tmux-bridge-read-${pane_id//%/_}"
socat TCP tunnel via host.docker.internal:41555

Layer 2 tmux-bridge semantic CLI
(scripts/tmux-bridge) read/type/keys/label/envelope
Comment thread CHANGELOG.md
## [Unreleased]

### Added
- `scripts/tmux-bridge` vendored from upstream smux (commit 95bf0b6, MIT) for layer-2 agent-to-agent communication over tmux panes: read/type/keys/label/envelope/doctor
Comment thread DEV-LOGS.md
- Reference issue numbers in the format `#<issue-number>` for easy linking.

# [2026-04-13] Dev Log: adopt smux tmux-bridge as layer-2 agent comms
- Why: deva-v2 proposal left the agent-to-agent transport CLI as an open question; smux (github.com/ShawnPana/smux) shipped exactly the shape we sketched (read/type/keys/label/envelope) in 403 lines of bash, MIT-licensed. Reinventing it would be waste. The existing `deva-bridge-tmux` (socat TCP) is layer 1 (kernel boundary); `tmux-bridge` is layer 2 (semantic). They compose cleanly.
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.

2 participants