"Always allow" for Claude-in-Chrome site permissions is always persisted as duration:"once" — approved sites list stays empty, prompt repeats for every browser action

Status Open
Reported on v2.1.201
Maintainer reply None cached
Activity 10 comments · opened Jul 6, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

When the Claude Code desktop app shows the site-permission dialog ("Allow Claude to read page content on www.avito.ru?" / "click on…" / "navigate to…") and the user presses Always allow, the grant is written into the Chrome extension's permissionStorage with duration:"once" instead of "always". The once-grant is consumed by the current tool call, so the very next browser action prompts again. "Your approved sites" (extension options → Permissions) stays permanently empty no matter how many times Always allow is pressed.

Storage forensics (byte-scan of the extension's chrome.storage.local LevelDB, extension id fcoeoabgfenejglbffodgkkbkcdhcgfn, v1.0.79, full history .log + .ldb):

  • 46 records for netloc:"www.avito.ru", ALL duration:"once", all created 2026-07-06 (the user pressed Always allow and/or Allow once ~46 times in one day);
  • zero records with duration:"always" — ever;
  • each once-record is immediately followed by a write of {"permissions":[]} (consumed).

Suspected root cause — in assets/mcpPermissions-B0h6Fctz.js (extension v1.0.79), the handler that resumes a tool call after the desktop dialog is answered grants the permission with a hardcoded MT.ONCE, discarding the duration the user chose:

const l=o;if(l.url)try{
  const{host:e}=new URL(l.url),
  r=t?.permissionManager??this.context.permissionManager;
  await r.grantPermission({type:"netloc",netloc:e},MT.ONCE,l.toolUseId)   // <-- always ONCE
}catch{}

grantPermission itself supports ALWAYS fine (duration:t with toolUseId only for ONCE). Either the desktop app never transmits the chosen duration over the bridge, or the extension ignores it — the visible result is identical: "Always allow" behaves exactly like "Allow once".

Workaround (verified end-to-end): manually appending {"action":"allow","duration":"always","scope":{"netloc":"avito.ru","type":"netloc"},"id":<uuid>,"createdAt":<now>} to permissionStorage.permissions via the extension service-worker console immediately makes the site appear in "Your approved sites" (with Revoke buttons) and the prompts stop — so the read path (findApplicablePermission) honors persistent grants; only the write path from the desktop dialog is broken.

Impact: autonomous/long-running sessions are blocked every few seconds waiting for the user; 46 prompts answered in one day for a single site. "Bypass permissions" mode and settings.json mcp__claude-in-chrome__* allow rules do not (and per design should not) affect this layer, so the broken "Always allow" is the only user control — and it does nothing. Possibly related: #67020, #30356.

What Should Happen?

One "Always allow" press stores a persistent duration:"always" netloc grant; the site appears in "Your approved sites"; no further prompts for that site (the grant should cover read/click/navigate on that domain and persist across sessions).

Error Messages/Logs

Sample stored record (from the extension's LevelDB, decoded):
{"action":"allow","createdAt":1783326998947,"duration":"once","id":"4f0d528e-4d70-45a9-afb7-5107b9ef3455","scope":{"netloc":"www.avito.ru","type":"netloc"},"toolUseId":"7c84a64b-df56-4b70-aae4-d69bf983aa2b"}

Current live value of permissionStorage after 46 user grants: {"permissions":[]}

Dialog text (desktop app): "Allow Claude to read page content on www.avito.ru?" with buttons Deny / Always allow / Allow once — pressing "Always allow" produces the duration:"once" record above.

Steps to Reproduce

  1. In the Claude Code desktop app (Windows), start a session that drives Chrome via the claude-in-chrome MCP on any site (e.g. avito.ru).
  2. When "Allow Claude to read page content on <site>?" appears, press Always allow.
  3. Watch the next read/click/navigate action on the same site prompt again within seconds.
  4. Open the extension options page → Permissions → "Your approved sites": it still says "No sites have been approved yet".

Environment: Claude Code desktop app on Windows 10 Pro (10.0.19045), CLI core 2.1.201; Claude in Chrome extension v1.0.79; Chrome stable.

Claude Model

None

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.201 (Claude Code)

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

Other

Additional Information

_No response_

View original on GitHub ↗

4 Comments

PropellerHead23 · 1 month ago

Matching behavior on macOS, desktop 1.20186.1 (so not Windows-only): claude-in-chrome tools re-prompt in every desktop-spawned session despite full allow-list entries — "Always allow" never sticks past the session, consistent with it being persisted as duration:once. Regression onset for me was the 2026-07-11 desktop auto-update.

Workaround that holds: permissions.defaultMode: "dontAsk" in ~/.claude/settings.json (with the tools allow-listed) suppresses the per-session cards — details in https://github.com/anthropics/claude-code/issues/73587#issuecomment-4975856651.

Same regression family: #73587 (desktop ignores permissions.allow, Windows + macOS), #76238 (MCP allowlisted tools still prompt on fresh session, macOS).

PropellerHead23 · 1 month ago

Still reproduces on the current build, with a new data point that narrows the surface: bypassPermissions mode is also ignored for connector tools.

Environment: macOS 15.5, Claude Desktop 1.22209.0, embedded Claude Code CLI 2.1.207, Claude in Chrome extension current as of 2026-07-19.

Repro (timestamped from the app's own local telemetry events):

  1. claudeai.code.permission_mode.changedprevious_mode: "default"current_mode: "bypassPermissions" via the mode dropdown (12:46:28)
  2. New local session created in that folder (12:46:31)
  3. claudeai.epitaxy.tool_approval.decided — a connector tool (mcp__claude-in-chrome__*) still raised a blocking approval card (12:46:48), decided "always"

So the desktop adjudicator cards connector tools even in bypassPermissions, and the "always" decision then doesn't survive the session (the duration: once behavior this issue describes). Also confirmed there's no user-side persistence to work with: Claude Extensions Settings/ant.dir.ant.anthropic.chrome-control.json contains only {isEnabled}, and the only related Local Storage key found (epitaxy-folder-permission-mode.<account>) governs the per-folder boot mode, which per the above doesn't suppress connector cards either.

For completeness, ~/.claude/settings.json in this setup allows the connector tools three ways (per-tool mcp__claude-in-chrome__navigate etc., mcp__claude-in-chrome__* glob, and server-level mcp__claude-in-chrome) with defaultMode: "dontAsk" — all ignored, consistent with #73587 and #76238.

edu5r · 29 days ago

Confirming this bug on Windows 11 Pro with the Claude Desktop app (pt-BR locale).

Impact: Every claude-in-chrome tool call (Computer, Find, Navigate, Tabs Context) triggers a permission prompt, on every action, in every session. Clicking "Always allow" ("Sempre permitir") never persists — the prompt returns on the very next action. This makes multi-session browser workflows effectively unusable (we run several parallel Claude Desktop sessions automating an Odoo ERP, and each one blocks on prompts constantly).

What we tried (no effect, consistent with this issue's root cause):

  • ~/.claude/settings.json with "defaultMode": "bypassPermissions" and server-level allow rule mcp__claude-in-chrome
  • Folder-level bypassPermissions mode in the Desktop app (badge shows bypass active — browser tools still prompt)
  • Clearing the Desktop app's Local Storage/IndexedDB and full app restart

The session-level bypass badge being active while browser tools still re-prompt on every action supports the finding that the extension permission layer ignores the grant duration chosen in the dialog.

Happy to provide logs or test a fix build.

mgu333 · 25 days ago

Adding a data point that I think is new: the verified workaround in this issue no longer works, and neither does the undocumented env var.

Claude Code 2.1.220 / Chrome extension 1.0.84 / Chrome 151.0.7922.75 / macOS 26.6.

Tried, all with no effect on per-action prompts:

  • Writing permissionStorage records directly (Chrome closed, LevelDB, duration:"always", single-JSON-encoded, verified readable on re-read)
  • Adding the sites through the supported Settings → Permissions → approved sites UI
  • CLAUDE_CHROME_PERMISSION_MODE=skip_all_permission_checks — set in settings.json env and ~/.zshrc, confirmed live via printenv inside the Claude process, full app restart
  • Extension side-panel mode "Skip all approvals"
  • permissions.allow (193 rules: server-level, wildcard, fully-qualified, 5 name spellings) in both user and project settings
  • bypassPermissions / acceptEdits / default modes

Also worth noting: prompts fire for tools that pass no URL at all (e.g. tabs_context_mcp with {"createIfEmpty": false}). In mcpPermissions-*.js, findApplicablePermission only matches scope.type === "netloc" and requires t.scope.netloc to be truthy — so a URL-less call can never match a stored grant, and empty-hostname scopes (file://) are filtered out entirely. matchesNetloc supports *.domain, but normalization strips a trailing dot so a bare *. can't serve as a catch-all.

Filed with fuller detail as #84355.

Showing cached comments. Read the full discussion on GitHub ↗