The database they published
On 28 October 2026 Yapper Media LLC published yapper-db. The public history is one commit, ed6e440, at 17:02 UTC, message "First public copy: migrations, access rules dump (Oct 28), SQL tests." The README says the repository exists so people can read the access rules themselves.
This page is a read of that commit: the migration files, the access-rules dump dated 28 October 2026, and the test runner. No account was created. The SQL tests were not run. Nothing here is a procedure for calling those functions against the live service. The repository asks people who find a hole to email hello@yapin.gg, and asks them not to test other people's accounts.
The Next.js app, the realtime server, and the bot API are not in the repository. The company says so in the README. Rules in this dump can be stricter or looser than a screen in the app. Where the database allows something, the database will accept it even if a button hides it.
What the README says
| README, 28 Oct 2026 | The files in the same commit |
|---|---|
supabase/migrations/ is every migration ever applied, in order. The live database is the result of running these. |
563 SQL files, numbered 1 through 623. 107 numbers are absent. 46 numbers are used more than once. Number 300 is three files. A repeated number is not a single ordered version. |
| Three ids are swapped for placeholders. Nothing else is edited. | Migration 202 says its function bodies are the live definitions copied back on 17 October, "not older repo files: several were patched in place on the live database." Files 186, 187, and 282 say they were applied live under a different number, then renamed because that number was taken. |
| Each stage test runs migrations 001 through NN, as that stage existed when it shipped. | The test runner says the stand-in database stops at migration 025. Stage 621 sets its base to 24, loads a few later files, and replaces is_site_mod() with a shorter stand-in. 231 stage-test files exist. The highest is 621. 288 migration numbers have no stage file, including 622 and 623. |
| There has been no outside security audit. The app code is not here. | That part matches the repository. This page is not an audit either. It is a read of what they chose to publish. |
102 files say in the opening comment that the change was applied on the live database, in the SQL editor, or through a connected admin tool, and written down afterwards. The git history cannot show the order. There is one commit, made the day of the dump.
How much, and how fast
563 migration files, about 2.9 MB of SQL, from the 11 October 2026 launch to the 28 October dump. That is 17 days. Dated comments put a large block of the early schema on 13 and 14 October. File 077 says live events were applied on 14 October. File 186 records a 17 October report. File 322 records the 20 October signup raid. File 582 is 27 October. File 622 is dated 28 October in its own comment. File 623 is in the same published commit. The pace is on the order of 30 files a day, often edited in production and copied back.
The same comments record numbers the videos had not reached yet. File 534, attributed to Antic on 26 October, is "2x Shards for 48 hours to celebrate 100K users," ending 28 October at 11:00 UTC. The comment says Plus multiplies that bonus again, so the event is 2x for everyone and 3x with Plus. The function site_user_count() counts every profile row and is executable by any signed-in user. This read did not call it, so the 100,000 figure stays their figure. The videos had said 50,000 on 17 October and 87,000 on 24 October.
The function bot_order() ranks the public bot list with a paid boost of 2, 4, or 8. Terms section 12.6 says a Boost can hold a place in the top 20, 10, or 5. The multipliers in the function match that promise.
What the rules do lock
The dump of 28 October lists 202 tables, row level security on for every one of them, 179 policies, and 109 tables with security on and no policy. A table in that last group returns no rows to the anonymous or signed-in API roles. No file in the folder turns row level security off. A search of the text files found no API keys, session tokens, or private keys. The function that copies production environment variables into app_host.secrets is limited to the service role and returns names and lengths.
- Reading a message through the published policies requires access to that channel, plus history or the manage-messages permission. For a direct message, access means membership. A normal signed-in user is not given someone else's DMs by the policies read here.
- The staff message search
mod_user_messagesjoins servers, so direct-message rows drop out of it. - The CSAM case functions refuse the caller unless they are a site admin. The list those admins get includes email, signup IP, and message context.
- Listing webhooks requires the manage-webhooks permission. The list does not include the webhook token. The public OAuth lookup returns the app's name and owner, not the client secret.
call_e2eereturns whether a feature flag is on for a channel. It does not return call keys.- On 14 October, a person could set Plus, a verified name, badges, and a mute time on their own profile, because the row policy only checked "this is your row." File 085 revokes those column updates. A trigger that runs as the caller pins the same columns. The Stripe customer id was moved to
billing_customers, which has security on and no policy.
837 functions run with the owner's rights. 539 of them can be called by any signed-in user, and 16 by someone who is not signed in. The functions named on this page were read. The other several hundred were not. A quiet function in that set is still unreviewed.
Concerns in the current rules
One secret sits in front of every bot's event queue
Three functions are granted to users who are not signed in: gateway auth, gateway events, and gateway presence. They check one shared secret stored in Supabase Vault under the name gw_secret. The value is not in the repository. The auth function also checks that bot's own token. The events and presence functions, once the shared secret matches, take the list of bot ids from the caller.
Server-message events store the message text, the author, the channel, and the attachment path. Direct messages are not written into that queue. The events table has row level security, no policy, and a table grant to the anonymous role, so a direct table read is refused while security stays on. The gateway functions are the way around the table. A leak of that one secret exposes those queues and can mark bots as polling.
A site moderator can delete any message
The policy "yapper moderators delete messages" allows a delete when is_site_mod() is true. That function means the account is in site_moderators, is not suspended, and passed the staff two-factor check. The two-factor check is skipped when the staff_2fa flag is off. The policy has no channel check and no report check. It covers direct messages, because nothing in it limits the delete to a server.
A different policy lets a server moderator with manage-messages delete messages in that server. The privacy policy says staff look when something was reported, flagged, or required for safety or law. The delete rule does not say that. The app might. The app is not in this repository.
Staff can read server messages with no report in the function
mod_user_messages can be called by any signed-in user. The body requires staff, then returns message content, up to 100 rows. A site admin can read a user's messages in any server. A site moderator can read them except in a server owned by a site admin. No report id is an argument. Direct messages are excluded by the query, as noted above. can_access_channel also lets staff see private server channels that use role locks, under the same "not owned by a site admin" limit for ordinary mods. History still depends on the read-history permission, which does not treat staff as a special case, so that peek is channel visibility, not an automatic copy of every private room.
Some sensitive tables are granted to logged-out users
Twenty-five tables have row level security on, zero policies, and a grant to the anonymous role. The list includes billing_customers, email_log, login_attempts, signup_log, staff_reauth, and bot_events. With security on and no policy, those roles receive no rows. The grant is already there. Turning security off later, or adding a loose policy, would expose signup IPs, login attempts, billing customer ids, and staff password-recheck state.
Profiles are readable by any signed-in user, column by column. The readable columns include plus_until, badges, who may DM the account, and verify_required. That last column is the flag for accounts the site wants extra verification from. It is not limited to staff.
What the migration comments record
These are incidents the project wrote into its own SQL. The files present them as fixed. They are still the record of what shipped, and of how it was repaired, during the public launch.
| When | What the file says |
|---|---|
| 14 Oct | Own-row profile edits could grant Plus, a verified name, badges, and a self-unmute (bug 824f55ad). Profile links accepted javascript: URLs (bugs da7892d6, ae56ebe9). Anyone with Manage Roles could give themselves a higher role (bugs f89b9b9a, 4c4c0e4b). A guard written as security definer saw the database owner as the current user, so the "is this a normal user?" check never fired. File 049 says that guard was changed to run as the caller. |
| 15 Oct | One person with alternate accounts got 7 people auto-banned at "8 reports in an hour." A security report the same day limited who can read emojis and feature flags. New signups started being refused when the network matched a banned account. |
| File 149 | bot_api_post was still executable by any signed-in user and took a bot id, "so any signed-in user could post as any bot." The dump now grants that function to the service role only. The same file records 44 deadlocks a day from bot event updates. |
| 17 Oct | The database was at about 3.5 of 4 cores. Functions were patched on the live database and copied back (file 202). Slowmode could be skipped by editing one message. |
| 20 Oct | A signup raid came through the signup API with a solved bot check, one home IP per account, and mailboxes on domains the raider owned. The comment names throwaway-mail domains and says one of them had made about 5,400 accounts. Per-IP limits did not see it. File 322 adds a daily cap per mail domain. |
| 26 Oct | A site moderator who held Headquarters' Moderator role deleted most of Yapper Headquarters between 15:08 and 15:22 UTC, and nothing was logged (file 564). The same day, file 529 says scripts had signed up 103 accounts on 13-14 October and taken the 2-character names. Those accounts were renamed and the short names were held until the year 2999, "for ourselves," in Antic's words in the comment. |
| 27 Oct | One account created 9,421 group chats in half an hour. With five other accounts, 13,931 group chats that day, and no messages in them (file 582). The file adds caps after the fact. |
What this read does not settle
- The app, the realtime server, and the bot API are still unpublished. A safe database rule can sit under an unsafe server, and the reverse is also possible.
- The tests in the repository were not executed for this page. The runner, as published, does not replay the full migration list for the later stages.
- No query was sent to the live database. The wide grants are a latent risk for as long as row level security stays on. The published files contain schema and functions, and no customer rows.
- User totals in the videos and in file 534 are the operator's totals.
site_user_count()would count profiles for a signed-in user. Calling it would mean using an account, which this record did not do.
The privacy wording those rules sit under is on Privacy. The 100,000-user line and the paid bot boost sit next to the earlier marketing claims on Claims.