Skip to content

v0.16.5

Choose a tag to compare

@github-actions github-actions released this 12 Aug 08:30
· 537 commits to main since this release

Three attach-triggered vulnerabilities, all live in 0.16.4 and all reachable from a hostile clone. If you use plumb on repositories you did not write, upgrade.

Full detail for every item is in CHANGELOG.md — this is the readable summary.

Security

All three are triggered by attaching a session to a repository. No tool call is needed, and nothing in the repository looks unusual — the payload is a committed symlink or a committed file.

  • A cloned repository could delete directories anywhere you can write. transaction_apply keeps a write-ahead log under <workspace>/.plumb/tx-log/, and txlog.Scan walks it on every attach and re-pin to roll back orphans. That path is an ordinary directory inside the workspace, so a repository can ship it — as a symlink. Scanning followed it out of the workspace and cleaned up what it found there. No manifest was required.
  • A cloned repository could write a file anywhere you can write, with mode bits of its choosing. Same scan, via a committed orphan manifest: the rollback wrote the manifest's recorded content to the manifest's recorded path, neither of which was confined to the workspace.
  • A committed symlink plus .. defeated the workspace boundary outright. Every boundary check ran filepath.Abs first, which cancels sub/.. lexically before any link is resolved; the kernel does the opposite, following sub and then applying .. to wherever that landed. When sub is a symlink out of the workspace the two readings name different files, and the syscall received the same uncleaned text the check had approved. Measured against the real tools: write_file wrote outside every allowed root, read_file disclosed the target, find_files listed it. One committed sub -> / made the whole filesystem addressable as in-workspace. Such a path is now refused rather than cleaned — cleaning it would keep every call working while silently retargeting it to a different file than the caller named.
  • Four more project-config fields that could soften a global safety setting are now covered by the trust gate.

Changed

  • Kotlin moves to JetBrains' kotlin-lsp and is promoted out of experimental. Note the macOS quarantine step in docs/adding-an-lsp.md — macOS silently deletes the unsigned server binary on first run unless it is cleared.
  • [collab]'s channel switches are gated on plumb trust instead of being forced global-only. 0.16.4 closed a real hole by making them global-only, but that also removed per-workspace chat settings entirely. Trust separates the two questions: settings can vary per workspace, while the user — not the repository — decides whether this repository's settings are honoured.
  • Per-root language-server state directories are a table rather than a special case.

Fixed

  • Two live sessions can no longer share a name, so a mailbox address always reaches the session it names. A name is an address: notes are stored and notified by the name string, so a duplicate silently misdelivered.
  • A tool added by a daemon rebuild is no longer invisible to already-connected clients. The tool list is fetched once at connect, and plumb serve is a reconnecting proxy — so from the client's side the server never goes away and never re-lists. The proxy now emits notifications/tools/list_changed after a reconnect. This is the case plumb's own dev loop hits constantly: rebuild the daemon under a live agent session and the new tool was unusable until the client restarted.

Install: brew install plumbkit/plumb/plumb, or grab a binary below (macOS and Linux, arm64 and amd64). Existing Homebrew users: brew update && brew upgrade plumb.