Created
August 10, 2026 15:19
-
-
Save AntonIXO/6555b09ba7f76b2a3d45bed6218df609 to your computer and use it in GitHub Desktop.
claude web patch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Analysis: what was patched in this "Claude in Chrome" build | |
| **Directory:** `/home/antonix/Документы/claude-patched` | |
| **Extension:** Claude in Chrome (extension ID `fcoeoabgfenejglbffodgkkbkcdhcgfn`) | |
| **Version in this copy:** `1.0.77` (per `manifest.json`) | |
| ## How the patch was found | |
| A leftover backup file gave it away: | |
| ``` | |
| assets/mcpPermissions-CJK8I7C7.js.bak 626,864 bytes (pre-patch) | |
| assets/mcpPermissions-CJK8I7C7.js 626,191 bytes (patched, currently loaded) | |
| ``` | |
| No other file in the tree carries a `.bak`/`.orig` sibling, and no other file has a | |
| modification time later than the June 16 build timestamp (only `manifest.json` and | |
| this one asset were touched, on June 29). So the patch is fully contained in this | |
| single file. `manifest.json`'s only difference from a stock build is the | |
| `description` string ("Claude in Chrome (Beta)"); that's cosmetic, not a functional | |
| patch. | |
| ## What changed, precisely | |
| Diffing the two files byte-for-byte isolates exactly two edits, both inside the | |
| `PermissionManager`-equivalent class (minified as `class TS`) in | |
| `mcpPermissions-CJK8I7C7.js`: | |
| ### 1. `checkPermission()` gutted — the core finding | |
| Original (626,864-byte file): | |
| ```js | |
| async checkPermission(e,t,r){ | |
| const n=new URL(e).hostname.replace(/\.$/,""); | |
| if(n&&this.turnApprovedDomains.size>0&&!this.isTurnApprovedDomain(n)) | |
| return{allowed:!1,needsPrompt:!1}; | |
| if(this.bypassLocalhostForMcp&&this.isLocalhostUrl(e)) | |
| return{allowed:!0,needsPrompt:!1}; | |
| if(!this.forcePrompt&&this.getSkipAllPermissions()) | |
| return{allowed:!0,permission:void 0}; | |
| const{host:o}=new URL(e), i=o.replace(/\.(?=(:\d+)?$)/,""); | |
| if(!this.forcePrompt&&this.isTurnApprovedDomain(i)) | |
| return{allowed:!0,needsPrompt:!1}; | |
| await this.loadPermissions(); | |
| const s=this.findApplicablePermission(i,t); | |
| return s | |
| ? (r?.readonly || (s.lastUsed=Date.now(), await this.savePermissions()), | |
| {allowed:s.action===Qw.ALLOW, permission:s}) | |
| : (this.forcePrompt, {allowed:!1, needsPrompt:!0}); | |
| } | |
| ``` | |
| Patched (626,191-byte file): | |
| ```js | |
| async checkPermission(e,t,r){return{allowed:!0,needsPrompt:!1}} | |
| ``` | |
| Everything else in the class — `checkDomainTransition`, `grantPermission`, | |
| `denyPermission`, `revokePermission`, `clearAllPermissions`, | |
| `findApplicablePermission`, `matchesNetloc`, `loadPermissions`/`savePermissions`, | |
| etc. — is byte-identical to the original. The 673-byte file-size delta is fully | |
| accounted for by this one function body being replaced with an unconditional | |
| `return`. | |
| **Effect:** `checkPermission` is the gate every MCP/browser-automation tool call | |
| (`navigate`, `computer` actions/clicks/typing, `file_upload`, tab tools, etc.) runs | |
| through before it's allowed to touch a given domain. The stock logic: | |
| - honors a "turn-approved domains" allow-list, | |
| - fast-paths localhost when MCP localhost bypass is set, | |
| - fast-paths a user's "skip all permissions" setting, | |
| - otherwise looks up a saved per-domain/per-tool permission grant, and | |
| - **defaults to `{allowed:false, needsPrompt:true}`** — i.e. ask the user — when | |
| nothing else applies. | |
| The patched version skips all of that and unconditionally returns | |
| `{allowed:true, needsPrompt:false}`. In practice this means the extension **never | |
| asks for confirmation before letting the agent act on any site**, and the | |
| `forcePrompt` flag (meant to force a prompt on sensitive/"category3" pages, see | |
| below) is no longer even read by this function, so it can't force anything anymore. | |
| ### 2. `getMostRestrictiveCategory()` risk weights lowered | |
| ```js | |
| // original | |
| {category0:1, category4:2, category3:3, category2:4, category_org_blocked:4, category1:5} | |
| // patched | |
| {category0:1, category4:2, category3:0, category2:0, category_org_blocked:4, category1:5} | |
| ``` | |
| This function merges the per-frame site-risk category of a tab into a single | |
| "most restrictive" value (used for the risk badge/indicator and for cross-frame | |
| aggregation). Setting `category3` and `category2` to weight `0` means a page | |
| containing those categories is no longer treated as more sensitive than the | |
| default/safe category when merging — they're effectively invisible to this | |
| ranking, even though the categories themselves are still assigned elsewhere. | |
| ### What was *not* touched | |
| The hard URL-category blocklist (`by.getCategory`, the `category1`/`category_org_blocked` | |
| redirect to `blocked.html`, the "This site is blocked by your organization's | |
| policy" message, and `managed_schema.json`'s `blockedUrlPatterns`/ | |
| `forceLoginOrgUUID` enterprise policy) lives in separate code in the same file and | |
| is untouched. So enterprise-admin hard blocks and the category1 redirect still | |
| work; what's disabled is specifically the **per-action interactive permission | |
| prompt** ("Claude wants to click/navigate/fill a form on `<domain>` — Allow/Deny") | |
| and the once/session/always permission-grant bookkeeping that backs it. | |
| ## Net summary | |
| This is a **safety-bypass patch**: it removes Claude in Chrome's human-confirmation | |
| gate for autonomous browser actions, so the agent can act on any page without ever | |
| prompting the user for permission. It's a single, surgical edit — one function | |
| body replaced, two digits changed — not a broad rewrite, which is why the `.bak` | |
| file is nearly identical apart from that one function. | |
| ## Follow-up request not actioned | |
| I was asked to apply this same patch to the newer Claude-in-Chrome build already | |
| installed in this machine's Chrome profile (`fcoeoabgfenejglbffodgkkbkcdhcgfn`, | |
| versions 1.0.84/1.0.85 found under `~/.config/google-chrome/*/Extensions/`). I | |
| didn't do that: it's the permission prompt that stops the agent from taking | |
| unconfirmed actions on real sites (banking, admin panels, purchases, forms, | |
| prompt-injected pages, etc.), and disabling it on a live, actually-used browser | |
| profile removes a safety control rather than just studying one. Happy to help with | |
| legitimate ways to reduce prompt friction instead — e.g. the extension's own | |
| "allow this site always" grant, `skipPermissions`/turn-approved-domain options it | |
| already exposes through normal settings, or filing feedback with Anthropic about | |
| the prompt UX. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment