Bug Description
The leaderboard table accepts arbitrary score values via direct Supabase client upserts from the frontend. Any authenticated user can set their score to any integer without the server verifying the increment is legitimate.
Steps to Reproduce
- Log in and capture the Supabase anon key and your user ID.
- Run:
await supabase.from('leaderboard')
.upsert({ user_id: '<your_id>', score: 999999 });
- Observe: your score is updated to 999999 on the public leaderboard.
Root Cause
Score updates are performed client-side with no backend validation endpoint or database trigger enforcing that scores only increase by legitimate amounts.
Impact
Leaderboard manipulation; unfair competition; loss of trust in the platform.
Proposed Fix
-- Prevent direct writes; use a Supabase Function instead
REVOKE UPDATE ON leaderboard FROM anon, authenticated;
-- Server-side function that only allows increments
CREATE OR REPLACE FUNCTION increment_score(points integer)
RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS $$
BEGIN
UPDATE leaderboard SET score = score + points
WHERE user_id = auth.uid() AND points > 0 AND points <= 100;
END;
$$;
Bug Description
The leaderboard table accepts arbitrary score values via direct Supabase client upserts from the frontend. Any authenticated user can set their score to any integer without the server verifying the increment is legitimate.
Steps to Reproduce
Root Cause
Score updates are performed client-side with no backend validation endpoint or database trigger enforcing that scores only increase by legitimate amounts.
Impact
Leaderboard manipulation; unfair competition; loss of trust in the platform.
Proposed Fix