Skip to content

fix: prevent users from inviting themselves in referral flow#386

Closed
jhosepm352-design wants to merge 1 commit into
profullstack:masterfrom
jhosepm352-design:fix/prevent-self-invites-v3
Closed

fix: prevent users from inviting themselves in referral flow#386
jhosepm352-design wants to merge 1 commit into
profullstack:masterfrom
jhosepm352-design:fix/prevent-self-invites-v3

Conversation

@jhosepm352-design
Copy link
Copy Markdown
Contributor

Prevents users from inviting their own email address in the referral flow. Also improves the error message to explicitly notify the user when they try to invite themselves.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Jun 4, 2026

Greptile Summary

This PR adds a self-invite guard to the referral POST endpoint: the authenticated user's email is stripped from the candidate list before any invites are sent, and a targeted "You cannot invite yourself" error is returned when the resulting valid-email list is empty. It also introduces deduplication via Set, raises the raw-input ceiling to 200, and caps actual processed invites at 20.

  • The self-invite filter relies on user.email?.toLowerCase(), but if user.email is undefined the guard silently no-ops — every email passes the e !== undefined check and self-invites are not blocked.
  • The onlySelf heuristic for selecting the error message can incorrectly return "You cannot invite yourself" for submissions that contain only syntactically invalid addresses (with no self-email present), because e === userEmail degrades to e === undefined when the user's email is unset.

Confidence Score: 3/5

The change introduces a self-invite guard that silently no-ops for accounts where user.email is undefined, meaning the feature's core goal is not reliably enforced.

The self-invite filter compares email strings against user.email?.toLowerCase(), but when user.email is undefined the comparison degrades to e !== undefined, which is always true for any string — every email passes through unfiltered. The onlySelf error-message branch has the same blind spot and can mislead users with a 'You cannot invite yourself' message when all they submitted was a syntactically invalid address. Both issues occur on the changed code path and affect the stated purpose of the PR.

src/app/api/referrals/route.ts — the self-invite guard and the error-message heuristic both need attention around the user.email undefined case.

Important Files Changed

Filename Overview
src/app/api/referrals/route.ts Adds self-invite prevention, deduplication, and a new two-tier rate-limit (200 raw entries / 20 valid invites). The self-invite guard silently bypasses when user.email is undefined, and the onlySelf error-message heuristic can misfire in the same scenario.

Reviews (1): Last reviewed commit: "fix: prevent users from inviting themsel..." | Re-trigger Greptile

Comment on lines +85 to +88
const userEmail = user.email?.toLowerCase();
const validEmails = Array.from(
new Set(normalizedEmails.filter((e: string) => emailRegex.test(e) && e !== userEmail))
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 user.email is typed as string | undefined in Supabase Auth — the optional-chain on line 85 confirms the developer knows this. When userEmail resolves to undefined, the filter condition e !== userEmail becomes e !== undefined, which is always true for any email string. That means the entire self-invite guard is silently bypassed for accounts without a stored email (e.g. certain OAuth providers), and the PR's primary goal is not met for those users.

Suggested change
const userEmail = user.email?.toLowerCase();
const validEmails = Array.from(
new Set(normalizedEmails.filter((e: string) => emailRegex.test(e) && e !== userEmail))
);
const userEmail = user.email?.trim().toLowerCase();
if (!userEmail) {
return NextResponse.json(
{ error: "Unable to determine your email address" },
{ status: 400 }
);
}
const validEmails = Array.from(
new Set(normalizedEmails.filter((e: string) => emailRegex.test(e) && e !== userEmail))
);

Comment on lines 90 to +96
if (validEmails.length === 0) {
const onlySelf = normalizedEmails.every(e => e === userEmail || !emailRegex.test(e));
return NextResponse.json(
{ error: onlySelf ? "You cannot invite yourself" : "No valid email addresses provided" },
{ status: 400 }
);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The onlySelf heuristic has a false-positive when userEmail is undefined: the condition e === userEmail becomes e === undefined, which is always false for email strings, so onlySelf falls through entirely to !emailRegex.test(e). Any submission consisting purely of syntactically invalid addresses (e.g. ["notanemail"]) then reports "You cannot invite yourself" even though no self-invite was attempted. Tightening the guard to require at least one entry that matches userEmail avoids the mislead.

Suggested change
if (validEmails.length === 0) {
const onlySelf = normalizedEmails.every(e => e === userEmail || !emailRegex.test(e));
return NextResponse.json(
{ error: onlySelf ? "You cannot invite yourself" : "No valid email addresses provided" },
{ status: 400 }
);
}
if (validEmails.length === 0) {
const hasSelfEntry = userEmail !== undefined && normalizedEmails.some(e => e === userEmail);
const onlySelf = hasSelfEntry && normalizedEmails.every(e => e === userEmail || !emailRegex.test(e));
return NextResponse.json(
{ error: onlySelf ? "You cannot invite yourself" : "No valid email addresses provided" },
{ status: 400 }
);
}

@ralyodio ralyodio closed this Jun 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants