Reserved and Unavailable Usernames

The names nobody may claim as a PhenomApp username or display name, and the rule each category is matched by. Covers internal staff mailboxes, roles (root, admin, support, help), brand, system words, and the terms-of-service blocklist — plus what this list deliberately does NOT catch.

What a “handle” is here

One value, two columns. users.display_name and users.username hold the same idea — the person’s public handle — and setDisplayName() writes both from a single variable so they cannot drift apart. It renders as @handle on the public profile card and next to the person’s face on every Phenom Event they publish.

Until PhenomApp #835 (2026-09-15) that field had no format rule and no reserved list. The onboarding gate checked three things: the value is not empty, it is not a raw Cognito or Matrix identifier, and nobody else already holds it. That was all. support, noreply, admin and any slur were first-come, first-served.

Two different refusals

The list separates them because they deserve different words at the UI, and different judgement when somebody appeals.

Reason Meaning What the app says
reserved The name belongs to the company or to a role. Someone holding it can impersonate us — @support messaging users in chat is a phishing primitive. That username is reserved — try another.
offensive The name violates the terms of service. That username isn’t allowed — try another.

Neither message names the term that matched. Telling somebody exactly which word tripped the filter is a map for getting around it.

Normalisation

Every handle is reduced to one comparison form before it is compared to anything. In order:

  1. NFKD decomposition — ádmín and fullwidth 4dmin lose their decorations.
  2. Casefold — Admin and ADMIN are admin.
  3. Leetspeak fold — 0→o, 1→i, 3→e, 4→a, 5→s, 7→t, 8→b, @→a, $→s, !→i, |→i, +→t. So 4dm1n, @dm!n and 5upp0r7 land on admin, admin and support.
  4. Strip everything outside a-z0-9 — A.D-M_I N is admin.

The strip is also what lets a single entry cover every spelling of a compound: one phenomsupport entry catches phenom_support, phenom-support, phenom.support and Phenom Support.

For token matching the handle is also split on its separators, so admin_matt is the two tokens admin and matt.

The three match rules

The rule is chosen per category, not per term, and the choice is the whole design. One rule for everything is wrong in both directions.

Rule Matches when Trade-off
exact the normalised handle equals the term Safest. Reserves the bare name and nothing else.
token exact, or the term is one of the handle’s separator-delimited tokens Catches the compound (phenom_support), lets a longer word through (supportive is one token and is not support).
fragment the term appears anywhere inside the normalised handle Catches padding (xx_nigger_xx). Also the Scunthorpe trap, so almost nothing qualifies.

Category 1 — Slurs and hate terms

Rule: fragment · Reason: offensive · 13 terms

Deliberately tiny. A term earns fragment matching only if no ordinary word, name or place contains it. Terms whose fragment would eat real words are in category 2 instead — spic (spicy), coon (raccoon), chink (a chink of light), retard (flame retardant), kike (Kiké, a Spanish nickname for Enrique). Those are real handles belonging to real people, and blocking them to catch a padded slur is a bad trade.

nigger              niggers             nigga               niggas
faggot              faggots             hitler              kkk
pedophile           paedophile          childporn           childpornography
bestiality

Category 2 — Profanity, sexual and violent terms

Rule: token · Reason: offensive · 87 terms

Whole-token only, so assassin keeps its ass and the residents of Scunthorpe keep their town. Padding these (xxfuckxx) walks through by design; that is the price of not blocking real names, and category 1 is where the terms worth paying false positives for live.

fuck                fucker              fuckers             fucking             motherfucker
shit                shithead            bullshit            cunt                cunts
bitch               bitches             bastard             asshole             assholes
arsehole            ass                 arse                dick                cock
prick               pussy               twat                wank                wanker
whore               slut                bollocks            piss                anal
blowjob             boner               boobs               clit                clitoris
cum                 cumshot             deepthroat          dildo               ejaculate
handjob             hentai              incest              jizz                masturbate
masturbation        milf                nipples             penis               porn
porno               pornhub             rimjob              semen               tits
titties             titty               vagina              xxx                 zoophilia
rape                rapist              molest              molester            pedo
jailbait            kys                 killyourself        genocide            nazi
nazis               heilhitler          whitepower          klan                spic
coon                chink               gook                wetback             tranny
trannies            retard              retarded            kike                fag
fags                dyke

Category 3 — Internal staff mailboxes

Rule: exact · Reason: reserved · 42 terms

The local part of every internal address: the AWS WorkMail groups (see The Phenom App Group Email Accounts), the individual staff mailboxes, and the build/bot senders.

Exact match only, and that is deliberate. matt, logan, jon and aaron are ordinary first names. Token-matching them would block matt_the_dog and logans_run for no impersonation gain. What is being protected is the bare handle that reads as “this is that mailbox”.

