Skip to content

🤖 Model-driven lossy snapshot archive needs user-origin approval (acknowledged_untracked_paths is model-echoable) #3950

Description

@ThomasK33

Problem

task_workspace_lifecycle (PR #3940) restores the model-driven archive path for owned workspace-turn peer workspaces. When the worktree archive behavior is snapshot and the target checkout contains untracked files, archive returns requires_confirmation with the exact path list, and the caller must re-invoke with acknowledged_untracked_paths matching those paths (normalized exact-list equality, pinned across the interruption window).

This round trip is a loss-awareness acknowledgement, not a model-resistant approval boundary: the acknowledgement originates from the same model that requested the archive. A prompt-influenced owner agent can read requires_confirmation.paths and immediately echo them back, after which snapshot capture omits the untracked files and the checkout is removed — deterministic loss of new work with no user gesture. Flagged by Codex review round 22 on PR #3940 (P1 Security).

Why it was not changed inline on #3940

  • The round trip is the accepted tool contract (mirrors the historical PR 🤖 feat: add parent-owned workspace lifecycle tool #3633 design and the human UI confirmation dialog) and the issue-triage-loop skill flow depends on it.
  • The restored tool is scoped to durably-owned peer workspaces. A compromised owner agent already has equivalent destructive capability over that same peer workspace without touching archive: task(kind: "workspace", mode: "existing") runs full agent turns with unrestricted bash in that checkout (git clean -fdx, rm -rf, …). So the acknowledgement gate is not the barrier a prompt injection must defeat today.
  • The risk nevertheless remains real for user-edited untracked files in a peer workspace the user co-drove: the user's saved-but-untracked work can be discarded by a model-only acknowledgement.
  • Any confirmation token emitted into tool output or the transcript is model-visible and therefore echoable — a real fix cannot be a smarter token in the same channel.

Design directions

A model-resistant mitigation needs one of:

  1. User-origin approval grant: requires_confirmation surfaces a pending approval in the UI; the user's approval is recorded backend-side (never exposed to model context) and the archive proceeds only when the backend verifies a live grant for that workspace + exact path list. The model-side acknowledged_untracked_paths becomes advisory (or is dropped).
  2. Make model-driven lossy archives impossible: model-driven snapshot archives with untracked files are always refused (status: "error", directing the user to archive via UI); only clean checkouts are model-archivable. Simple, but breaks the documented round trip and degrades orchestrator loops on workspaces with incidental untracked files (logs, scratch).
  3. Make snapshot non-lossy: capture untracked files into the snapshot (or a durable side-store) so nothing is lost and no confirmation is needed. Changes user-facing archive semantics too; storage-cost and secret-hygiene questions (untracked files often contain credentials).

Option 1 preserves the existing contract shape and matches the consent-surface precedent (managed plugin installation consent); option 3 removes the hazard class entirely but is the largest change. Whatever is chosen should be applied consistently across destructive model-driven workspace operations (task_remove has no confirmation at all today).

References


Generated with xum • Model: anthropic:claude-fable-5 • Thinking: xhigh • Cost: $366.45

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions