From 82d158d92c8e12832b463d28e0fe43869268d40a Mon Sep 17 00:00:00 2001 From: Saadi Myftija Date: Thu, 25 Sep 2025 19:42:59 +0200 Subject: [PATCH] fix: use higher entropy invite tokens (#2558) * fix: use higher entropy invite tokens We currently use CUIDs for invite tokens, which are generated using a pattern and are not cryptographically secure. This PR switches to a higher entropy string generated with `nanoid`. * Dedupe the invite emails in the application --- apps/webapp/app/models/member.server.ts | 27 ++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/apps/webapp/app/models/member.server.ts b/apps/webapp/app/models/member.server.ts index 82af3d01b..04c1df1b4 100644 --- a/apps/webapp/app/models/member.server.ts +++ b/apps/webapp/app/models/member.server.ts @@ -1,5 +1,9 @@ -import { prisma } from "~/db.server"; +import { type Prisma, prisma } from "~/db.server"; import { createEnvironment } from "./organization.server"; +import { customAlphabet } from "nanoid"; + +const tokenValueLength = 40; +const tokenGenerator = customAlphabet("123456789abcdefghijkmnopqrstuvwxyz", tokenValueLength); export async function getTeamMembersAndInvites({ userId, @@ -95,14 +99,19 @@ export async function inviteMembers({ throw new Error("User does not have access to this organization"); } - const created = await prisma.orgMemberInvite.createMany({ - data: emails.map((email) => ({ - email, - organizationId: org.id, - inviterId: userId, - role: "MEMBER", - })), - skipDuplicates: true, + const invites = [...new Set(emails)].map( + (email) => + ({ + email, + token: tokenGenerator(), + organizationId: org.id, + inviterId: userId, + role: "MEMBER", + } satisfies Prisma.OrgMemberInviteCreateManyInput) + ); + + await prisma.orgMemberInvite.createMany({ + data: invites, }); return await prisma.orgMemberInvite.findMany({