Rapport d'audit sécurité

vibe-app

Date : 19 octobre 2026 à 21:53 UTC15 fichiers analysés97 ms

7Critique · critical
3Élevée · high
0Moyenne · medium
1Faible · low
11Total

Offre recommandée

  • Pack Prêt pour la Prod (800–1500€)
  • Déblocage Flash (150–300€)

Findings (11)

Critique · critical

1.Secret exposé au bundle via VITE_SUPABASE_SERVICE_ROLE_KEY

.env.example:3 · détecteur public-env-secret

VITE_SUPABASE_SERVICE_ROLE_KEY=your-se…[REDACTED]
Remédiation
Les variables NEXT_PUBLIC_* / VITE_* / PUBLIC_* / REACT_APP_* sont copiées en clair dans le JavaScript livré au navigateur (nom de variable réservé aux secrets). Révoquer la clé, la renommer sans préfixe public, et faire l'appel depuis une route serveur / Edge Function qui la lit en variable d'environnement serveur.
Offre
Pack Prêt pour la Prod (800–1500€)
Critique · critical

2.Secret exposé au bundle via VITE_RESEND_SECRET_KEY

.env.example:4 · détecteur public-env-secret

VITE_RESEND_SECRET_KEY=your-…[REDACTED]
Remédiation
Les variables NEXT_PUBLIC_* / VITE_* / PUBLIC_* / REACT_APP_* sont copiées en clair dans le JavaScript livré au navigateur (nom de variable réservé aux secrets). Révoquer la clé, la renommer sans préfixe public, et faire l'appel depuis une route serveur / Edge Function qui la lit en variable d'environnement serveur.
Offre
Pack Prêt pour la Prod (800–1500€)
Critique · critical

3.Clé Supabase service_role utilisée côté client

src/integrations/supabase/client.ts:5 · détecteur service-role-client

const SUPABASE_ADMIN_KEY = import.meta.env.VITE_SUPABASE_SERVICE_ROLE_KEY;
Remédiation
La clé service_role contourne toute la RLS : elle ne doit jamais atteindre le navigateur. Côté front, utiliser uniquement la clé anon/publishable ; déplacer les opérations admin dans une Edge Function qui lit SUPABASE_SERVICE_ROLE_KEY depuis ses secrets, puis régénérer la clé exposée.
Offre
Pack Prêt pour la Prod (800–1500€)
Critique · critical

4.Secret exposé au bundle via VITE_RESEND_SECRET_KEY

src/lib/email.ts:1 · détecteur public-env-secret

const RESEND_KEY = import.meta.env.VITE_RESEND_SECRET_KEY;
Remédiation
Les variables NEXT_PUBLIC_* / VITE_* / PUBLIC_* / REACT_APP_* sont copiées en clair dans le JavaScript livré au navigateur (nom de variable réservé aux secrets). Révoquer la clé, la renommer sans préfixe public, et faire l'appel depuis une route serveur / Edge Function qui la lit en variable d'environnement serveur.
Offre
Pack Prêt pour la Prod (800–1500€)
Critique · critical

5.Clé secrète Stripe exposée dans le bundle front

src/lib/stripe.ts:1 · détecteur secrets

const STRIPE_SECRET_KEY = 'sk_li…[REDACTED]';
Remédiation
Révoquer et régénérer la clé immédiatement (elle est publique). Déplacer l'appel dans une Edge Function / route serveur et lire la clé depuis une variable d'environnement serveur (jamais préfixée VITE_/NEXT_PUBLIC_).
Offre
Pack Prêt pour la Prod (800–1500€)
Critique · critical

6.Table sans RLS : public.invoices

supabase/migrations/20250110120000_init.sql:15 · détecteur supabase-rls

create table public.invoices (
Remédiation
Ajouter une migration ALTER TABLE public.invoices ENABLE ROW LEVEL SECURITY; puis des policies explicites (ex. USING (auth.uid() = user_id)). Sans RLS, la clé anon publique donne lecture/écriture totale sur la table.
Offre
Pack Prêt pour la Prod (800–1500€)
Critique · critical

7.Table sans RLS : public.subscriptions

supabase/migrations/20250110120000_init.sql:25 · détecteur supabase-rls

create table public.subscriptions (
Remédiation
Ajouter une migration ALTER TABLE public.subscriptions ENABLE ROW LEVEL SECURITY; puis des policies explicites (ex. USING (auth.uid() = user_id)). Sans RLS, la clé anon publique donne lecture/écriture totale sur la table.
Offre
Pack Prêt pour la Prod (800–1500€)
Élevée · high

8.Edge Function « stripe-webhook » publique sans authentification (verify_jwt = false)

supabase/config.toml:4 · détecteur edge-fn-no-auth

[functions.stripe-webhook] verify_jwt = false
Remédiation
Vérifier l'appelant en tête de handler : supabase.auth.getUser(token) avec le header Authorization (puis filtrer sur user.id), ou une signature / un secret partagé pour un webhook. Réserver verify_jwt = false aux webhooks signés et n'utiliser le client service_role qu'après ce contrôle.
Offre
Pack Prêt pour la Prod (800–1500€)
Élevée · high

9.Webhook Stripe sans vérification de signature

supabase/functions/stripe-webhook/index.ts:8 · détecteur stripe-webhook

const event = (await req.json()) as Stripe.Event;
Remédiation
Lire le body brut (express.raw() / await req.text()) et appeler stripe.webhooks.constructEvent(rawBody, sig, STRIPE_WEBHOOK_SECRET) (ou constructEventAsync en Edge/Deno) avant tout traitement ; rejeter en 400 si la signature est invalide. Sinon n'importe qui peut forger un checkout.session.completed.
Offre
Déblocage Flash (150–300€)
Élevée · high

10.Policy RLS permissive (true) sur public.profiles

supabase/migrations/20250110120000_init.sql:12 · détecteur supabase-rls

create policy "Profiles are viewable by everyone" on public.profiles
Remédiation
Remplacer USING (true) / WITH CHECK (true) par une condition liée à l'utilisateur, ex. USING (auth.uid() = user_id), et restreindre la policy au rôle authenticated et à la commande nécessaire (FOR SELECT/INSERT…).
Offre
Pack Prêt pour la Prod (800–1500€)
Faible · low

11.Body de requête utilisé sans validation de schéma

supabase/functions/create-invoice/index.ts:17 · détecteur zod-missing

const body = await req.json();
Remédiation
Valider le body avec un schéma avant usage : const input = Schema.safeParse(await req.json()) (zod / valibot), renvoyer 400 si !input.success, puis n'utiliser que input.data. Évite les champs inattendus (ex. role, user_id) injectés par un client malveillant.
Offre
Déblocage Flash (150–300€)