Skip to content

fix(desktop): frame each tmux format record so a newline in a field cannot forge a pane - #8725

Merged
waleedlatif1 merged 3 commits into
stagingfrom
fix/desktop-tmux-format-framing
Oct 7, 2026
Merged

waleedlatif1 merged 3 commits into
stagingfrom
fix/desktop-tmux-format-framing

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • tmux prints a newline inside a -F field as is. Suppose a pane's working directory (or its window title, or its command's name) holds a newline followed by separator-joined text, such as a + newline + user:0.0<~sim~>forged<~sim~>rm -rf<~sim~>home.
  • Its own record then ends early, and the rest reads as a whole pane of its own: any target, command and path. Meanwhile the real pane drops out of panes.
  • That lets a crafted directory name misattribute pane targets. The pane argument then sends input to, or closes, the wrong pane.
  • The fix, in two layers:
    • Newlines are neutralised at the source. In the fields someone other than the user can set, tmux replaces each newline with <NL> itself (#{s/<newline>/<NL>/:…}). Those fields are the pane's directory, its command's name, and the window title a program sets with an escape sequence. A record is then always one line.
      • Session names stay as they are: users name their own sessions, and a record a newline would split is dropped by the frame.
    • Each record is framed per call. Every -F read (list-clients, list-panes, and the active-pane lookup) wraps each record in a marker made fresh for that call, and only lines framed whole are read.
      • The marker is not a secret. On macOS ps shows any process's arguments, and on Linux /proc/<pid>/cmdline is world-readable. So the marker is a second line of defence for fields tmux prints raw, not the protection itself.
  • The separator comment now describes this model.
  • tmux output is decoded as a stream, so a character split across two chunks arrives whole.

Type of Change

  • Bug fix

Testing

  • Real tmux 2.9a and 3.4:
    • Output captured verbatim for the forging directory: without neutralisation the forged rm -rf row is read; with it, the pane is one line and nothing is forged.
    • listPanes returns nothing for the forging session, and a directory holding just a newline lists as one pane with <NL> in its path.
    • activePane still resolves.
  • Unit tests, each failing when its guard is undone:
    • a fake tmux that evaluates formats as tmux does lists a pane whose directory and title hold newlines as one pane;
    • two calls are framed with different markers;
    • a line framed at one end only is dropped, even when it has the right field count;
    • a record framed by another call is dropped.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…annot forge a pane

tmux prints a newline inside a `-F` field as is. A pane whose working
directory (or window name, or session name) held a newline followed by
separator-joined text ended its own record early and forged another: any
target, command and path, while the real pane disappeared from `panes`.

Every `-F` read (list-clients, list-panes, the active pane) now frames each
record with a marker made fresh for that call, and only lines framed whole by
it are read. Nobody outside the call knows the marker, so no field can forge a
record, and the halves of a record a newline split are each dropped.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@vercel

vercel Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
docs Skipped Skipped Oct 7, 2026 6:22am UTC

Request Review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 2 files

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Turn on auto-fix | Re-trigger cubic

Comment thread apps/desktop/src/main/terminal/tmux.ts Outdated
@greptile-apps

greptile-apps Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[Medium risk] Fixes tmux pane parsing to prevent forged records from newlines.

The PR appears safe to merge; no new actionable issue was found.

What we checked:

  • Format text stays outside HTML: untrusted receives fixed field names. listPanes sends the resulting string to tmux as a format argument, not to browser HTML.

Summary

The PR frames tmux records with a fresh marker so text inside a field cannot be mistaken for another pane.

  • The latest changes replace newlines in pane titles, commands, and paths with <NL>.
  • runTmux now decodes UTF-8 across chunks without breaking characters.
  • Tests add captured output and checks for incomplete frames and newline-containing fields.
  • The earlier randomness-helper finding is fixed: framedFormat uses generateRandomHex(16).
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Fields[Pane fields] --> Replace[Replace newlines with NL marker]
  Replace --> Frame[Add fresh frame around each record]
  Frame --> Tmux[tmux output]
  Tmux --> Check{Both frames and correct field count?}
  Check -->|Yes| Pane[Return pane]
  Check -->|No| Drop[Drop line]
Loading

Reviews (3) · Last reviewed commit: "fix(desktop): neutralise newlines at the..." · Reviewed by Greptile

Comment thread apps/desktop/src/main/terminal/tmux.ts Outdated
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 2 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Turn on auto-fix | Re-trigger cubic

… can set

The per-call frame is not a secret: on macOS `ps` shows any process's
arguments, and on Linux `/proc/<pid>/cmdline` is world-readable, so someone
who owns the directory a pane sits in can read the frame and rename the
directory before tmux reads it.

tmux now replaces each newline with `<NL>` itself (`#{s/\n/<NL>/:…}`) in the
fields someone other than the user can set: the pane's directory, its
command, and the window title a program sets. A record is then one line, and
the frame stays as a second line of defence. tmux output is also decoded as a
stream, so a character split across two chunks arrives whole.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 2 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Turn on auto-fix | Re-trigger cubic

@waleedlatif1
waleedlatif1 merged commit 566cea6 into staging Oct 7, 2026
36 of 37 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/desktop-tmux-format-framing branch October 7, 2026 07:15

This branch was previously deployed

1 inactive deployment
Preview — da5007aa Deployed Oct 7, 2026 by vercel[bot]
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.

1 participant