When a mailbox is added or removed in WorkMail, this list has to follow.

accounts            beta                careers             contact             dev
devops              feedback            int                 internal            jobs
legal               media               partners            press               sales
systems             aaron               aaronsilverman      il                  ilena
ilenalogan          jon                 jonathan            jonathanhart        logan
m                   matt                matthew             matthewstevens      moneypenny
phenomjon           q                   silverman           smsmatt             zorin
agent               androidbuildbot     build               builder             buildbot
drop                sanmarcsoft

Category 4 — Roles and authority

Rule: token · Reason: reserved · 27 terms

The four M named explicitly — root, admin, support, help — plus the rest of the authority vocabulary.

Token match, because here the impersonation shape is the compound: phenom_support, admin_matt, official-help. The cost is that legitimate compounds using these words are refused too. That is accepted: the words are narrow and authority-signalling, and the alternative is an @phenom_support account we do not control.

abuse               admin               administrator       admins
billing             customercare        customerservice     customersupport
donotreply          help                helpdesk            hostmaster
moderator           moderators          noreply             official
postmaster          root                security            staff
superuser           support             sysadmin            sysop
trustandsafety      verified            webmaster

Category 5 — Brand

Rule: exact · Reason: reserved · 21 terms

Exact rather than token, so an enthusiast can still be phenom_hunter or phenom_fan. The impersonating compounds are enumerated individually instead, and separator stripping means one entry covers every spelling of each.

phenom              phenoms             phenomapp           phenomearth
thephenom           thephenomapp        phenomadmin         phenomhelp
phenomhq            phenommod           phenommoderator     phenomofficial
phenomsecurity      phenomstaff         phenomsupport       phenomteam
officialphenom      codetalker          trusteddit          trustedditsupport
verifieddit

Category 6 — System, routing and placeholder words

Rule: exact · Reason: reserved · 93 terms

Names that would read as infrastructure, as a URL path, or as the absence of a name — null, undefined, deleted, api, www. Exact only: these are cheap to reserve and expensive to token-match, because news_feed, sound_system and my_profile are all perfectly good handles.

about               account             all                 android             anon
anonymous           api                 app                 apps                assets
auth                blog                bot                 bots                callback
cdn                 channel             console             create              dashboard
deleted             deleteduser         delete              demo                discover
dns                 edit                everyone            example             explore
faq                 false               favicon             feed                ftp
guest               health              here                home                imap
index               ios                 login               logout              mail
me                  mobile              my                  nan                 new
news                nil                 nobody              none                notifications
null                oauth               ping                policy              pop
portal              privacy             profile             profiles            redirect
register            robots              sample              search              service
services            settings            signin              signup              sitemap
smtp                static              status              system              temp
terms               test                testing             tmp                 true
undefined           unknown             user                username            users
web                 www                 you

Where it is enforced

HasuraAPIAdapter.setDisplayName() — the single choke point that both handle-writing screens go through, so the list cannot be live on one and not the other:

  • DisplayNameGate, the blocking onboarding modal
  • ProfileScreen, where an existing user changes their handle

The check runs before the availability query. A name nobody may have is not a question worth asking the server. Both screens also check locally as the person types, so the answer arrives without a round trip.

A rejection raises ReservedHandleError, which is deliberately not DisplayNameTakenError. “Somebody else has that” and “nobody may have that” are different answers.

What this does NOT do

Stated plainly, because a blocklist that is believed to be complete is worse than one known to be partial.

  • It is client-side. It is bypassable by anyone talking to Hasura directly with a user JWT. To be authoritative the same terms have to land as a Postgres CHECK or a Hasura permission on the users update. That is a phenom-backend change and has not been made.
  • It does not reclaim handles already held. If an account on production currently holds one of these names, this list does not take it away. That needs a query against production and a decision from the owner.
  • Repeated characters are not collapsed. fuuuck passes. Collapsing runs would break bookkeeper and aaron.
  • Cyrillic and Greek homoglyphs are not folded. аdmin with a Cyrillic а is a different string.
  • Padded profanity passes the token list by design (xxfuckxx), which is the stated price of not blocking real names.
  • It does not cover users.name, the full name. Only the handle columns.

Changing the list

The source of truth is PhenomApp/app/utils/reservedHandles.ts. This page is the human-readable copy of it; change the code, then change this page in the same PR.

Two invariants are enforced by the test suite and will fail CI if broken:

  • every term is already in normal form (lowercase, a-z0-9 only) — a term that is not could never match anything, because the handle it is compared against always is;
  • no category contains a duplicate term.

Before adding a term to the fragment list, check it against ordinary English words, surnames, and place names. That list is small on purpose.

Total across all six categories: 283 terms.