fix(commands): require trusted session for /image path reads#5988
Merged
Conversation
Owner
Author
|
Follow-up filed for the out-of-scope gateway webhook trust-inheritance gap found during review (impl-critic finding S1): #5989 |
ImageCommand never overrode CommandHandler::requires_auth(), so Telegram/Discord/Slack sessions -- none of which are trusted by CommandRegistry::dispatch -- could invoke /image <path> to read any file reachable under the server's working directory (CWE-284). Override requires_auth() to true, matching the existing /cache-stats and /notify-test handlers in the same module. /image remains available from local CLI/TUI/ACP-stdio sessions.
bug-ops
force-pushed
the
fix/5967-image-arbitrary-read
branch
from
July 10, 2026 23:14
1d5df59 to
0bc8326
Compare
bug-ops
enabled auto-merge (squash)
July 10, 2026 23:14
This was referenced Jul 10, 2026
Closed
bug-ops
added a commit
that referenced
this pull request
Jul 13, 2026
… durable replay dedup (#6203) CommandHandler::requires_auth() defaulted to false (accessible from all channels), a recurring defect class where new handlers silently stayed reachable from untrusted remote channels until an audit caught them (4th recurrence: #5967/#5988, #5997/#6002, #6003/PR#6033). Flip the default to true (fail-closed); the six previously-implicit read-only handlers now override it explicitly to preserve behavior. Also fixes durable subagent replay's channel-notify side effects, which bypassed the ctx.step() dedup discipline (spec-064 INV-10): a resumed parent could refire the "replayed from durable journal" notice on every restart. Rather than gating via ctx.step (found to break step-id determinism between fresh and replay runs), dedup via an out-of-band notified_at claim column on durable_promises, consuming no step id. Tightens the doc comment on resolve_durable_spawn_gate's still-pending resume branch to make the LocalBackend-only safety rationale explicit at the call site. Closes #6034 Closes #6027 Closes #6010
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.
Summary
ImageCommandnever overrodeCommandHandler::requires_auth()(defaultfalse), so remote channels — Telegram, Discord, Slack — could invoke/image <path>and read any file reachable under the server's working directory viaload_image'sstd::fs::read, subject only topath_guard::classify_relative_path's "no absolute path, no.." check (CWE-284).ImageCommand::requires_auth()now returnstrue, closing the remote vector at the existing dispatch gate (CommandRegistry::dispatch), matching the pattern already used by the sibling/cache-statsand/notify-testhandlers in the same module./imageremains available from trusted local sessions (CLI/TUI/ACP-stdio)./imageis allowed when trusted and rejected when untrusted.Out of scope (filed separately)
zeph-channels/src/cli.rsis local-operator-only (intercepted at the stdin loop before dispatch) — not remote-exploitable, left unchanged.trusted=truefrom a local primary channel when no bearer token is configured, letting an unauthenticated webhook POST reach/imagethe same way. This is a pre-existing, broader gap not introduced or fixed by this change; a follow-up issue is being filed separately.Fixes #5967
Test plan
cargo +nightly fmt --checkcargo clippy --profile ci --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,testing" -- -D warningscargo nextest run --config-file .github/nextest.toml --workspace --features "desktop,ide,server,chat,pdf,scheduler" --lib --bins(12639 passed)cargo nextest run --config-file .github/nextest.toml -p zeph-commands(133/133, includes new dispatch tests)RUSTFLAGS="-D warnings" RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc --no-deps --workspace --features "desktop,ide,server,chat,pdf,scheduler"