Skip to content

[BUG] File modification tools (edit/write/apply_patch/shell) lack data-loss prevention guards #31248

@LifetimeVip

Description

@LifetimeVip

Description

The file modification tools (edit, write, apply_patch) and shell tool lack fundamental data-loss prevention guards. AI agents can silently overwrite files, replace unintended content, or delete project files without adequate safeguards. Unlike V2 core tools (which have partial protection like writeIfUnchanged and TargetExistsError), the V1 tools lack these entirely.

Data-Loss Risks by Tool

1. edit.ts (V1) — packages/opencode/src/tool/edit.ts

# Risk Lines Details
A replaceAll: true + short oldString → unintended replacements 714–715 No minimum-length or uniqueness validation. String like "a" or "const" with replaceAll: true silently replaces every occurrence
B "oldString not found" error doesn't tell AI to re-read 725 Message: "It must match exactly, including whitespace, indentation, and line endings" — encourages retry guessing instead of re-reading
C "multiple matches" error doesn't tell AI to re-read 728 Message: "Provide more surrounding context to make the match unique" — doesn't suggest re-reading
D No stale-content guard between read (L126) and write (L155) 126→155 File changed by another agent/user between read and write is silently overwritten. V2 core already has writeIfUnchanged (file-mutation.ts:143-156)

2. write.ts (V1) — packages/opencode/src/tool/write.ts

# Risk Lines Details
E Unconditionally overwrites existing files 64 yield* fs.writeWithDirs(filepath, ...) — no stale-content check, no abort on existing file
F No content validation before writing entire tool Can write empty or truncated content

3. shell.ts (V1) — packages/opencode/src/tool/shell.ts

# Risk Lines Details
G rm/del/rmdir inside project not flagged specially 410 containsPath check skips extra permissions for project-internal paths. Destructive commands on project files get same treatment as cat or ls
H No git awareness entire tool Cannot distinguish tracked vs untracked files; no recovery path for accidental deletion

4. apply_patch.ts (V1) — packages/opencode/src/tool/apply_patch.ts

# Risk Lines Details
I No stale-content check for update hunks 115→231 File read at start, written after all hunks processed — stale content overwritten
J "add" hunks don't check if file already exists → silent overwrite 226 No TargetExistsError check (unlike V2 core at file-mutation.ts:134-136)
K "delete" hunks remove files with generic permission only 247 No additional confirmation for destructive deletion

5. All V1 tools

# Risk Details
L No git integration Cannot snapshot/restore files before modification. No post-hoc recovery

Contrast with V2 Core

The V2 core tools already implement some protections that V1 lacks:

  • writeIfUnchanged (file-mutation.ts:143-156): Compares current file content with read snapshot; returns StaleContentError if modified
  • files.create() with "wx" flag (file-mutation.ts:123-141): Fails with TargetExistsError if file already exists
  • edit.ts (core V2, L114–116): Error message says "File changed after permission approval. Read it again before editing."

These patterns should be applied to V1 tools.

Expected Behavior

  • edit tool should validate that oldString is specific enough before allowing replaceAll
  • Error messages for "not found" and "multiple matches" should tell the AI to re-read the file
  • write tool should warn or abort when overwriting existing files
  • shell tool should flag destructive commands (rm, del, rmdir) with additional warning
  • apply_patch tool should check file existence before "add" hunks and validate stale content before "update" hunks
  • V1 tools should adopt the V2 core patterns (writeIfUnchanged, TargetExistsError) where applicable

Suggested Fix

This is a cross-cutting concern. The canonical fix is to adopt the V2 core's FileMutation service in V1 tools, which already implements stale-content detection and existence checks. The V1 tools at packages/opencode/src/tool/edit.ts, write.ts, apply_patch.ts should be migrated to use @opencode-ai/core/filesystem/file-mutation where possible, and the error messages in edit.ts should be updated to recommend re-reading.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions