fix(mcp): make execute timeout opt-in for unprivileged commands (#54) - #56
Merged
Merged
Conversation
) `execute` applied its wall-clock `timeout` (default 120s) uniformly to privileged and unprivileged requests. For an unprivileged command — which runs as the user with no escalation — the deadline also counts human- approval latency, so a command that was approved and ran could still be reported to the caller as "server did not respond within 120s". A caller that then retries a side-effecting command double-executes it. Make the timeout opt-in for unprivileged requests: honored when the caller sets it, otherwise the client read waits as long as the daemon needs. The daemon still bounds the command (the 60s default-deny approval prompt and the executor's own exec timeout), the connect/write phases keep their 5s PHASE_TIMEOUT, and a dead daemon surfaces as EOF — so an unbounded read cannot hang on a daemon that has died. Privileged requests keep the 120s default; an explicit `timeout` is always honored and clamped. Stacked on #55, which already refuses *local* unprivileged execute(), so this governs the remaining (remote) unprivileged path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cuihtlauac
changed the base branch from
feat/g7-unprivileged-invariant
to
main
October 2, 2026 06:56
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.
Closes #54. Stacked on #55 (base =
feat/g7-unprivileged-invariant); review/merge after #55.Problem
executeapplied its wall-clocktimeout(default 120s) uniformly to privileged and unprivileged requests. An unprivileged command runs as the user with no escalation, but the deadline also counts human-approval latency — so a command that was approved and executed could still be returned to the caller as "server did not respond within 120s". A caller that retries a "timed-out" side-effecting command then double-executes it.Fix
The client-side read timeout becomes opt-in for unprivileged requests (
read_timeout_for): honored when the caller setstimeout, otherwise the read waits as long as the daemon needs. This is safe because the daemon always answers or drops:PHASE_TIMEOUT, and a dead daemon surfaces as EOF — an unbounded read cannot hang on a daemon that has died.Privileged requests keep the 120s default; an explicit
timeoutis always honored and clamped to 600000.Scope note
This fixes the observed failure (the client-side "did not respond" false-failure + the double-execution risk). The daemon-side exec bound (
SUDO_PROXY_EXEC_TIMEOUT_SECS, 300s) is intentionally left as a resource guard (assurance-case G6.4) — long-running unprivileged work should background itself, as the issue's own example does (setsid … & disown). Because #55 already refuses local unprivilegedexecute(), this governs the remaining remote unprivileged path.Tests
read_timeout_forunit test (opt-in/kept/honored+clamped); full suite green (minus the pre-existing flaky burst test); clippy-D warningsclean. Tool description anddocs/mcp.mdupdated.🤖 Generated with Claude Code