Skip to content

fix(invites): one accepted invite per account (affiliates 0.3) - #111

Merged
ralyodio merged 1 commit into
masterfrom
aff-0.3
Oct 26, 2026
Merged

ralyodio merged 1 commit into
masterfrom
aff-0.3

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

What

  • Bump @profullstack/affiliates to ^0.3.0: an account can redeem ONE invite, enforced atomically in Postgres (aff_claim_invite() + unique index aff_invites_one_per_user), new reason already_invited.
  • acceptInvite drops its racy invitedBy() pre-check; the bonus is paid only on redeemInvite(...).ok. A second invite (sequential or concurrent) gets already_invited, pays nothing and stays unused.
  • supabase/migrations/019_affiliates_0_3.sql = the module's supabase-0.3.0-upgrade.sql.
  • Tests: concurrent double-accept (two simultaneous sign-ins, different invites: one paid, the other refused and still spendable) and a later second invite.

Why

Exposure audit: two simultaneous confirmed sign-ins with different invite cookies could both redeem and both pay.

DB

Applied to prod by hand before merge (backup smshub-aff-pre03-20261026T180832Z.dump), NOTIFY pgrst. Legacy duplicates (legacy_dup = 1): none.

🤖 Generated with Claude Code

…es 0.3)

Two confirmed sign-ins racing with different invite cookies could both pass
the invitedBy() pre-check, both redeem, and both pay. affiliates 0.3 claims
atomically (aff_claim_invite + unique index aff_invites_one_per_user), so the
bonus now rests on redeemInvite's result alone: already_invited pays nothing
and leaves the second invite unused. Migration 019 is the module's
supabase-0.3.0-upgrade.sql (applied to prod by hand, 0 legacy duplicates).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

ThreatCrush Security Scan

12 finding(s)

HIGH/CRITICAL: 2 | MEDIUM: 4 | LOW: 6

Severity Rule Location
HIGH sh-unquoted-expansion-destructive public/install.sh:67
HIGH sh-remote-script-execution public/install.sh:89
MEDIUM sh-remote-script-execution public/install.sh:133
MEDIUM js-open-redirect src/app/numbers/page.tsx:180
MEDIUM js-open-redirect src/components/inbox-client.tsx:35
MEDIUM js-unescaped-html-sink src/components/pit-footer.tsx:17
LOW secret-generic-credential src/lib/providers/__tests__/twilio.test.ts:24
LOW secret-generic-credential src/lib/providers/__tests__/twilio.test.ts:46
LOW secret-generic-credential src/lib/providers/__tests__/twilio.test.ts:60
LOW secret-generic-credential src/lib/providers/__tests__/twilio.test.ts:78
LOW secret-generic-credential supabase/config.toml:287
LOW secret-generic-credential supabase/config.toml:319

Snippets are redacted; ThreatCrush never prints matched credential material.

@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​profullstack/​affiliates@​0.2.0 ⏵ 0.3.076 +1100100 +192 +3100

View full report

@ralyodio
ralyodio merged commit 312325c into master Oct 26, 2026
12 checks passed
@ralyodio
ralyodio deleted the aff-0.3 branch October 26, 2026 18:11
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.

1 participant