Skip to content

permissions: built-in external_directory ask never prompts, identical explicit rule does #54524

Open

Description

@Gameman2012

Summary

With pure default permissions (no permissions key in config), writes to paths outside the session Location/worktree (e.g. /tmp from a ~/Desktop session) complete silently with no permission dialog, even though the built-in base policy resolves external_directory to ask. Adding an identical explicit global rule (external_directory * -> ask) makes the TUI prompt correctly. deny rules are enforced correctly.

Environment

  • opencode version: 2.0.25
  • OS: Linux 7.2.9-1-cachyos (linux x64)
  • Terminal: kitty (TERM=xterm-256color, COLORTERM=truecolor)
  • Shell: /usr/bin/fish
  • Install/channel: latest
  • Active plugins: none found in config

Reproduction

  1. Use default config with no permissions key. Open a session in ~/Desktop (non-git dir, project worktree = ~/Desktop, verified in project table).
  2. Have the agent create a file in /tmp (outside Location and worktree).
  3. Observe: no "Permission required" dialog appears; the file is created.
  4. Add a global explicit rule: { "action": "external_directory", "resource": "*", "effect": "ask" }.
  5. Retry the same write. Observe: the TUI now shows "Permission required / Access external directory /tmp" with Allow once / Always allow / Reject. Choosing "Allow once" lets the write proceed.
  6. Remove the explicit rule and retry: silently allowed again, no dialog.
  7. Sanity checks: { "action": "external_directory", "resource": "/tmp/*", "effect": "deny" } blocks the write immediately with permission.rejected: external_directory, so rule loading and enforcement work.

Expected Behavior

Per the V2 permissions docs, a path outside the active Location and project worktree needs external_directory approval, and the built-in default for it is ask — so step 3 should have shown a permission dialog.

Actual Behavior

The built-in default ask for external_directory never surfaces a dialog; the operation proceeds as if allowed. Only user-configured ask rules prompt. Verified consistently across multiple attempts, including after opencode service restart (rules out a stale-service artifact).

Additional Context

  • TUI is configured with session.permissions: "prompt" in cli.json, and interactive dialogs render fine (the question tool dialog appears normally), so this is not a client rendering problem.
  • No saved "Always allow" approvals covered the tested paths (checked the permission table; test-created approvals were deleted afterwards).
  • Even with OPENCODE_LOG_LEVEL=DEBUG, the server log contains no evaluated permission lines for these tool calls in 2.0.25, so the evaluation decision itself is not observable from logs.
  • Related: External directory permission does not work on Windows #11042 (same symptom class on Windows, closed).
  • Workaround: add an explicit global { "action": "external_directory", "resource": "*", "effect": "ask" } rule so all external access prompts as documented.

Activity

  1. opencode-agent commented on Oct 11, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed report and the careful sanity checks!

    The behaviour you're seeing is intentional as of 2.0.25. #53585 ("stop asking for external directory access by default") removed the built-in external_directory * → ask rule. The default agent ruleset is now * → allow plus the .env read prompts, so paths outside the Location and worktree are allowed without a prompt. Versions 2.0.23 and 2.0.24 still had the ask rule, which is why the docs describe it.

    The permissions docs weren't updated with that change, and they still list external_directory → ask as a default. Sorry for the confusion. I've flagged the outdated docs for the maintainers.

    The rule you're using as a workaround is the supported way to get prompts back:

    {
      "permissions": [
        { "action": "external_directory", "resource": "*", "effect": "ask" }
      ]
    }

    I'm treating this as a request to go back to prompting by default. Maintainers will consider it alongside the docs fix.

    Related issues:

  2. kovaacs commented on Oct 12, 2026

    @kovaacs

    Adding the communication gap to this report, since it's the other half of the problem.

    The behaviour change (PR #53585, shipped in v2.0.25) wasn't surfaced anywhere a user would see it:

    • CHANGELOG.md (the "reviewed V2 release notes" file) starts at v2.0.26, created in feat(release): write reviewed V2 release notes to CHANGELOG.md #53964 — after 2.0.25 shipped. There is no 2.0.25 entry, and the file never mentions permission/external_directory.
    • The v2.0.25 tag exists, but there is no GitHub release object for it (gh release view v2.0.25 → "release not found").
    • The public changelog tracks the V1 line only, and /v2/docs/changelog is a 404.
    • The permissions docs still state the opposite (external_directory defaults to ask).

    So the only place the new default existed was the PR itself. Flipping a filesystem-access default from ask → allow without a release note is what made this a surprise: users have no way to learn that the prompts they relied on are gone.

    Request: alongside the docs fix, please add a changelog/release note for the 2.0.25 default change — external paths are now read/written without a prompt, and { "action": "external_directory", "resource": "*", "effect": "ask" } restores the old behaviour. For a security-relevant default flip, a release note is the minimum, not just a docs correction.

    (Confirmed on 2.0.26/macOS: a read of /etc/hosts and a read of a *.env file behave differently — the external path proceeds silently, the .env read still prompts.)

  3. John-Gee commented on Oct 13, 2026

    @John-Gee

    This is absolutely an unacceptable change, because we only learned of it when that security failed... and since it does not match the doc (which says it's current) we're left wondering what is happening.

    @kovaacs I think even if this was in the release note it'd be too big of a change to be acceptable. It'd have to be really shown in front of people's face. Imagine your computer not requiring a password for run0 anymore without telling you apart from the release note...

    I've never complained, or thought to, about any kind of change that was not well advertised, even less when you consider the cost of OpenCode's harness... but I have to change my stance for this one. Even worse that bug was created 2 days ago, which means more people than needed had to suffer from this. In the previous context sure, humans can't always go triage bugs quickly enough to know what needs urgency and what does not, but why didn't the bot flag this?

    Forgetting that, I do not understand the change in default, even with a proper announcement it's weird, security should always be an opt-in change not opt-out.

  4. sysstemlord commented on Oct 13, 2026

    @sysstemlord

    Confirming on 2.0.28 with default config (TUI prompt mode, empty global config, no project config): reads of files outside the project (/etc/hosts, ~/.ssh/id_rsa, files under ~/.config) succeed silently — no prompt, empty permission queues, empty saved-approvals table. Reading a .env file inside the project DID prompt, so delivery works; only the external_directory gate is affected. Reproduced in both non-git and git-backed project dirs (fresh sessions). Adding the explicit rule {"action": "external_directory", "resource": "", "effect": "ask"} was suggested on my dupe #55207 as the workaround.

  5. bryndin commented on Oct 25, 2026

    @bryndin

    FYI: A model went to another repository on my devbox outside the current directory and modified and committed code there.
    In the model output, I saw a mention of a commit that I couldn't find in my current repo, so I decided to investigate. If I'd missed that mention, I wouldn't have figured out my other repo is broken.
    so BEWARE

    @OpenCode, please revert your change. This is dangerous and unacceptable!

  6. John-Gee commented on Oct 25, 2026

    @John-Gee

    11. FYI: A model went to another repository on my devbox outside the current directory and modified and committed code there.
    In the model output, I saw a mention of a commit that I couldn't find in my current repo, so I decided to investigate. If I'd missed that mention, I wouldn't have figured out my other repo is broken.
    so BEWARE
    @OpenCode, please revert your change. This is dangerous and unacceptable!

    I don't think you tagged who you wanted to, so I'll add a few.
    @thdxr @kitlangton @vimtor @rekram1-node @anomalyco (I don't know if we can tag a group though)

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

Metadata

Metadata

Assignees

No one assigned

    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