"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
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", ALLduration:"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
- 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).
- When "Allow Claude to read page content on <site>?" appears, press Always allow.
- Watch the next read/click/navigate action on the same site prompt again within seconds.
- 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_
Showing cached comments. Read the full discussion on GitHub ↗
4 Comments
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).Still reproduces on the current build, with a new data point that narrows the surface:
bypassPermissionsmode 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):
claudeai.code.permission_mode.changed—previous_mode: "default"→current_mode: "bypassPermissions"via the mode dropdown (12:46:28)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 (theduration: oncebehavior this issue describes). Also confirmed there's no user-side persistence to work with:Claude Extensions Settings/ant.dir.ant.anthropic.chrome-control.jsoncontains 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.jsonin this setup allows the connector tools three ways (per-toolmcp__claude-in-chrome__navigateetc.,mcp__claude-in-chrome__*glob, and server-levelmcp__claude-in-chrome) withdefaultMode: "dontAsk"— all ignored, consistent with #73587 and #76238.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.jsonwith"defaultMode": "bypassPermissions"and server-level allow rulemcp__claude-in-chromeThe 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.
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:
permissionStoragerecords directly (Chrome closed, LevelDB,duration:"always", single-JSON-encoded, verified readable on re-read)CLAUDE_CHROME_PERMISSION_MODE=skip_all_permission_checks— set insettings.jsonenvand~/.zshrc, confirmed live viaprintenvinside the Claude process, full app restartpermissions.allow(193 rules: server-level, wildcard, fully-qualified, 5 name spellings) in both user and project settingsbypassPermissions/acceptEdits/defaultmodesAlso worth noting: prompts fire for tools that pass no URL at all (e.g.
tabs_context_mcpwith{"createIfEmpty": false}). InmcpPermissions-*.js,findApplicablePermissiononly matchesscope.type === "netloc"and requirest.scope.netlocto be truthy — so a URL-less call can never match a stored grant, and empty-hostname scopes (file://) are filtered out entirely.matchesNetlocsupports*.domain, but normalization strips a trailing dot so a bare*.can't serve as a catch-all.Filed with fuller detail as #84355.