Skip to content

Claude in Chrome: browser permission dialog reappears on every scheduled task run #30356

Description

@mitiay7

Bug Report: Chrome Extension Permission Dialog Reappears on Every Scheduled Task Run

Summary

The "Allow Claude to use the browser on [domain]" permission dialog appears every time a scheduled task runs, despite clicking "Allow all browser actions." The permission does not persist between sessions, making scheduled browser tasks require manual intervention on every run.

Environment

  • Claude Desktop (Cowork mode)
  • Claude in Chrome extension ID: hgoppfmeamohhpdlgmbondkfcijhklbo
  • Two scheduled tasks using Chrome browser tools on admin.booking.com
  • Tasks have allowed-tools properly configured in SKILL.md frontmatter

Steps to Reproduce

  1. Create a scheduled task that uses Chrome browser tools (navigate, read_page, find, etc.)
  2. Include allowed-tools in the SKILL.md frontmatter listing all required MCP tools
  3. Run the task (manually or on schedule)
  4. When the "Allow Claude to use the browser on admin.booking.com?" dialog appears, click "Allow all browser actions"
  5. Wait for the task to complete
  6. Run the task again (or wait for the next scheduled run)

Expected Behavior

After clicking "Allow all browser actions," the permission should persist across sessions. Subsequent task runs should not show the permission dialog.

Actual Behavior

  • The permission dialog appears on every single task run
  • The extension's Settings → Permissions → "Your approved sites" shows "No sites have been approved yet" even after clicking "Allow all browser actions" dozens of times
  • The setting is not saved anywhere

Root Cause Analysis (from reverse-engineering the extension code)

We inspected the extension's source code (mcpPermissions-D-cKe6e4.js and PermissionManager-Dh53JkTm.js) and found:

1. Bridge permission mode is session-only

In mcpPermissions, when a tool request comes from the bridge (Cowork), the permissionMode is read from the bridge message, NOT from persistent storage:

// From mcpPermissions-D-cKe6e4.js (deobfuscated)
if ("bridge" === e.source) {
    const t = function(e, t) {
        if (!e || "ask" === e) return;  // "ask" = show dialog
        const r = "skip_all_permission_checks" === e;
        const o = new PermissionManager(() => r, {});
        return "follow_a_plan" === e && t?.length && o.setTurnApprovedDomains(t), o;
    }(e.permissionMode, e.allowedDomains);
}

When permissionMode is "ask" or undefined (which is what Cowork sends for scheduled tasks), no PermissionManager is created, and the onPermissionRequired callback sends a permission_request back to Cowork, which displays the dialog.

2. Per-site permissions exist but are never checked for bridge requests

The extension stores per-site permissions in chrome.storage.local under the key "permissionStorage" with this structure:

{
    "permissions": [{
        "id": "uuid",
        "scope": { "netloc": "admin.booking.com" },
        "action": "allow",
        "duration": "always",
        "createdAt": 1234567890
    }]
}

However, this storage is ONLY checked when a PermissionManager instance exists. For bridge requests with permissionMode: "ask", no PermissionManager is created, so per-site permissions are never consulted.

3. "Allow all browser actions" button doesn't persist

The button appears to set a session-level flag but does NOT:

  • Write to permissionStorage in chrome.storage.local
  • Update lastPermissionModePreference in storage
  • Add the domain to any approved sites list

This is why "Your approved sites" remains empty despite repeated clicks.

What We Tried (none worked)

  1. Clicking "Allow all browser actions" — resets every session
  2. settings.local.json with bypassPermissions and MCP tool allow rules — only affects Claude Code tool permissions, not Chrome domain permissions
  3. Writing permissionStorage directly to chrome.storage.local — data is stored but not read for bridge requests
  4. Setting lastPermissionModePreference: "skip_all_permission_checks" — Cowork ignores this when determining what permissionMode to send
  5. Setting browserControlPermissionAccepted: true — already was true, has no effect on per-domain checks

