Skip to content

Granular read permission deny rules don't block file access (patterns never match) #28150

Closed as not planned

Description

@DeSynkro

Description

Provider: OpenCode Zen (opencode/big-pickle)
Config: ~/.config/opencode/opencode.json / jsonc
Shell: zsh

I wanted to restrict the agent from reading certain personal folders when using cloud models. The permission system seemed perfect for this, but granular deny rules on read, glob, and grep never block access despite the config loading correctly.

What works:
Global deny ("read": "deny") correctly removes the read tool entirely
opencode debug config confirms rules are loaded into resolved config
Config validates as valid JSON

What doesn't work:
Granular deny rules never match file paths. Tested all following pattern formats in read, glob, and grep permissions — none blocked access:

"*/Documents/*": "deny"              # wildcard prefixes
"*Documents*": "deny"                # substring
"Documents": "deny"                  # bare names
"/home/user/Documents": "deny"       # exact absolute

Also tested:

Removing "*": "allow" entirely (falling through to default allow)
Restarting both opencode and terminal between config changes
Applying same rules to glob and grep permissions

Expected behavior:
Setting "read": { "Documents": "deny" } should prevent the agent from reading files whose path contains "Documents".

Actual behavior:
All file reads succeed regardless of deny rules.

OpenCode version

Version: 1.15.4

Operating System

Linux (CachyOS, kernel 7.0.8-1-cachyos)

Terminal

konsole (xterm-256color)

Activity

  1. github-actions commented on May 18, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    If your issue is distinct from the above, please add a note explaining what makes it different.

  2. lexlian commented on May 28, 2026

    @lexlian

    I created a fix in PR #28689, but this might lead to some design discussion. Granular read permission deny rules weren't blocking file access — when configuring { read: { "*.env": "deny", "*": "allow" } }, the deny rule was bypassed for paths like src/.env.

    The root cause: wildcard * was converted to regex .*, which matches any character including /. This meant *.env matched src/.env, a/b/.env — making it as broad as *. With "last matching rule wins" semantics, a later wildcard * rule always overrode specific deny rules for any path containing /.

    The fix makes * match any characters except /, and adds ** globstar support for cross-directory matching — aligning with standard glob semantics (gitignore, bash glob). Patterns that need to match across directories (like the catch-all "*" → "**" and "*.env" → "**/*.env") have been updated in the default permission rules in agent.ts.

    Pattern matching changes:

    Pattern Before (bug) After (fix)
    *.env matches .env, src/.env, a/b/.env matches .env only
    **/*.env same as *.env (no ** support) matches .env, src/.env, a/b/.env
    src/*.env matches src/.env, src/a/.env matches src/.env only
    src/**/*.env not possible matches src/.env, src/a/.env
    * matches anything including paths matches single-segment filenames only
    ** same as * matches anything including paths

    Note for reviewers: This changes the semantics of * in permission patterns. Existing configs using * to match files at any depth will need to migrate to **. I've documented the migration path in the PR description.

  3. github-actions commented on Aug 16, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions