security: authenticate the V1 pipe surface and hook.event/agent.activity (fixes #72) - #73
Merged
Merged
Conversation
…ivity (amirlehmam#72) Any local process could previously spoof agent status, notifications, and diff refreshes through three tokenless paths: all V1 text commands, hook.event, and agent.activity. The legitimate senders (shell integration, Claude Code hooks, the CLI) all run inside wmux-spawned shells and already carry WMUX_PIPE_TOKEN, so tokenless access only benefited processes that were never supposed to write state. - Trim PUBLIC_V2_METHODS to the read-only system.identify / system.capabilities; hook.event and agent.activity now authenticate like every other V2 method. - Require an "auth <token>" prefix on V1 lines; only the read-only ping stays public. Unauthenticated V1 state updates get "unauthorized" and are not forwarded to renderers. - Send the prefix from the CLI sendV1 and the PowerShell integration (prompt reporting + the PR-polling background job). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Owner
|
Merged and released in v0.17.0 — thank you for a genuinely well-scoped security PR. What I especially appreciated on review: the allowlist got smaller instead of the auth getting bolted on per-method, the PowerShell integration's background PR-poller job was not forgotten (easy to miss — it opens its own pipe connection), and the tests cover the exact spoofing scenario from the issue ( The ownership check on |
tawman
added a commit
to tawman/wmux
that referenced
this pull request
Jul 7, 2026
Syncs the fork with upstream master (release v0.17.0) — the first sync carrying third-party code, security-gate reviewed before merge (PASS): - amirlehmam#73 (Rajveerx11) pipe auth — security-positive: V1 commands now require an "auth <token>" prefix (ping stays public) and hook.event/agent.activity leave the tokenless V2 allowlist; timing-safe compare reused, clients (CLI sendV1, PowerShell integration) updated coherently, +4 auth tests. Closes the unauthenticated-local-pipe-write gap our own review flagged. - amirlehmam#74 + maintainer CI commits — SignPath signing wired behind secrets (only egress is app.signpath.io with the repo's own secrets; inert on the fork), publisherName pinned via win.signtoolOptions, README updater-security docs, asarUnpack narrowed to node-pty prebuilds. - Our merged amirlehmam#75 content (cli-bin OOTB, orchestrator resolver, skills lessons) arrives as no-ops; electron-builder cli-bin extraResources lands. - No dependency changes (lock diff = version fields only). Base bump 0.16.0 -> 0.17.0; fork version resets to 0.17.0-local.1. Conflicts resolved: version files; .gitattributes (fork superset); README.md + orchestration-state.sh (fork copies kept — hardening superset). Fork CI repo-guard on release.yml survived the auto-merge (verified). Verified: build:main + vite build clean, 169/169 tests, 0 vulns (full + --omit=dev), security-touched files byte-identical to upstream.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #72.
Any local process could spoof agent status, notifications, and diff refreshes through three tokenless pipe paths: every V1 text command,
hook.event, andagent.activity. Since wmux already injectsWMUX_PIPE_TOKENinto every shell it spawns, all legitimate telemetry senders (shell integration, Claude Code hooks, the CLI, the opencode plugin via the CLI) already have the token — keeping these paths tokenless only benefited processes that were never supposed to write state.Changes
src/main/pipe-server.tsPUBLIC_V2_METHODStrimmed to the two genuinely read-only methods (system.identify,system.capabilities).hook.eventandagent.activitynow require the per-instance token like every other V2 method.auth <token>prefix (validated with the existing timing-safetokensMatch). All V1 commands mutate UI state (notify,report_pwd,report_pr, shell state, …), so every command except the read-onlypingnow requires it. Unauthenticated lines getunauthorizedback and are not forwarded to renderers.src/cli/wmux.ts—sendV1prepends the auth prefix (token already resolved fromWMUX_PIPE_TOKEN/ the APPDATA token file).src/shell-integration/wmux-powershell-integration.ps1—Send-WmuxMessageprepends the prefix, and the PR-polling background job receives the token via-ArgumentListand prefixes itsreport_prline.tests/unit/pipe-server.test.ts— new coverage: V1 rejected without/with wrong token (and not emitted),pingstill public,hook.event/agent.activityrejected tokenless and accepted with the token.No client migration needed:
wmux-hook.tsand the CLI'ssendV2were already sending the token — it was just being ignored for these methods.Not included (deliberately)
agent.activity— the token is per-instance, so the server can't verify which surface a caller owns without per-surface credentials. Requiring the token removes the anonymous spoofing this issue is about; per-surface tokens would be a separate, larger change.net.Serverdoesn't expose a security descriptor for named pipes, so this needs a native module or a different pipe implementation. The token now gates every state write, which was the load-bearing gap.Testing
npm test— 162/162 pass (13 inpipe-server.test.ts, 4 new).npm run build:main— clean.🤖 Generated with Claude Code