• Mahmoud Aglan's avatar
    fix(security): close coin minting and open write policies · f4eec81f
    Mahmoud Aglan authored
    Found while building the org/redeem layer; all exploitable with the public
    anon key that ships in realtime.js, or with a player's own session.
    
    - complete_match, award_coins and the match/queue functions were executable
      by anon and players: one REST call paid win coins to anyone. Service role
      only now; every caller is PHP with the service key.
    - battlepass.php credited whatever "coins" the request carried, to anyone,
      as often as asked. The server now decides the reward, needs an active
      season and an unlocked tier, and pays each tier once.
    - The legacy api/ludo.php let any player end any ludo match with any winners
      and get paid. It, api/domino.php and api/multiplayer.php were unused by the
      app and are removed.
    - Shop, challenges and daily reward wrote balances with the player's token,
      which only worked because players could PATCH their own coins over REST.
      They write with the service key now; the shop deducts only if the balance
      is unchanged (a double tap cannot pay twice), refunds if the grant fails,
      and records its transaction (the old insert used a missing column).
    - Policies: anyone could delete any ludo/domino/backgammon match, rewrite
      queues, groups and the theme, insert an "accepted" friendship with anyone
      and post into any chat. Writes are service-role only; every read and
      Realtime feed is unchanged. Group members read only their own memberships.
    - profiles-guard.sql (applied after this deploy): a player's token may change
      only cosmetic profile fields.
    
    Also the org-unify / redeem SQL layer and its contract (docs/redeem-contract.md).
    Co-Authored-By: 's avatarClaude Opus 5.5 <noreply@anthropic.com>
    f4eec81f
2026-10-26-security-lockdown.sql 4.73 KB