Summary
The leaderboard table still grants INSERT and DELETE to authenticated users. A client can delete their own row and re-insert it with arbitrary xp, streak, sessions_joined, and badges values — bypassing the whole gamification security model.
Evidence
supabase/migrations/20260617000000_consolidate_rls_policies.sql:
CREATE POLICY "Users can insert leaderboard entry"
ON public.leaderboard FOR INSERT WITH CHECK (user_id = auth.uid());
CREATE POLICY "Users can delete leaderboard entry"
ON public.leaderboard FOR DELETE USING (user_id = auth.uid());
The recent hardening (20260730000001_secure_leaderboard_updates.sql, 20260803000002_enforce_leaderboard_score_immutability.sql) only covers UPDATE. INSERT and DELETE are unguarded.
Exploit
-- delete own row, then re-insert with a fabricated top score
delete from public.leaderboard where user_id = auth.uid();
insert into public.leaderboard (user_id, username, xp, streak, sessions_joined, badges)
values (auth.uid(), 'x', 2147483647, 9999, 999, '{top}');
This instantly puts the attacker at rank #1 in every leaderboard view and awards them top badges. Repeatable at any time.
Impact
- Leaderboard integrity completely broken; fake scores and badges.
- Undermines the anti-forgery guarantees documented in the 08-03 migration.
Suggested Fix
- Drop both
INSERT and DELETE policies for the leaderboard table and REVOKE INSERT, DELETE ON public.leaderboard FROM anon, authenticated;.
- Keep the existing SECURITY DEFINER
join_leaderboard RPC as the only legitimate row-creation path (it already zero-initializes the score fields).
Summary
The
leaderboardtable still grantsINSERTandDELETEto authenticated users. A client can delete their own row and re-insert it with arbitraryxp,streak,sessions_joined, andbadgesvalues — bypassing the whole gamification security model.Evidence
supabase/migrations/20260617000000_consolidate_rls_policies.sql:The recent hardening (
20260730000001_secure_leaderboard_updates.sql,20260803000002_enforce_leaderboard_score_immutability.sql) only coversUPDATE.INSERTandDELETEare unguarded.Exploit
This instantly puts the attacker at rank #1 in every leaderboard view and awards them top badges. Repeatable at any time.
Impact
Suggested Fix
INSERTandDELETEpolicies for the leaderboard table andREVOKE INSERT, DELETE ON public.leaderboard FROM anon, authenticated;.join_leaderboardRPC as the only legitimate row-creation path (it already zero-initializes the score fields).