paperclipai/paperclip · error · AuthorizationError

unauthorized_peer

unauthorized_peer

Error message

missing peer credentials

What it means

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.

Source

Thrown at packages/tailscale-https-broker/src/authorization.ts:43

      | "unauthorized_peer"
      | "invalid_handle"
      | "listener_ownership_mismatch",
    message: string,
  ) {
    super(message);
    this.name = "AuthorizationError";
  }
}

/**
 * Complete-mediation check run on every accepted connection before any request
 * is even decoded. Throws AuthorizationError("unauthorized_peer") on any
 * mismatch. Supplemental-group-only membership does not satisfy the GID check
 * because peer.gid is the process's primary GID from SO_PEERCRED.
 */
export function authorizePeer(peer: PeerCredentials, policy: PeerPolicy): void {
  if (!Number.isInteger(peer.uid) || !Number.isInteger(peer.gid)) {
    throw new AuthorizationError("unauthorized_peer", "missing peer credentials");
  }
  if (!policy.allowedUids.has(peer.uid)) {
    throw new AuthorizationError("unauthorized_peer", `uid ${peer.uid} not allowlisted`);
  }
  if (!policy.allowedGids.has(peer.gid)) {
    throw new AuthorizationError("unauthorized_peer", `gid ${peer.gid} not allowlisted`);
  }
}

/** Generate an unguessable lease handle (256 bits, url-safe). */
export function generateLeaseHandle(): string {
  return randomBytes(32).toString("base64url");
}

/** Constant-time handle comparison to avoid timing oracles. */
export function handlesEqual(a: string, b: string): boolean {
  const ab = Buffer.from(a, "utf8");
  const bb = Buffer.from(b, "utf8");

View on GitHub (pinned to 120ae5428f)

Solutions

  1. Connect via Tailscale HTTPS so peer credentials are present, or use an authorized local path.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at packages/tailscale-https-broker/src/authorization.ts:43 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@120ae5428f (2026-08-18). Data as JSON: /api/errors/34da16264f74d4ed. Report an issue: GitHub.