You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
desktop: per-window permission handler on a shared Electron session gets overwritten #51748
Electron permission handlers are registered on the shared session but decide using the current window's id. Opening a second window replaces the handler registered by the first, so permission requests raised on behalf of the other windows can be denied.
Environment
opencode version: source tree root package.json reports 2.0.17; audited at commit 041885d838c7eea81cffbe446e0cb0ac6f197728 (branch v2)
Not reproduced. This is a source-review finding from a read-only audit of the v2 tree at the commit above. The trigger window is described below; I did not manage to construct it reliably on my machine.
Open one app window; its permission handler is registered against the shared session.
Open a second window; a new handler is registered and replaces the first.
Trigger a permission-requiring action (notifications, clipboard, media) from the first window.
Expected Behavior
A single handler is registered for the shared session and decides based on the set of live windows, so every window behaves consistently.
Actual Behavior
packages/desktop/src/main/windows/security.ts:8-18 registers per-window while keying on the window id; callers in windows/early.ts:55-60 and windows/index.ts:117-138. The last registration wins.
Additional Context
Impact: inconsistent permission behaviour across windows — requests from earlier windows can be denied.
Suggested fix: register one handler per shared session and evaluate against the live window set; clean up on window close.
Suggested tests: two windows open simultaneously; close one of them and re-check permissions.
This issue might be related to an existing multi-window Electron issue. Please check:
#20371: It covers duplicate notifications across multiple Electron windows; this report describes a separate permission-handler overwrite, but both involve per-window handling in the multi-window desktop app.
Thanks for the detailed source review. I can confirm the bug in 2.0.18, and it still happens on the latest dev (86ce19d96ecc).
allowRendererPermissions(win) in packages/desktop/src/main/windows/security.ts sets the permission request handler and the permission check handler on win.webContents.session. Both only allow that window's webContents.id. Every window uses the default session, since none sets a partition. Each new window therefore replaces the previous handlers, and only the newest window passes the id check.
The script below tests the real allowRendererPermissions against a stand-in for Electron's shared session and registers two windows. The second window gets notifications and clipboard-sanitized-write. The first window is refused both. I checked this with that stand-in only, not in the running desktop app, so a maintainer may still want to confirm it there with two windows open.
Reproduction script (permissions.test.ts)
// Reproduces #51748: allowRendererPermissions() installs per-window handlers on the// shared Electron session; Electron keeps only the last handler (set* replaces), so// earlier windows lose renderer permissions.// Run: SRC=/path/to/checkout bun test /workspace/repro/permissions.test.tsimport{expect,mock,test}from"bun:test"mock.module("electron",()=>({protocol: {registerSchemesAsPrivileged(){},handle(){}},app: {},net: {}}))constsrc=process.env.SRC??"/workspace/repo"const{ allowRendererPermissions }=awaitimport(`${src}/packages/desktop/src/main/windows/security.ts`)// Fake of the shared default session: like Electron, setting a handler replaces the previous one.constsession: any={request: undefinedasany,check: undefinedasany,setPermissionRequestHandler(fn: any){this.request=fn},setPermissionCheckHandler(fn: any){this.check=fn},}constmakeWin=(id: number)=>({webContents: { id, session }})asanyconsturl="oc://renderer/index.html"constask=(id: number,permission: string)=>newPromise<boolean>((resolve)=>session.request({ id },permission,resolve,{requestingUrl: url,isMainFrame: true}))constcheck=(id: number,permission: string)=>session.check({ id },permission,url,{requestingUrl: url,isMainFrame: true})test("both renderer windows keep notification/clipboard permission",async()=>{allowRendererPermissions(makeWin(1))// first windowallowRendererPermissions(makeWin(2))// second window on the same sessionconstresult={win1_request_notifications: awaitask(1,"notifications"),win2_request_notifications: awaitask(2,"notifications"),win1_check_clipboard: check(1,"clipboard-sanitized-write"),win2_check_clipboard: check(2,"clipboard-sanitized-write"),}console.log(src,result)expect(result).toEqual({win1_request_notifications: true,win2_request_notifications: true,win1_check_clipboard: true,win2_check_clipboard: true,})})
Activity
github-actions commentedon Sep 28, 2026
This issue might be related to an existing multi-window Electron issue. Please check:
opencodejr commentedon Oct 28, 2026
Thanks for the detailed source review. I can confirm the bug in 2.0.18, and it still happens on the latest
dev(86ce19d96ecc).allowRendererPermissions(win)inpackages/desktop/src/main/windows/security.tssets the permission request handler and the permission check handler onwin.webContents.session. Both only allow that window'swebContents.id. Every window uses the default session, since none sets apartition. Each new window therefore replaces the previous handlers, and only the newest window passes the id check.The script below tests the real
allowRendererPermissionsagainst a stand-in for Electron's shared session and registers two windows. The second window getsnotificationsandclipboard-sanitized-write. The first window is refused both. I checked this with that stand-in only, not in the running desktop app, so a maintainer may still want to confirm it there with two windows open.Reproduction script (permissions.test.ts)
Run it:
bun permissions.test.ts