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

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