Skip to content

Record the Windows peer-link pipe squat as not defended - #1241

Merged
nedtwigg merged 6 commits into
mainfrom
peer-pipe-token-name
Oct 20, 2026
Merged

nedtwigg merged 6 commits into
mainfrom
peer-pipe-token-name

Conversation

@nedtwigg

@nedtwigg nedtwigg commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Documents a Windows limit of the VS Code peer link.

Every VS Code window of an installation contends for one fixed path, and the bind elects the window that runs the Burrow. On unix that path sits in a per-user 0700 directory (peerDirIsSafe), so no other account can create it first. On Windows the path is a named pipe in a machine-wide namespace, derived from the extension's storage path. Another account can create that pipe first. The token handshake still serves it nothing, but every window's bind then fails and VS Code's remote control and peer surfaces stay down.

Keying the name by the shared token does not close this. Windows lists every pipe to every account, and because the token and storage path are permanent, the keyed name stays fixed once a broker first binds it. Closing the gap needs a name that is unpredictable on every bind, which bind-as-lease cannot provide as it works today, so it is recorded instead:

  • docs/specs/security.md → "What is not defended": a new entry next to the Windows dor pipe one (word budget ratcheted to 2650).
  • docs/specs/vscode.md → "Trust": the Windows line now points at that entry instead of saying named pipes "carry their own ACL".

The first commit tried a token-keyed name with a compatibility listener for older builds; the second restores the path-only name. Net diff: docs only.

🤖 Generated with Claude Code

On Windows the pipe every VS Code window contends for was named from the
extension's storage path alone, in the machine-wide pipe namespace, so
another local user could compute it and create it first; every window's
bind then failed and the peer link and remote control stayed down.

The name is now an HMAC over the storage path keyed by the peer token.
A Windows broker also listens on the path-only name older builds bind,
and a window that wins the keyed pipe while an older build's broker holds
that name joins it as a client, so the two builds share one broker during
an update. Unix paths are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Deploying mouseterm with  Cloudflare Pages  Cloudflare Pages

Latest commit: f186f5c
Status: ✅  Deploy successful!
Preview URL: https://30e3fb00.mouseterm.pages.dev
Branch Preview URL: https://peer-pipe-token-name.mouseterm.pages.dev

View logs

@dormouse-bot dormouse-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The keyed name protects only until the first bind. Every user on the machine can list the Windows pipe namespace (Get-ChildItem \\.\pipe\, Sysinternals pipelist). While a broker runs, dormouse-peer-<key> is visible in that list. The key never changes, because the token and storage path are permanent, so whoever reads the name once can create the pipe whenever the broker window closes, and again after every reboot. The squat this PR targets still works against anyone who checks the list. What the PR adds to get there is the keyed derivation plus a permanent second listener for older builds, joinLegacyBroker, which no CI job runs.

Before adding more machinery to close that gap, consider the smaller option. Record the peer-pipe squat as a Windows known gap next to the dor pipe entry in docs/specs/security.md → "What is not defended", and keep the path-only name. If the hardening is worth having, it needs a name that is unpredictable on each bind rather than one that is secret only until someone looks. That breaks bind-as-lease as it works today, so it is a design decision for a maintainer.

If the PR goes ahead as written, the Windows-only parts have never run. The Standalone Platform Check (windows-latest) job in .github/workflows/ci.yml runs no vscode-ext tests, and the new derivedSocketPath breaks two existing tests on Windows (inline). Adding pnpm --dir vscode-ext exec vitest run test/peer-link.test.ts to that job would show whether the three new skipIf tests pass. I haven't run these on Windows. The test claims come from reading the code, and the enumeration claim relies on documented Windows behavior.

Comment thread vscode-ext/src/peer-link.ts Outdated
Comment thread vscode-ext/test/helpers.ts Outdated
… path-only name

Windows lists every pipe to every account, so a token-keyed name is
secret only until a broker first binds it, and from then on it is fixed.
It adds a second listener for older builds without closing the squat.
Restore the path-only name and record the squat next to the `dor` pipe
entry in security.md "What is not defended".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nedtwigg nedtwigg changed the title Key the Windows peer-link pipe name by the shared token Record the Windows peer-link pipe squat as not defended Oct 20, 2026

@dormouse-bot dormouse-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The vscode.md edit removes the claim that Windows named pipes "carry their own ACL", but the code comment that rule came from still says it. The doc comment on peerDirIsSafe() in vscode-ext/src/peer-link.ts reads "Windows named pipes are not filesystem objects and carry their own ACL, so there is nothing here for them to check." The next reader of the win32 early return will take that as a reason the skip is safe, which is the opposite of the new security.md entry. It is outside the diff, so I can't attach a suggestion. Rewording it to match, for example "Windows named pipes are not filesystem objects, so there is no directory here to check; the squat this leaves open is recorded in docs/specs/security.md → "What is not defended".", would close it. I can push that as a commit if you'd like.

nedtwigg and others added 2 commits October 20, 2026 09:05
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nedtwigg

Copy link
Copy Markdown
Member Author

Agreed. The peerDirIsSafe() doc comment no longer says Windows pipes "carry their own ACL"; it now says there is no directory to check and points at the security.md entry, in 6ba37ae.

@nedtwigg
nedtwigg merged commit 11b73ca into main Oct 20, 2026
14 checks passed
@nedtwigg
nedtwigg deleted the peer-pipe-token-name branch October 20, 2026 16:38

This branch is waiting to be deployed

1 waiting deployment
hosted-preview — f186f5c7 Waiting Oct 20, 2026 by nedtwigg via cleanup #1685
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