Supabase Security
Tip
Apprenez & pratiquez AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Soutenez HackTricks
- Consultez les subscription plans!
- Rejoignez le đŹ Discord group ou le telegram group ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des hacking tricks en soumettant des PRs aux HackTricks et HackTricks Cloud github repos.
Informations de base
Comme indiqué sur leur landing page : Supabase est une alternative open source à Firebase. Démarrez votre projet avec une base de données Postgres, Authentication, instant APIs, Edge Functions, Realtime subscriptions, Storage, and Vector embeddings.
Sous-domaine
Lorsque un projet est créé, lâutilisateur reçoit gĂ©nĂ©ralement un sous-domaine supabase.co tel que : jnanozjdybtpqgcwhdiz.supabase.co
Configuration de la base de données
Tip
This data can be accessed from a link like
https://supabase.com/dashboard/project/<project-id>/settings/database
Cette database sera dĂ©ployĂ©e dans une rĂ©gion AWS, et pour sây connecter il est possible de le faire en se connectant Ă : postgres://postgres.jnanozjdybtpqgcwhdiz:[YOUR-PASSWORD]@aws-0-us-west-1.pooler.supabase.com:5432/postgres (cela a Ă©tĂ© créé en us-west-1).
Le mot de passe est le mot de passe choisi prĂ©cĂ©demment par lâutilisateur.
Ainsi, comme le sous-domaine est connu et quâil est utilisĂ© comme nom dâutilisateur et que les rĂ©gions AWS sont limitĂ©es, il pourrait ĂȘtre possible dâessayer de brute force the password.
Cette section contient aussi des options pour :
- Reset the database password
- Configure connection pooling
- Configure SSL: Reject plan-text connections (by default they are enabled)
- Configure Disk size
- Apply network restrictions and bans
Configuration de lâAPI
Tip
This data can be accessed from a link like
https://supabase.com/dashboard/project/<project-id>/settings/api
LâURL pour accĂ©der Ă lâAPI Supabase de votre projet ressemblera Ă : https://jnanozjdybtpqgcwhdiz.supabase.co.
anon api keys
Elle gĂ©nĂ©rera aussi une anon API key (role: "anon"), comme : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQ5OTI3MTksImV4cCI6MjAzMDU2ODcxOX0.sRN0iMGM5J741pXav7UxeChyqBE9_Z-T0tLA9Zehvqk que lâapplication devra utiliser pour contacter lâAPI exposĂ©e dans notre exemple dans
Il est possible de trouver lâAPI REST pour contacter cette API dans les docs, mais les endpoints les plus intĂ©ressants seraient :
Signup (/auth/v1/signup)
``` POST /auth/v1/signup HTTP/2 Host: id.io.net Content-Length: 90 X-Client-Info: supabase-js-web/2.39.2 Sec-Ch-Ua: "Not-A.Brand";v="99", "Chromium";v="124" Sec-Ch-Ua-Mobile: ?0 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQ5OTI3MTksImV4cCI6MjAzMDU2ODcxOX0.sRN0iMGM5J741pXav7UxeChyqBE9_Z-T0tLA9Zehvqk User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.60 Safari/537.36 Content-Type: application/json;charset=UTF-8 Apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQ5OTI3MTksImV4cCI6MjAzMDU2ODcxOX0.sRN0iMGM5J741pXav7UxeChyqBE9_Z-T0tLA9Zehvqk Sec-Ch-Ua-Platform: "macOS" Accept: */* Origin: https://cloud.io.net Sec-Fetch-Site: same-site Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: https://cloud.io.net/ Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en-US;q=0.9,en;q=0.8 Priority: u=1, i{âemailâ:âtest@exmaple.comâ,âpasswordâ:âSomeCOmplexPwd239.â}
</details>
<details>
<summary>Connexion (/auth/v1/token?grant_type=password)</summary>
POST /auth/v1/token?grant_type=password HTTP/2 Host: hypzbtgspjkludjcnjxl.supabase.co Content-Length: 80 X-Client-Info: supabase-js-web/2.39.2 Sec-Ch-Ua: âNot-A.Brandâ;v=â99â, âChromiumâ;v=â124â Sec-Ch-Ua-Mobile: ?0 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQ5OTI3MTksImV4cCI6MjAzMDU2ODcxOX0.sRN0iMGM5J741pXav7UxeChyqBE9_Z-T0tLA9Zehvqk User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.60 Safari/537.36 Content-Type: application/json;charset=UTF-8 Apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQ5OTI3MTksImV4cCI6MjAzMDU2ODcxOX0.sRN0iMGM5J741pXav7UxeChyqBE9_Z-T0tLA9Zehvqk Sec-Ch-Ua-Platform: âmacOSâ Accept: / Origin: https://cloud.io.net Sec-Fetch-Site: same-site Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: https://cloud.io.net/ Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en-US;q=0.9,en;q=0.8 Priority: u=1, i
{âemailâ:âtest@exmaple.comâ,âpasswordâ:âSomeCOmplexPwd239.â}
</details>
Ainsi, chaque fois que vous découvrez un client utilisant supabase avec le sous-domaine qui lui a été attribué (il est possible qu'un sous-domaine de l'entreprise ait un CNAME pointant vers leur sous-domaine supabase), vous pouvez essayer de **créer un nouveau compte sur la plateforme en utilisant l'API supabase**.
### Clés API secret / service_role
Une clé API secrÚte sera également générée avec **`role: "service_role"`**. Cette clé API doit rester secrÚte car elle pourra contourner la **Row Level Security**.
La clé API ressemble à ceci : `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTcxNDk5MjcxOSwiZXhwIjoyMDMwNTY4NzE5fQ.0a8fHGp3N_GiPq0y0dwfs06ywd-zhTwsm486Tha7354`
### JWT Secret
Un **JWT Secret** sera également généré afin que l'application puisse **créer et signer des tokens JWT personnalisés**.
## Authentification
### Inscription
> [!TIP]
> Par **défaut** supabase permettra aux **nouveaux utilisateurs de créer des comptes** sur votre projet en utilisant les endpoints API mentionnés précédemment.
Cependant, ces nouveaux comptes, par dĂ©faut, **devront valider leur adresse eâmail** pour pouvoir se connecter au compte. Il est possible d'activer **"Allow anonymous sign-ins"** pour permettre aux personnes de se connecter sans vĂ©rifier leur adresse eâmail. Cela pourrait donner accĂšs Ă des **donnĂ©es inattendues** (ils obtiennent les rĂŽles `public` et `authenticated`).\
C'est une trÚs mauvaise idée car supabase facture par utilisateur actif, donc des personnes pourraient créer des utilisateurs, se connecter et supabase facturera pour ceux-ci :
<figure><img src="../images/image (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
#### Auth : application cÎté serveur des restrictions d'inscription
Masquer le bouton d'inscription dans le frontend ne suffit pas. Si le **serveur Auth autorise toujours les inscriptions**, un attaquant peut appeler l'API directement avec la clé publique `anon` et créer des utilisateurs arbitraires.
Test rapide (depuis un client non authentifié) :
```bash
curl -X POST \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
-H "Content-Type: application/json" \
-d '{"email":"attacker@example.com","password":"Sup3rStr0ng!"}' \
https://<PROJECT_REF>.supabase.co/auth/v1/signup
Durcissement attendu :
- DĂ©sactiver les inscriptions par email/mot de passe dans le Dashboard : Authentication â Providers â Email â Disable sign ups (invite-only), ou dĂ©finir lâĂ©quivalent dans GoTrue.
- VĂ©rifier que lâAPI renvoie maintenant un code 4xx Ă lâappel prĂ©cĂ©dent et quâaucun nouvel utilisateur nâest créé.
- Si vous dépendez des invitations ou du SSO, assurez-vous que tous les autres providers sont désactivés sauf si explicitement nécessaires.
RLS and Views: contournement dâĂ©criture via PostgREST
Utiliser une Postgres VIEW pour « masquer » des colonnes sensibles et lâexposer via PostgREST peut modifier la façon dont les privilĂšges sont Ă©valuĂ©s. Dans PostgreSQL :
- Les vues ordinaires sâexĂ©cutent par dĂ©faut avec les privilĂšges du propriĂ©taire de la view (definer semantics). Dans PG â„15, vous pouvez opter pour
security_invoker. - Row Level Security (RLS) sâapplique aux tables de base. Les propriĂ©taires des tables contournent le RLS sauf si
FORCE ROW LEVEL SECURITYest défini sur la table. - Les vues updatables peuvent accepter des INSERT/UPDATE/DELETE qui sont ensuite appliqués à la table de base. Sans
WITH CHECK OPTION, des Ă©critures qui ne correspondent pas au prĂ©dicat de la view peuvent tout de mĂȘme rĂ©ussir.
Schéma de risque observé sur le terrain :
- Une view ne contenant que certaines colonnes est exposĂ©e via Supabase REST et son accĂšs est accordĂ© Ă
anon/authenticated. - PostgREST autorise du DML sur la view updatable et lâopĂ©ration est Ă©valuĂ©e avec les privilĂšges du propriĂ©taire de la view, contournant de fait les politiques RLS prĂ©vues sur la table de base.
- ConsĂ©quence : des clients Ă faible privilĂšge peuvent modifier en masse des lignes (p. ex. bios/avatars de profil) quâils ne devraient pas pouvoir modifier.
Ăcriture illustrative via la view (tentative depuis un client public) :
curl -X PATCH \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
-H "Content-Type: application/json" \
-H "Prefer: return=representation" \
-d '{"bio":"pwned","avatar_url":"https://i.example/pwn.png"}' \
"https://<PROJECT_REF>.supabase.co/rest/v1/users_view?id=eq.<victim_user_id>"
Checklist de durcissement pour les vues et RLS :
- PrivilĂ©giez lâexposition des tables de base avec des autorisations explicites au moindre privilĂšge et des politiques RLS prĂ©cises.
- Si vous devez exposer une vue :
- Rendez-la non modifiable (par ex., inclure des expressions/jointures) ou refusez
INSERT/UPDATE/DELETEsur la vue pour tous les rĂŽles non fiables. - Appliquez
ALTER VIEW <v> SET (security_invoker = on)pour que les privilĂšges de lâinvocateur soient utilisĂ©s au lieu de ceux du propriĂ©taire. - Sur les tables de base, utilisez
ALTER TABLE <t> FORCE ROW LEVEL SECURITY;afin que mĂȘme les propriĂ©taires soient soumis au RLS. - Si vous autorisez des Ă©critures via une vue modifiable, ajoutez
WITH [LOCAL|CASCADED] CHECK OPTIONet des RLS complĂ©mentaires sur les tables de base pour garantir que seules les lignes autorisĂ©es peuvent ĂȘtre Ă©crites/modifiĂ©es. - Dans Supabase, Ă©vitez dâaccorder Ă
anon/authenticateddes privilĂšges dâĂ©criture sur les vues sauf si vous avez vĂ©rifiĂ© le comportement end-to-end avec des tests.
Detection tip:
- Depuis un user de test
anonetauthenticated, tentez toutes les opérations CRUD sur chaque table/vue exposée. Toute écriture réussie alors que vous attendiez un refus indique une mauvaise configuration.
Sondage CRUD piloté par OpenAPI depuis les rÎles anon/auth
PostgREST expose un document OpenAPI que vous pouvez utiliser pour énumérer toutes les ressources REST, puis sonder automatiquement les opérations autorisées depuis des rÎles peu privilégiés.
RĂ©cupĂ©rez lâOpenAPI (fonctionne avec la clĂ© publique anon) :
curl -s https://<PROJECT_REF>.supabase.co/rest/v1/ \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
-H "Accept: application/openapi+json" | jq '.paths | keys[]'
ModĂšle de sonde (exemples):
- Lire une seule ligne (sâattendre Ă 401/403/200 selon RLS):
curl -s "https://<PROJECT_REF>.supabase.co/rest/v1/<table>?select=*&limit=1" \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>"
- Tester que UPDATE est bloquĂ© (utilisez un filtre inexistant pour Ă©viter dâaltĂ©rer les donnĂ©es pendant les tests) :
curl -i -X PATCH \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
-H "Content-Type: application/json" \
-H "Prefer: return=minimal" \
-d '{"__probe":true}' \
"https://<PROJECT_REF>.supabase.co/rest/v1/<table_or_view>?id=eq.00000000-0000-0000-0000-000000000000"
- Vérifier si INSERT est bloqué :
curl -i -X POST \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
-H "Content-Type: application/json" \
-H "Prefer: return=minimal" \
-d '{"__probe":true}' \
"https://<PROJECT_REF>.supabase.co/rest/v1/<table_or_view>"
- Vérifier que DELETE est bloqué:
curl -i -X DELETE \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
"https://<PROJECT_REF>.supabase.co/rest/v1/<table_or_view>?id=eq.00000000-0000-0000-0000-000000000000"
Recommandations:
- Automatisez les tests précédents pour
anonet pour un utilisateurauthenticatedminimal, et intĂ©grez-les dans la CI pour dĂ©tecter les rĂ©gressions. - Traitez chaque table/vue/fonction exposĂ©e comme une surface de premier ordre. Ne supposez pas quâune vue âhĂ©riteâ de la mĂȘme posture RLS que ses tables de base.
Mots de passe & sessions
Il est possible dâindiquer la longueur minimale du mot de passe (par dĂ©faut), les exigences (aucune par dĂ©faut) et dâinterdire lâutilisation de leaked passwords.
Il est recommandĂ© dâamĂ©liorer les exigences car celles par dĂ©faut sont faibles.
- Sessions utilisateur : Il est possible de configurer le fonctionnement des sessions (timeouts, 1 session par utilisateurâŠ)
- Protection contre les bots et les abus : Il est possible dâactiver Captcha.
ParamĂštres SMTP
Il est possible de configurer un serveur SMTP pour envoyer des e-mails.
ParamÚtres avancés
- DĂ©finir le temps dâexpiration des access tokens (3600 par dĂ©faut)
- Activer la détection et la révocation des refresh tokens potentiellement compromis ainsi que le timeout
- MFA : Indiquer combien de facteurs MFA peuvent ĂȘtre enregistrĂ©s simultanĂ©ment par utilisateur (10 par dĂ©faut)
- Max Direct Database Connections : Nombre maximal de connexions utilisĂ©es pour lâauth (10 par dĂ©faut)
- Max Request Duration : DurĂ©e maximale autorisĂ©e pour une requĂȘte Auth (10s par dĂ©faut)
Stockage
Tip
Supabase permet de stocker des fichiers et de les rendre accessibles via une URL (il utilise S3 buckets).
- DĂ©finir la taille maximale dâupload (par dĂ©faut 50MB)
- La connexion S3 est fournie avec une URL comme :
https://jnanozjdybtpqgcwhdiz.supabase.co/storage/v1/s3 - Il est possible de demander des S3 access key qui sont composĂ©es dâun
access key ID(ex.a37d96544d82ba90057e0e06131d0a7b) et dâunsecret access key(ex.58420818223133077c2cec6712a4f909aec93b4daeedae205aa8e30d5a860628)
Edge Functions
Il est aussi possible de stocker des secrets dans supabase qui seront accessibles by edge functions (ils peuvent ĂȘtre créés et supprimĂ©s depuis le web, mais il nâest pas possible dâaccĂ©der directement Ă leur valeur).
References
- Building Hacker Communities: Bug Bounty Village, getDisclosedâs Supabase Misconfig, and the LHE Squad (Ep. 133) â YouTube
- Critical Thinking Podcast â Episode 133 page
- Supabase: Row Level Security (RLS)
- PostgreSQL: Row Security Policies
- PostgreSQL: CREATE VIEW (security_invoker, check option)
- PostgREST: OpenAPI documentation
Tip
Apprenez & pratiquez AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Soutenez HackTricks
- Consultez les subscription plans!
- Rejoignez le đŹ Discord group ou le telegram group ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des hacking tricks en soumettant des PRs aux HackTricks et HackTricks Cloud github repos.
HackTricks Cloud

