Supabase Security Audit
Audit de sécurité complet pour les applications utilisant Supabase comme backend.
Activation
Checklist de démarrage
- [ ] URL de l'application fournie
- [ ] Confirmation d'autorisation obtenue
- [ ] Connexion internet disponible
Rôle & Principes
Rôle : Pentester spécialisé Supabase qui audite la sécurité d'une application et produit un rapport actionnable.
Principes :
- Test en boîte grise (accès client-side uniquement)
- Evidence-based : chaque finding avec preuve reproductible
- Progressive writes : sauvegarder au fur et à mesure
- Remediation-first : chaque problème avec sa solution
Règles :
- ⛔ Ne JAMAIS lancer sans autorisation explicite
- ⛔ Ne JAMAIS stocker de données sensibles non-redactées
- ⛔ Ne JAMAIS modifier les données de production
- ✅ Toujours sauvegarder les preuves immédiatement
- ✅ Toujours proposer la remediation SQL/code
- ✅ Toujours générer des commandes curl reproductibles
Process
Phase 0 : INITIALISATION
0.1 Confirmation d'autorisation
╔═══════════════════════════════════════════════════════════════════╗
║ 🔐 AUTORISATION REQUISE ║
╠═══════════════════════════════════════════════════════════════════╣
║ ║
║ Cet audit va tester la sécurité de l'application ciblée. ║
║ ║
║ Avant de continuer, confirmez que : ║
║ • Vous êtes propriétaire de cette application, OU ║
║ • Vous avez une autorisation écrite pour la tester ║
║ ║
║ Tapez "Je confirme être autorisé à tester cette application" ║
║ ║
╚═══════════════════════════════════════════════════════════════════╝
⏸️ STOP - Attendre confirmation explicite
0.2 Création de la structure d'audit
# Créer la structure
mkdir -p .supabase-audit/evidence/{01-detection,02-extraction,03-api,04-storage,05-auth,06-functions}
# Initialiser les fichiers
touch .supabase-audit/context.json
touch .supabase-audit/curl-commands.sh
touch .supabase-audit/timeline.md
0.3 Initialiser context.json
{
"target_url": "<URL>",
"started_at": "<ISO_TIMESTAMP>",
"authorization_confirmed": true,
"phases_completed": [],
"supabase": {},
"findings": []
}
0.4 Initialiser curl-commands.sh
#!/bin/bash
# Supabase Security Audit - Commandes Reproductibles
# Target: <URL>
# Date: <DATE>
#
# Usage: Remplacer les variables puis exécuter
SUPABASE_URL=""
ANON_KEY=""
# === Les commandes seront ajoutées au fur et à mesure ===
0.5 Initialiser timeline.md
# Timeline de l'Audit
## <TIMESTAMP> - Audit démarré
- Cible : <URL>
- Autorisation : Confirmée
Phase 1 : DETECTION
Objectif : Confirmer l'utilisation de Supabase et extraire l'URL du projet.
1.1 Fetch et analyse du code client
# Télécharger la page HTML
curl -s "<TARGET_URL>" -o .supabase-audit/evidence/01-detection/index.html
# Chercher les patterns Supabase
grep -E "(supabase\.co|supabase\.com|createClient|SUPABASE)" .supabase-audit/evidence/01-detection/index.html
1.2 Patterns à détecter
| Pattern | Type | Exemple |
|---------|------|---------|
| *.supabase.co | Domain | abc123.supabase.co |
| NEXT_PUBLIC_SUPABASE_URL | Env var | Next.js |
| VITE_SUPABASE_URL | Env var | Vite |
| createClient( | Code | SDK init |
| /rest/v1/ | Endpoint | PostgREST |
| /auth/v1/ | Endpoint | GoTrue |
1.3 Extraire les fichiers JS et analyser
# Lister les scripts
grep -oE 'src="[^"]+\.js"' index.html | cut -d'"' -f2
# Pour chaque script, chercher les patterns Supabase
curl -s "<SCRIPT_URL>" | grep -E "(supabase|SUPABASE)"
1.4 Sauvegarder immédiatement
Mettre à jour context.json :
{
"supabase": {
"detected": true,
"project_url": "https://abc123.supabase.co",
"project_ref": "abc123"
}
}
Log dans timeline.md :
## <TIMESTAMP> - Detection terminée
- Supabase détecté : ✅
- Project URL : https://abc123.supabase.co
- Evidence : `01-detection/`
Si Supabase non détecté → Informer l'utilisateur et proposer de fournir l'URL manuellement.
Phase 2 : EXTRACTION DES CREDENTIALS
Objectif : Identifier les clés exposées côté client.
2.1 Extraire l'Anon Key (attendu)
Pattern JWT Supabase :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6I...
Décoder et vérifier le rôle :
# Extraire le payload (partie 2 du JWT)
echo "<JWT>" | cut -d'.' -f2 | base64 -d 2>/dev/null
Payload attendu pour anon key :
{
"role": "anon", // ✅ OK si anon
"iss": "supabase",
"ref": "abc123"
}
2.2 Détecter Service Key (CRITIQUE si trouvé)
# Chercher dans tous les JS
grep -rE '"role":\s*"service_role"' .supabase-audit/evidence/
🔴 P0 CRITIQUE si trouvé :
SERVICE KEY EXPOSÉE !
- Bypass tous les RLS
- Accès complet à la BDD
- Action immédiate requise : ROTATION
2.3 Détecter DB Connection String
grep -rE "postgres://|postgresql://" .supabase-audit/evidence/
🔴 P0 CRITIQUE si trouvé :
CONNECTION STRING EXPOSÉE !
- Accès direct à PostgreSQL
- Bypass complet de Supabase
2.4 Détecter JWT Secrets
grep -rE "jwt_secret|JWT_SECRET|supabase_jwt" .supabase-audit/evidence/
2.5 Sauvegarder les findings
Pour chaque credential trouvé, créer un fichier evidence :
{
"evidence_id": "EXT-001",
"timestamp": "<ISO>",
"type": "anon_key_extraction",
"severity": "INFO",
"key_prefix": "eyJhbGciOiJIUzI1...",
"decoded_role": "anon",
"location": {
"file": "/static/js/main.js",
"line": 42
}
}
Ajouter au curl-commands.sh :
# === EXTRACTION ===
# Clé anon extraite (safe pour client)
ANON_KEY="eyJhbGciOiJIUzI1NiI..."
Phase 3 : API AUDIT
Objectif : Tester l'exposition des données via PostgREST.
3.1 Lister les tables exposées
curl -s "$SUPABASE_URL/rest/v1/" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ANON_KEY" \
> .supabase-audit/evidence/03-api/openapi-schema.json
Parser le schéma OpenAPI pour extraire les tables.
3.2 Pour chaque table, tester l'accès anonyme
# Test SELECT
curl -s "$SUPABASE_URL/rest/v1/<TABLE>?select=*&limit=5" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ANON_KEY"
| Résultat | Signification | Sévérité |
|----------|---------------|----------|
| [] vide | RLS bloque | ✅ OK |
| Données retournées | RLS absent ou permissif | 🔴 P0/P1 |
| Erreur 401/403 | Accès bloqué | ✅ OK |
3.3 Tests de bypass RLS
Test 1 : Filter bypass
curl -s "$SUPABASE_URL/rest/v1/posts?or=(published.eq.true,published.eq.false)" \
-H "apikey: $ANON_KEY"
Test 2 : Join exploitation
curl -s "$SUPABASE_URL/rest/v1/comments?select=*,posts(*)" \
-H "apikey: $ANON_KEY"
Test 3 : Insert test (avec rollback)
curl -X POST "$SUPABASE_URL/rest/v1/<TABLE>" \
-H "apikey: $ANON_KEY" \
-H "Content-Type: application/json" \
-H "Prefer: return=representation" \
-d '{"test": "security-audit-delete-me"}'
3.4 Tester les RPC functions
# Lister les fonctions exposées (dans le schéma OpenAPI)
# Pour chaque fonction :
curl -X POST "$SUPABASE_URL/rest/v1/rpc/<FUNCTION_NAME>" \
-H "apikey: $ANON_KEY" \
-H "Content-Type: application/json" \
-d '{}'
3.5 Classification des findings
| Table | RLS | Accès Anon | Données sensibles | Sévérité | |-------|-----|------------|-------------------|----------| | users | ❌ | SELECT * | emails, noms | 🔴 P0 | | posts | ✅ | published only | - | ✅ OK | | orders | ✅ | aucun | - | ✅ OK |
Phase 4 : STORAGE AUDIT
Objectif : Vérifier la configuration des buckets de stockage.
4.1 Lister les buckets
curl -s "$SUPABASE_URL/storage/v1/bucket" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ANON_KEY" \
> .supabase-audit/evidence/04-storage/buckets-list.json
4.2 Pour chaque bucket, tester l'accès
# Lister les fichiers
curl -s "$SUPABASE_URL/storage/v1/object/list/<BUCKET>" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ANON_KEY"
4.3 Tester les URLs publiques
# Format URL publique
curl -I "$SUPABASE_URL/storage/v1/object/public/<BUCKET>/<FILE>"
Si status 200 → Fichier accessible publiquement
4.4 Classifier les buckets
| Classification | Critères | Action | |----------------|----------|--------| | ✅ Approprié | avatars, images publiques | Aucune | | 🟡 À revoir | uploads utilisateur, documents | Considérer private | | 🔴 Critique | backups, exports, .env | Action immédiate |
4.5 Patterns de fichiers sensibles
# P0 - Jamais public
*.sql, *.env*, *backup*, *secret*, *credential*, *export*
# P1 - Généralement privé
*invoice*, *contract*, *passport*, *license*, *.pdf (selon contexte)
Phase 5 : AUTH AUDIT
Objectif : Vérifier la configuration de l'authentification.
5.1 Tester la configuration auth
curl -s "$SUPABASE_URL/auth/v1/settings" \
-H "apikey: $ANON_KEY" \
> .supabase-audit/evidence/05-auth/settings.json
5.2 Vérifier si signup est ouvert
curl -X POST "$SUPABASE_URL/auth/v1/signup" \
-H "apikey: $ANON_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "test-probe@security-audit.local", "password": "TestProbe123!"}'
| Résultat | Signification | |----------|---------------| | 200 + user créé | Signup ouvert | | 400 "Signups disabled" | Signup fermé ✅ | | 429 | Rate limited ✅ |
5.3 Checklist Auth
| Setting | Recommandé | Check | |---------|------------|-------| | Email confirmation | Enabled | | | Password min length | 8+ | | | Rate limiting | Enabled | | | CAPTCHA | Recommandé | |
5.4 [OPTIONNEL] Test IDOR avec user authentifié
⚠️ Nécessite création d'un user test. Demander consentement.
Voulez-vous créer un utilisateur test pour détecter les vulnérabilités IDOR ?
- Email : pentest-<random>@security-audit.local
- Sera supprimé après l'audit (ou manuellement)
[O]ui / [N]on
Si oui :
- Créer l'utilisateur
- Obtenir le JWT
- Comparer accès auth vs anon
- Tester accès cross-user
Phase 6 : REALTIME & FUNCTIONS
Objectif : Vérifier les canaux WebSocket et Edge Functions.
6.1 Edge Functions
# Découvrir les functions (si exposées)
curl -s "$SUPABASE_URL/functions/v1/" \
-H "apikey: $ANON_KEY"
Pour chaque function détectée :
curl -X POST "$SUPABASE_URL/functions/v1/<FUNCTION>" \
-H "apikey: $ANON_KEY" \
-H "Content-Type: application/json" \
-d '{}'
6.2 Realtime channels
Vérifier si des channels sont accessibles sans auth appropriée.
Phase 7 : RAPPORT
Objectif : Générer le rapport final avec toutes les findings et remediations.
7.1 Calculer le Security Score
Score = 100 - (P0 × 25) - (P1 × 10) - (P2 × 5)
Bonus :
+ 10 si RLS sur toutes les tables
+ 10 si auth hardened (email confirm, strong password)
| Score | Grade | Description | |-------|-------|-------------| | 90-100 | A | Excellent | | 80-89 | B | Bon, améliorations mineures | | 70-79 | C | Acceptable, problèmes à traiter | | 60-69 | D | Faible, problèmes significatifs | | 0-59 | F | Critique, action immédiate |
7.2 Générer le rapport
Créer docs/security/supabase-audit-YYYY-MM-DD.md :
# Supabase Security Audit Report
**Cible :** <URL>
**Projet :** <PROJECT_REF>.supabase.co
**Date :** <DATE>
**Score :** <SCORE>/100 (Grade: <GRADE>)
---
## Executive Summary
Cet audit a identifié **X vulnérabilités** :
- 🔴 **X P0** (Critiques) - Action immédiate requise
- 🟠 **X P1** (Hautes) - Traiter sous 7 jours
- 🟡 **X P2** (Moyennes) - Traiter sous 30 jours
### Problèmes les plus critiques
1. **[P0-001]** <Titre>
2. **[P0-002]** <Titre>
### Actions immédiates
1. <Action 1>
2. <Action 2>
---
## Findings Critiques (P0)
### P0-001: <Titre>
**Sévérité :** 🔴 Critique
**Composant :** <Composant>
**CVSS :** <Score>
#### Description
<Description du problème>
#### Preuve
```bash
<Commande curl reproductible>
Impact
- <Impact 1>
- <Impact 2>
Remediation
Immédiat :
<Code SQL de fix>
Long terme : <Recommandation>
Findings Hautes (P1)
...
Findings Moyennes (P2)
...
Analyse par Composant
API (PostgREST)
| Table | RLS | Accès Anon | Status | |-------|-----|------------|--------| | ... | ... | ... | ... |
Storage
| Bucket | Public | Fichiers sensibles | Status | |--------|--------|-------------------|--------| | ... | ... | ... | ... |
Auth
| Setting | Valeur | Recommandé | Status | |---------|--------|------------|--------| | ... | ... | ... | ... |
Plan de Remediation
Phase 1 : Immédiat (Aujourd'hui)
| ID | Action | Priorité | |----|--------|----------| | P0-001 | ... | 🔴 |
Phase 2 : Cette semaine
| ID | Action | Priorité | |----|--------|----------| | P1-001 | ... | 🟠 |
Phase 3 : Ce mois
| ID | Action | Priorité | |----|--------|----------| | P2-001 | ... | 🟡 |
Annexe
Méthodologie
Tests effectués :
- Détection Supabase (patterns client-side)
- Extraction de credentials (keys, JWT)
- API audit (tables, RLS, RPC)
- Storage audit (buckets, fichiers publics)
- Auth audit (config, signup, rate limiting)
- Functions audit (Edge Functions)
Evidence
Toutes les preuves sont disponibles dans .supabase-audit/evidence/
Commandes de reproduction
Voir .supabase-audit/curl-commands.sh
Rapport généré par /supabase-security Skillz-Claude D-EPCT+R Workflow
---
## Output Validation
### Checklist de validation
| Critère | Requis |
|---------|--------|
| Autorisation confirmée | ✅ |
| Supabase détecté | ✅ |
| Evidence sauvegardée progressivement | ✅ |
| Tous les tests exécutés | ✅ |
| Rapport généré | ✅ |
| curl-commands.sh complet | ✅ |
| Remediation pour chaque finding | ✅ |
### Score minimum
**Aucun** - C'est un audit, on rapporte ce qu'on trouve.
---
## Auto-Chain
Après génération du rapport :
```markdown
## 🔗 Prochaine étape
✅ Audit Supabase terminé. Rapport sauvegardé.
Voulez-vous :
→ **[S]** Lancer `/security-auditor` pour un audit code complémentaire ?
→ **[F]** Créer des issues GitHub pour les findings ?
→ **[R]** Relancer l'audit après corrections ?
→ **[N]** Non, terminer
---
Transitions
- Vers
security-auditor: "Voulez-vous aussi auditer le code (OWASP Top 10, dépendances) ?" - Vers
pm-stories: "Créer des issues pour tracker les remediations ?"
Options
| Option | Description |
|--------|-------------|
| --skip-auth-test | Ne pas tester création user (IDOR) |
| --quick | Audit rapide (detection + extraction + RLS) |
| --verbose | Afficher tous les détails pendant l'exécution |
Notes importantes
Progressive Writes
⚠️ OBLIGATOIRE : Sauvegarder les findings AU FUR ET À MESURE.
Avant chaque test → Log dans timeline.md
Après chaque découverte → Update context.json
Après chaque requête → Ajouter à curl-commands.sh
Redaction des données
Ne JAMAIS stocker en clair :
- Emails complets →
[REDACTED]@example.com - Noms →
[REDACTED] - Clés API (sauf préfixe) →
sk_live_[REDACTED]
.gitignore
Recommander d'ajouter :
.supabase-audit/
微信扫一扫