{"record":{"id":"34da16264f74d4ed","repo":"paperclipai/paperclip","slug":"unauthorized-peer","errorCode":"unauthorized_peer","errorMessage":"missing peer credentials","messagePattern":"missing peer credentials","errorType":"error_code","errorClass":"AuthorizationError","httpStatus":null,"severity":"error","filePath":"packages/tailscale-https-broker/src/authorization.ts","lineNumber":43,"sourceCode":"      | \"unauthorized_peer\"\n      | \"invalid_handle\"\n      | \"listener_ownership_mismatch\",\n    message: string,\n  ) {\n    super(message);\n    this.name = \"AuthorizationError\";\n  }\n}\n\n/**\n * Complete-mediation check run on every accepted connection before any request\n * is even decoded. Throws AuthorizationError(\"unauthorized_peer\") on any\n * mismatch. Supplemental-group-only membership does not satisfy the GID check\n * because peer.gid is the process's primary GID from SO_PEERCRED.\n */\nexport function authorizePeer(peer: PeerCredentials, policy: PeerPolicy): void {\n  if (!Number.isInteger(peer.uid) || !Number.isInteger(peer.gid)) {\n    throw new AuthorizationError(\"unauthorized_peer\", \"missing peer credentials\");\n  }\n  if (!policy.allowedUids.has(peer.uid)) {\n    throw new AuthorizationError(\"unauthorized_peer\", `uid ${peer.uid} not allowlisted`);\n  }\n  if (!policy.allowedGids.has(peer.gid)) {\n    throw new AuthorizationError(\"unauthorized_peer\", `gid ${peer.gid} not allowlisted`);\n  }\n}\n\n/** Generate an unguessable lease handle (256 bits, url-safe). */\nexport function generateLeaseHandle(): string {\n  return randomBytes(32).toString(\"base64url\");\n}\n\n/** Constant-time handle comparison to avoid timing oracles. */\nexport function handlesEqual(a: string, b: string): boolean {\n  const ab = Buffer.from(a, \"utf8\");\n  const bb = Buffer.from(b, \"utf8\");","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/paperclipai/paperclip/blob/120ae5428fa29bee300bcf806491cd4d965fbb7c/packages/tailscale-https-broker/src/authorization.ts#L25-L61","documentation":"AuthorizationError('unauthorized_peer'/'missing peer credentials') thrown by authorizePeer, the complete-mediation check run on every accepted broker connection before any request is decoded. The peer credential structure lacked usable uid/gid/pid values, so SO_PEERCRED identity could not be established and the connection is denied rather than treated as trusted.","triggerScenarios":"Thrown at packages/tailscale-https-broker/src/authorization.ts:43 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Connect via Tailscale HTTPS so peer credentials are present, or use an authorized local path."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"120ae5428fa29bee300bcf806491cd4d965fbb7c","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}