{"record":{"id":"fad331c8e4f1761a","repo":"m1k1o/neko","slug":"cannot-access-clipboard","errorCode":null,"errorMessage":"cannot access clipboard","messagePattern":"cannot access clipboard","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/websocket/handler/clipboard.go","lineNumber":12,"sourceCode":"package handler\n\nimport (\n\t\"errors\"\n\n\t\"github.com/m1k1o/neko/server/pkg/types\"\n\t\"github.com/m1k1o/neko/server/pkg/types/message\"\n)\n\nfunc (h *MessageHandlerCtx) clipboardSet(session types.Session, payload *message.ClipboardData) error {\n\tif !session.Profile().CanAccessClipboard {\n\t\treturn errors.New(\"cannot access clipboard\")\n\t}\n\n\tif !session.IsHost() {\n\t\treturn errors.New(\"is not the host\")\n\t}\n\n\treturn h.desktop.ClipboardSetText(types.ClipboardText{\n\t\tText: payload.Text,\n\t\t// TODO: Send HTML?\n\t})\n}\n","sourceCodeStart":1,"sourceCodeEnd":24,"githubUrl":"https://github.com/m1k1o/neko/blob/b0f01cedea68893e85a3fd852c0521238c285695/server/internal/websocket/handler/clipboard.go#L1-L24","documentation":"clipboardSet in server/internal/websocket/handler/clipboard.go rejects any incoming clipboard-set message when the sending session's profile lacks CanAccessClipboard. The neko server gates clipboard access behind a per-session permission so only authorized users may read or write the remote machine's clipboard. The permission check deliberately runs before the host check.","triggerScenarios":"A WebSocket client sends a clipboard data message (handled by clipboardSet, dispatched from controlPaste or the anonymous clipboard handler) while session.Profile().CanAccessClipboard is false.","commonSituations":"Connecting a user whose member profile was created without CanAccessClipboard:true; an admin recently toggled profile permissions server-side but the client session was created earlier; embedding neko for read-only viewers who then attempt copy/paste into the remote desktop.","solutions":["Grant CanAccessClipboard: true in the session's profile when creating the session (config or membership provider).","Have the client hide/disable clipboard UI when its profile lacks the clipboard permission (profile is delivered to the client).","Reconnect the session after changing profiles so the new profile takes effect.","If using an external membership provider, verify it returns the clipboard flag correctly."],"exampleFix":"// before\nconfig.Member.Profile = types.MemberProfile{ CanWatch: true }\n// after\nconfig.Member.Profile = types.MemberProfile{ CanWatch: true, CanAccessClipboard: true }","handlingStrategy":"validation","validationCode":"// client-side, before sending clipboard data\nif (!session.profile.canAccessClipboard) {\n  throw new Error('clipboard access not permitted for this profile')\n}","typeGuard":"function canAccessClipboard(session) {\n  return typeof session.profile === 'object' && session.profile != null && session.profile.canAccessClipboard === true\n}","tryCatchPattern":"try {\n  socket.emit('clipboard/set', { text })\n} catch (e) {\n  if (e.message === 'cannot access clipboard') disableClipboardUI()\n}","preventionTips":["Set CanAccessClipboard in the member profile at session creation time.","Render clipboard UI conditionally based on the profile delivered to the client.","Re-authenticate/reconnect after permission changes so profiles refresh.","Audit external membership providers for correct flag mapping."],"tags":["websocket","permissions","clipboard"],"backgroundTag":"insufficient-permissions","analyzedSha":"b0f01cedea68893e85a3fd852c0521238c285695","analyzedAt":"2026-09-01T10:35:56.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}