indexed.digital
Back to posts

How I dumped 14,000 crypto traders from a scanner app with exposed Supabase keys


How I dumped 14,000 crypto traders from a scanner app with exposed Supabase keys

CryptoXScanner is a crypto trading tool. You sign up, connect your exchange accounts, set up Telegram alerts, and it watches the markets for you.

The entire user database was readable through an unauthenticated Supabase API call. 14,021 users, full records, no restrictions.

The setup

The site uses Supabase as its backend with Auth0 for authentication. The Supabase anon key was in the frontend source, which is normal. What's not normal is that the key had unrestricted read access to every row in the users table.

One GET request:

GET /rest/v1/users?select=*&limit=1000&offset=0

Returns everything. Paginate through with offset and you have the full database in about 15 batches.

What leaked

Every user record contains:

FieldExample
nameReal full names from Google OAuth
emailPersonal Gmail, Hotmail, Yahoo, iCloud, Yandex accounts
auth0_id`google-oauth2
telegram_idNumeric Telegram user IDs
telegram_alertWhether alerts are enabled
mexc_uidMEXC exchange user IDs
created_atAccount creation timestamp

The user base is heavily international. Lots of Turkish names (Mehmet, Emre, Mustafa), Arabic names, Russian, Indonesian, Pakistani users. Registration dates start February 2024 and run through early 2026.

The Auth0 IDs are particularly interesting. For Google OAuth users, the format google-oauth2|NUMERIC_ID contains the Google user ID, which can be used to look up Google profiles. For email/password users, the auth0|HEX format identifies them in Auth0's system.

The Telegram IDs are also worth noting. If someone has your Telegram numeric ID, they can use it to correlate your Telegram account with your real identity from this leak. A user named "klic klac" at klacklic29@gmail.com has Telegram ID 1471886557 with alerts turned on. That's enough to find them on Telegram and know their real email, and potentially what crypto positions they're watching.

The MEXC exchange UIDs, where present, link these accounts directly to a centralized exchange. Someone cross-referencing this data with other breaches could piece together trading activity.

No passwords, but that's not the point

Supabase stores password hashes in the internal auth.users table, which wasn't accessible with the anon key. And most users signed in through Google OAuth anyway, so there aren't that many password hashes to begin with.

But the combination of real name + email + Telegram ID + exchange UID is plenty. For 14,000 crypto traders, that's a phishing kit waiting to happen. You know who they are, how they trade, and how to reach them.

The fix

Enable Row Level Security on the users table. With Supabase, the anon key is expected to be public. RLS is what gates access.

ALTER TABLE users ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Users can only read own record"
  ON users FOR SELECT
  USING (auth.uid() = id);