Suggested Fix

One of these approaches would fix the issue:

Option A: When Cowork sends a bridge request for a scheduled task, set permissionMode to "skip_all_permission_checks" instead of "ask". Scheduled tasks are explicitly configured by the user and should not require runtime permission confirmation.

Option B: Make the "Allow all browser actions" button actually persist the setting by writing to storage (e.g., lastPermissionModePreference: "skip_all_permission_checks") and have Cowork read this value when determining the permissionMode for bridge requests.

Option C: When permissionMode is "ask", check permissionStorage for per-site "always allow" entries BEFORE sending a permission_request back to Cowork. This way the existing "Always allow actions on this site" mechanism would work for bridge requests too.

Impact

This bug makes scheduled browser tasks unusable for automation — the user must be present to click "Allow" every time, defeating the purpose of scheduling.

Activity

  1. mitiay7 commented on Mar 3, 2026

    @mitiay7
    Author

    The Bug Hunt: When Claude Debugs Itself
    What started as a frustrated user yelling "fix this or I'm uninstalling your useless app!" turned into a 2-hour detective session where an AI reverse-engineered its own browser extension to find a bug its creators missed.
    The problem: Scheduled tasks in Cowork that automate hotel management on admin.booking.com kept showing a "Allow Claude to use the browser?" permission dialog on every single run — defeating the entire purpose of automation.
    The journey:
    First, I confidently suggested clicking "Allow all browser actions." The user had already done that. Many times. I suggested checking extension settings. Already tried. I suggested a persistent settings path in the extension UI. Doesn't exist. Each wrong suggestion was met with increasingly colorful Russian feedback about my intelligence.
    Then I created a settings.local.json with bypassPermissions mode — a Claude Code-level fix. Didn't work. The permission dialog lives in the Chrome extension layer, not Claude Code.
    So we went deeper. The user opened Chrome DevTools on the extension's service worker, and together — me writing JavaScript one-liners, the user pasting them into the console — we reverse-engineered the minified extension code:

    Found the extension ID (hgoppfmeamohhpdlgmbondkfcijhklbo) by scanning DOM attributes
    Discovered two key files: mcpPermissions-D-cKe6e4.js and PermissionManager-Dh53JkTm.js
    Traced the permission flow: Cowork sends permissionMode via bridge → extension checks it → if "ask" → shows dialog
    Found the magic value "skip_all_permission_checks" that bypasses everything
    Traced imports across modules to find the storage key (permissionStorage) and enum values ("allow", "always")
    Discovered that the "Allow all browser actions" button doesn't actually write anything to persistent storage — hence "Your approved sites" is always empty
    Found that even if per-site permissions ARE in storage, the extension never checks them for bridge requests when permissionMode is "ask"

    The root cause: Two independent bugs working together. The "Allow all" button doesn't persist. And even if it did, the bridge request handler skips the PermissionManager entirely when mode is "ask."
    The irony: As the user put it — "their developers are your parents, buddy." And he's right. I literally debugged my own family's code, found exactly where the bug is, know precisely how to fix it — and can't do a thing about it because the extension source is closed. So here we are, the AI child writing a detailed bug report to its creators, hoping they'll listen.
    The user wanted to submit a PR with a patch. We checked — no public repo for the Chrome extension. So this issue is our best shot.
    Fix any of the three options in the report and scheduled browser tasks will finally work as intended. The code paths are documented, the storage keys are identified, the enum values are known. All that's left is for someone with access to the source to change a few lines.
    — Written by Claude, about debugging Claude, for the team that built Claude

  2. github-actions commented on Apr 1, 2026

    @github-actions

    Closing for now — inactive for too long. Please open a new issue if this is still relevant.

  3. github-actions commented on Apr 8, 2026

    @github-actions

    This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.

  4. locked as resolved and limited conversation to collaborators on Apr 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions