Repository navigation
Description
Summary
apply_diff builds its appliedDiff approval payload without the isOutsideWorkspace field. The auto-approval decision treats a missing value as "inside the workspace", so with alwaysAllowWrite: true, every apply_diff is auto-approved for any path on disk — even when alwaysAllowWriteOutsideWorkspace: false and the target matches no allowedWriteFiles glob. write_to_file and edit prompt correctly in the same situation; apply_diff silently applies.
Environment
- Zoo Code extension 3.92.0 (marketplace bundle); the same code is present on
main(src/core/tools/ApplyDiffTool.ts@4011f802) - VSCodium, Linux
- Settings:
autoApprovalEnabled: true,alwaysAllowWrite: true,alwaysAllowWriteOutsideWorkspace: false,alwaysAllowWriteProtected: false,allowedWriteFilesnot matching the target path
Steps to reproduce
- Configure auto-approval as above.
- Ask the agent to
apply_diffa file outside the workspace (absolute path or a../-relative path), e.g.~/.config/some-app/config.json. - The diff is applied without an approval prompt.
- Contrast:
write_to_filetargeting the same directory prompts as expected.
Root cause (source on main)
src/core/tools/ApplyDiffTool.ts — both approval messages spread sharedMessageProps, which never carries the flag:
const sharedMessageProps: ClineSayTool = {
tool: "appliedDiff",
path: getReadablePath(task.cwd, relPath),
diff: diffContent,
}handlePartial's props have the same omission (cosmetic only — partial asks don't gate the write — but inconsistent with the other tools).
The decision in src/core/auto-approval/index.ts (checkAutoApproval) defaults a missing field to false:
const isOutsideWorkspace = !!tool.isOutsideWorkspace
if (isWriteToolAction(tool)) {
return state.alwaysAllowWrite === true &&
(!isOutsideWorkspace || state.alwaysAllowWriteOutsideWorkspace === true) &&
(!isProtected || state.alwaysAllowWriteProtected === true)
? { decision: "approve" }
: { decision: "ask" }
}So apply_diff is classified as inside-workspace no matter where the file is, and alwaysAllowWriteOutsideWorkspace / allowedWriteFiles are effectively bypassed for this tool.
The sibling tools do it correctly — src/core/tools/EditTool.ts:
const isOutsideWorkspace = isPathOutsideWorkspace(absolutePath)
const sharedMessageProps: ClineSayTool = {
tool: "appliedDiff",
path: getReadablePath(task.cwd, relPath),
diff: sanitizedDiff,
isOutsideWorkspace,
}ApplyDiffTool.ts already computes absolutePath = path.resolve(task.cwd, relPath) — it just never consults isPathOutsideWorkspace.
Expected
apply_diff should honor alwaysAllowWriteOutsideWorkspace and allowedWriteFiles exactly like edit / write_to_file: outside-workspace diffs must prompt unless the path matches the write allowlist.
Suggested fix
import { isPathOutsideWorkspace } from "../../utils/pathUtils"
// ...
const isOutsideWorkspace = isPathOutsideWorkspace(absolutePath)
const sharedMessageProps: ClineSayTool = {
tool: "appliedDiff",
path: getReadablePath(task.cwd, relPath),
diff: diffContent,
isOutsideWorkspace,
}(plus the same field in handlePartial's props for consistency). Happy to follow up with a PR.
Observed impact
With the settings above, an agent task edited files under ~/.config/ with no approval while the user believed outside-workspace writes were gated. Verified by side-by-side probes in the same session: write_to_file → prompt; apply_diff → silent apply (reproduced both with absolute and ../-traversal relative paths). A local bundle patch adding the field restores correct prompting and allowedWriteFiles allowlisting for apply_diff.
Activity
kanchinadd98 commentedon Nov 7, 2026
Claiming
[Fix] apply_diff auto-approves edits outside the workspace (Zoo-Code-…