coder / coder/xum

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

Open
#3,950 1 comment 0 reactions 0 assignees View on GitHub
bug investigation
Dominant language
TypeScript
Stars
2k
Forks
134
Avg merge
14h 57m
Merged PRs (30d)
307

Description

## 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 #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

- PR #3940 (restoration), Codex round-22 finding on `src/node/services/tools/task_workspace_lifecycle.ts`.
- Related archive-gating follow-ups: #3943, #3944, #3946, #3947.

---

_Generated with `xum` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh` • Cost: `$366.45`_

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.