anomalyco / anomalyco/opencode

permission.edit patterns are matched against worktree-relative paths — absolute/~ patterns silently never match (fail-open for deny rules)

Open
#40,945 2 comments 0 reactions 1 assignee View on GitHub

@jlongster is already working on this.

Since Aug 6, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Summary

permission.edit (and by extension write) rules are matched against the worktree-relative path of the file being edited, not the absolute path. Any rule using an absolute path or ~ pattern silently never matches. This is fail-open for deny rules: a rule like "~/.ssh/**": "deny" looks like it protects a directory but does nothing.

Environment

  • opencode 1.18.13 (Homebrew, macOS)
  • Config: ~/.config/opencode/opencode.jsonc

Root cause

The edit/write tools submit a worktree-relative path as the permission pattern:

  • packages/opencode/src/tool/write.ts:56patterns: [path.relative(instance.worktree, filepath)]
  • packages/opencode/src/tool/edit.ts:104 and :147 — same

For a file outside the worktree this yields paths with ../.. segments (e.g. ../../daily-notes/2026-08.md), which absolute/~ patterns can never match.

Repro

  1. Global config:
{
  "agent": {
    "writer": {
      "mode": "all",
      "permission": {
        "bash": "deny",
        "edit": { "*": "deny", "~/daily-notes/**": "allow" }
      }
    }
  }
}
  1. Run: opencode run --agent writer "Create the file ~/daily-notes/test.txt containing ok"

Expected: edit allowed by the ~/daily-notes/**" allow rule.

Actual: denied — the submitted pattern is relative (e.g. ../../daily-notes/test.txt from a repo cwd, Users/<name>/daily-notes/test.txt from /tmp), so the allow rule never matches and "*": "deny" wins.

The fail-open direction (security)

"edit": { "*": "allow", "~/.ssh/**": "deny" }

A user writing this believes ~/.ssh is protected. The deny rule never matches, so the agent can edit ~/.ssh/* freely. Any absolute-path deny rule for edit/write is currently a no-op.

Workaround (what I had to do)

Use relative patterns that anticipate ../ segments, which is undocumented and fragile:

"edit": { "*": "deny", "daily-notes/**": "allow", "*/daily-notes/**": "allow" }

This also over-broadens the rule: any directory named daily-notes anywhere becomes writable.

Suggestion

Resolve the submitted pattern to an absolute path before matching (or match against both absolute and relative forms), so absolute and ~ patterns work as users expect. At minimum, document that edit/write permission patterns are worktree-relative and that absolute/~ patterns do not work.

Happy to provide more detail or test a fix.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.