Repository navigation
Record the Windows peer-link pipe squat as not defended - #1241
Conversation
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>
Deploying mouseterm with
|
| Latest commit: |
f186f5c
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://30e3fb00.mouseterm.pages.dev |
| Branch Preview URL: | https://peer-pipe-token-name.mouseterm.pages.dev |
dormouse-bot
left a comment
There was a problem hiding this comment.
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.
… 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>
dormouse-bot
left a comment
There was a problem hiding this comment.
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.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Agreed. The |
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
0700directory (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 Windowsdorpipe 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