Document de transparence · v1 · 9 mai 2026
Audit sécurité RECOVMAX
État détaillé de la sécurité technique et juridique de la suite RECOV / RECOVMAX. Document destiné aux DPO, responsables sécurité, dirigeants de cabinets qui veulent comprendre ce qui est en place avant d'utiliser le service. Ce document est public et imprimable en PDF (Ctrl + P) pour archivage.
Solide
18
contrôles en place
À améliorer
8
priorités P1-P2
Gaps critiques
4
à 250+ utilisateurs
Score global
A−
solide pour pilote 30 fondateurs
Verdict en une phrase : RECOVMAX est solidement sécurisé pour le pilote 30 fondateurs. Les fondations (RLS multi-tenant, headers HTTP, hébergement UE, RGPD, signature webhooks) sont au niveau attendu d'un SaaS B2B sérieux. Les 8 améliorations identifiées sont planifiées en P1-P2. Les 4 gaps critiques (DPO formel, audit juridique externe, runbook incidents, retention auto) deviennent recommandés au-delà de 250 utilisateurs.
Architecture & isolation des données
| Contrôle | Statut | Détail |
| RLS PostgreSQL multi-tenant |
✓ En place |
Toutes les tables métier (creances, clients, debiteurs, dossier_events, promesses_paiement, echeanciers, templates) appliquent auth.uid() = user_id. Un cabinet ne peut techniquement pas voir les données d'un autre — la base elle-même refuse. |
| RLS read-only enforcement |
✓ En place |
Migration 031 (mai 2026) : helper is_user_writable() bloque INSERT/UPDATE/DELETE quand subscription_status ∉ (active, grace). Les comptes archived/purged ne peuvent que lire. |
| RLS plan enforcement |
✓ En place |
Migration 032 : quotas (50 clients, 50 créances, 1 000 relances) appliqués au niveau base, pas seulement applicatif. |
| Service-role isolé serverless |
✓ En place |
La clé SUPABASE_SERVICE_ROLE_KEY n'apparaît jamais côté client. Uniquement utilisée dans les fonctions Vercel serverless (admin.js, webhook.js, generate.js). |
| Migrations versionnées |
✓ En place |
43 migrations SQL versionnées dans Git, idempotentes (DROP IF EXISTS, CREATE OR REPLACE, ALTER...IF NOT EXISTS). |
| Backups automatisés |
⚠ À tester |
Cron weekly /api/backup?action=cron_weekly dans vercel.json. Test de restauration jamais effectué — à faire avant lancement officiel. |
Headers HTTP & durcissement web
| Header | Statut | Valeur appliquée |
| Strict-Transport-Security (HSTS) |
✓ |
max-age=63072000; includeSubDomains; preload (2 ans, sous-domaines, preload list) |
| X-Frame-Options |
✓ |
DENY — pas d'embed possible (anti-clickjacking) |
| X-Content-Type-Options |
✓ |
nosniff — anti-MIME sniffing |
| Content-Security-Policy |
✓ |
Whitelist stricte : self + cdn.jsdelivr.net + cdnjs + unpkg + js.stripe + supabase + plausible. frame-src https://js.stripe.com uniquement. connect-src limité aux domaines explicites. |
| Referrer-Policy |
✓ |
strict-origin-when-cross-origin — pas de leak de chemins lors de navigation externe |
| Permissions-Policy |
✓ |
camera=(), geolocation=(), interest-cohort=() — APIs sensibles désactivées + opt-out FLoC |
| X-Robots-Tag (pages sensibles) |
✓ |
noindex, nofollow, noarchive, nosnippet sur /admin, /recovmax-dashboard, /partner-report |
| Cache-Control (pages auth) |
✓ |
private, no-store, no-cache, must-revalidate, max-age=0 — pas de cache sur les pages connectées |
| Cross-Origin-Opener-Policy |
⚠ Non configuré |
À ajouter en P1 pour isolation totale du contexte de navigation (SAB / process isolation) |
CSP 'unsafe-inline' |
⚠ Présent |
Nécessaire actuellement pour les inline-styles HTML. Mitigation : tous les innerHTML avec données user passent par esc() qui échappe & < > ". Refactor vers nonces possible mais lourd (5+ jours). |
Authentification & sessions
| Contrôle | Statut | Détail |
| Supabase Auth (PostgreSQL backed) |
✓ En place |
Email + mot de passe, magic links, OAuth Google. JWT signés HS256. Tokens d'accès en session storage, refresh tokens en cookie httpOnly côté Supabase. |
| Hash des mots de passe |
✓ En place |
bcrypt côté Supabase (workfactor 10). Aucun mot de passe en clair côté DEZVOLTA. |
| Rate limiting login |
⚠ Backend Supabase uniquement |
Pas de rate limit applicatif persistant côté Vercel (cold start reset toutes les 5 min). Supabase a son propre rate limit backend (5 tentatives / 5 min / IP). À renforcer en P1 avec Upstash Redis (gratuit jusqu'à 10k requêtes/jour). |
| Honeypot anti-bot signup |
✓ En place |
Champ caché gateWebsite dans le formulaire d'inscription, rempli par les bots, vérifié côté serveur. |
| 2FA (TOTP) |
À faire P1 |
Supabase Auth supporte TOTP nativement. Sprint estimé : 2-3 jours. Recommandé avant 100 utilisateurs payants. |
| CAPTCHA login |
À faire P1 |
Cloudflare Turnstile ou hCaptcha. Sprint estimé : 1 jour. Mitigation actuelle : rate limit Supabase backend. |
| Tokens API admin |
✓ En place |
ADMIN_TOKEN (HMAC bearer) pour les endpoints sensibles. Secret stocké en env Vercel, jamais en code. |
XSS, CSRF, injection
| Vecteur | Statut | Mitigation |
| XSS — escape HTML user-controlled |
✓ En place |
Fonction esc() utilisée 129× dans le dashboard pour échapper & < > " sur toute donnée provenant de la base. Pattern systématique : ${esc(variable)}. |
| SQL injection |
✓ Couvert |
Requêtes via Supabase JS SDK (paramétrées) ou via supabaseQuery() côté serverless. Aucune concaténation SQL côté code applicatif. RPCs côté Postgres en SECURITY DEFINER avec params typés. |
| CSRF dashboard |
✓ Couvert |
Authentification par JWT en header Authorization: Bearer (pas de cookie session) → CSRF par formulaire impossible. SameSite cookies sur Supabase Auth. |
| CSRF webhooks Stripe |
✓ Couvert |
Signature HMAC SHA-256 vérifiée sur chaque event via STRIPE_WEBHOOK_SECRET. Rejet immédiat si signature invalide. |
| CSRF webhooks partenaires |
✓ Couvert |
HMAC mutuelle via partner.webhook_secret. Header X-Recov-Signature sur les réponses sortantes. |
| Open redirect |
✓ Couvert |
Tous les redirects (login, magic link, Stripe checkout) utilisent des URLs hardcodées vers le domaine recov.pro. Aucun paramètre user-controlled dans les redirects. |
Données personnelles & RGPD
| Exigence RGPD | Statut | Détail |
| Hébergement Union européenne |
✓ Conforme |
Supabase région eu-central-1 (Frankfurt). Vercel UE pour les fonctions sensibles. Cloudflare CDN POP UE. |
| Transferts hors UE encadrés |
✓ Conforme |
Anthropic (USA, API Claude) : Clauses Contractuelles Types Commission UE 2021/914 + Zero Data Retention. Stripe Irlande (UE). Cloudflare : POPs UE forcés. |
| Liste publique des sous-traitants (art. 28-2) |
✓ Conforme |
Page recov.pro/sous-traitants mise à jour à chaque ajout/retrait. Préavis 15 jours pour droit d'opposition. |
| DPA spécifique RECOVMAX |
✓ Conforme |
15 articles couvrant la sous-traitance à 3 niveaux (RECOV → Cabinet → Client TPE). Voir DPA RECOVMAX. |
| Mandat de gestion fourni |
✓ Conforme |
Template PDF généré par RECOVMAX (7 articles, références L441-10 + DGCCRF). Le cabinet doit le signer avec chacun de ses clients TPE avant traitement. |
| Droits des personnes (art. 15-22) |
✓ Conforme |
Accès, rectification, effacement, portabilité, limitation, opposition. Procédure : pedro.berbel@dezvolta.org. Délai 30 jours. |
| Pseudonymisation analytics |
✓ Conforme |
PostHog : userId hashé, IP anonymisée, blacklist explicite (email, nom, SIRET). Aucune PII transmise. |
| Retention policy automatisée |
À faire P2 |
Pas de purge auto après inactivité. Recommandé : 3 ans après dernière connexion. Sprint estimé : 1 jour (cron). |
| DPO désigné |
Non requis |
Pas obligatoire en l'état (volume < 250 users, pas de données sensibles RGPD strict art. 9). Recommandé au-delà de 250 utilisateurs ou en cas de saisine CNIL. Budget : 50-150 €/mois externalisé. |
| Procédure incident (notification 72h) |
À faire P2 |
Pas de runbook formel pour notification CNIL en cas de violation. À documenter (modèle CNIL fourni). |
Paiements & facturation
| PCI DSS |
✓ N/A direct |
Aucune donnée carte ne transite chez DEZVOLTA. Stripe Payments Europe Ltd (Irlande, PCI DSS Level 1) gère intégralement la collecte et le stockage des moyens de paiement. |
| Webhook Stripe — signature |
✓ |
HMAC SHA-256 vérifié via STRIPE_WEBHOOK_SECRET (env Vercel). Rejet immédiat si invalide. Idempotence sur stripe_payment_id. |
| Customer Portal (annulation, MAJ CB) |
✓ |
Géré 100% par Stripe (UI hosted). DEZVOLTA n'a jamais accès aux données carte. |
| Mode TEST séparé du LIVE |
✓ |
Environnements isolés. Bascule LIVE = changement de variables d'env Vercel uniquement, pas de code. |
Monitoring actif en production
Au-delà des contrôles statiques (architecture, headers), un middleware Vercel Edge tourne en permanence devant chaque requête. Il bloque les scrapers, AI bots non autorisés et outils offensifs avant même qu'ils n'atteignent l'application.
Couverture
Edge runtime
Latence ~ 0 ms · zero cold start
Modèles bloqués
30+
User-Agents + IPs + comportements
Crawlers légitimes
~ 15
Whitelist Google, Bing, LinkedIn, Apple…
Dashboard live
interne
Admin SOC · accès restreint
| Catégorie bloquée | Exemples | Justification |
| Scrapers Python génériques |
scrapy, python-httpx, python-requests |
Aucun usage légitime sur un SaaS — uniquement des scripts d'extraction massive de contenu. |
| AI scrapers non autorisés |
gptbot, ccbot, perplexitybot, cohere-ai |
Ces bots utilisent le contenu pour entraîner des modèles concurrents sans contrepartie. Anthropic (notre sous-traitant IA) est exempté car couvert par DPA. |
| SEO crawlers agressifs |
semrushbot, ahrefsbot, mj12bot, bytespider |
Crawl à haute fréquence sans valeur ajoutée pour les utilisateurs. Ralentissent l'application. |
| Outils offensifs |
nikto, nmap, nuclei, zgrab, masscan |
Outils de pentest publics — leur présence indique une tentative active de cartographie ou exploitation. |
| Crawlers SEO secondaires |
dotbot, petalbot, blexbot, seokicks |
Sources de bruit sans valeur pour les utilisateurs. Bloqués pour préserver les ressources Edge. |
Ce qui est observé en production (extrait anonymisé)
Statistiques sur 7 jours — accessibles en temps réel dans le dashboard admin interne :
| Métrique | Valeur observée 7j | Lecture |
| Requêtes bloquées | ~ 200 | Tentatives de scraping rejetées avant traitement |
| Crawlers légitimes autorisés | ~ 400 | Google, LinkedIn, Apple : indexation normale |
| Top scraper bloqué | gptbot | OpenAI tente régulièrement — toujours rejeté |
| Pays de provenance des scrapers | US, BR, NL, PT, CN, TH, ID, TR, GB, BE | Profil mondial typique des pools de proxies |
| Vecteurs distincts détectés | 8 types | UA pattern, IP pattern, comportement anormal |
Whitelist explicite — les bots légitimes (Googlebot, Bingbot, LinkedInBot, AppleBot, FacebookBot, TwitterBot, DuckDuckBot, Slackbot, WhatsApp, Telegram, Discord) sont autorisés explicitement. Le SEO et le partage social fonctionnent normalement.
Pas de blocage géographique massif — RECOVMAX cible le marché français mais l'application reste accessible depuis l'étranger. Un cabinet français peut avoir un client à l'étranger ou un dirigeant en déplacement. Le blocage géographique serait disproportionné.
Secrets & gestion des clés
| Variables d'environnement Vercel |
✓ |
Tous les secrets stockés en env vars Vercel (chiffrement at-rest). Aucun secret en code (vérifié par grep + secrets scanning GitHub Push Protection). |
| Rotation des secrets |
⚠ Manuelle |
Pas de rotation automatique. Procédure manuelle documentée. À industrialiser en P2 (rotation tous les 6 mois recommandée). |
| Anon key Supabase publique |
✓ |
L'anon key est par design publique. Sécurité reposant intégralement sur les policies RLS. Service-role key strictement serverless. |
Roadmap sécurité 2026-2027
Priorisation transparente — voici ce qui est prévu et quand. Si un point est critique pour vous, contactez-nous : nous pouvons accélérer pour un client cabinet majeur.
| Sprint | Action | Bénéfice |
| P1 · Q3 2026 | 2FA TOTP optionnelle | Protège contre les comptes compromis (mot de passe leaké) |
| P1 · Q3 2026 | CAPTCHA login (Turnstile) | Anti brute-force applicatif persistant |
| P1 · Q3 2026 | Rate limit persistant (Upstash Redis) | Remplace le rate limit in-memory Vercel |
| P2 · Q4 2026 | Headers COOP/COEP | Isolation totale du contexte navigation |
| P2 · Q4 2026 | Audit log applicatif admin (table immutable) | Traçabilité juridique des actions admin |
| P2 · Q4 2026 | Test restauration backup | Validation effective de la stratégie DRP |
| P2 · Q4 2026 | Retention auto (purge 3 ans) | Conformité RGPD art. 5-1-e |
| P2 · Q4 2026 | Runbook incident + notification CNIL | Procédure documentée 72h |
| P3 · Q1 2027 | Pentest externe (1 500-3 000 €) | Audit indépendant tiers |
| P3 · Q1 2027 | Audit juridique CGU/DPA externe (800-1 500 €) | Validation par avocat tech-RGPD |
| P3 · Q2 2027 | DPO externalisé si > 250 users | Conformité art. 37 RGPD si volume / sensibilité |
Pour aller plus loin
Une question, une demande spécifique ?
Contactez directement le fondateur :
pedro.berbel@dezvolta.org.
Pour les sujets RGPD :
pedro.berbel@dezvolta.org.
Si vous êtes responsable sécurité d'un cabinet ou d'une entreprise et avez besoin d'un complément (audit indépendant, certification, contrat sur mesure), nous pouvons en discuter en visio.
Accessibilité — déclaration partielle
DEZVOLTA s'engage à rendre la suite RECOV / RECOVMAX accessible au plus grand nombre. L'audit professionnel WCAG 2.1 AA / RGAA 4.1 n'a pas encore été réalisé — nous publions ici une auto-déclaration partielle honnête, mise à jour au fil des améliorations.
Date de la déclaration : 9 mai 2026. Méthode : auto-évaluation interne (sans audit externe). Un audit professionnel sera réalisé dans les 12 mois.
Ce qui est déjà en place
| Critère | Niveau | État |
Hiérarchie de titres + langue de la page (lang="fr") | WCAG A · 1.3.1 / 3.1.1 | ✓ Conforme |
Labels formulaires associés (label for=) | WCAG A · 3.3.2 | ✓ Conforme |
| Navigation 100 % au clavier (Tab, Enter, Espace, Échap) | WCAG A · 2.1.1 | ✓ Conforme |
| Skip link "Aller au contenu principal" | WCAG A · 2.4.1 | ✓ Conforme |
| Trap focus dans les drawers / modales | WCAG A · 2.4.3 | ✓ Conforme |
| Focus visible (outline lime) | WCAG AA · 2.4.7 | ✓ Conforme |
aria-hidden sur emojis décoratifs | WCAG A · 1.1.1 | ✓ Conforme |
aria-label enrichi sur composants drag | WCAG A · 4.1.2 | ✓ Conforme |
Annonces lecteurs d'écran (aria-live) | WCAG AA · 4.1.3 | ✓ Conforme |
Identification erreurs forms (aria-invalid, role="alert") | WCAG A · 3.3.1 | ✓ Conforme (login) |
| Alternative clavier au glisser-déposer Kanban (touche Espace) | WCAG AA · 2.5.7 | ✓ Conforme |
prefers-reduced-motion respecté | WCAG AAA · 2.3.3 | ✓ Conforme |
| Tooltips dismissable par Échap | WCAG AA · 1.4.13 | ✓ Conforme (partiel) |
| Mode confort de lecture (zoom utilisateur, contraste renforcé, animations off) | Bonus utilisateur | ✓ Disponible |
| Compatible NVDA, JAWS, VoiceOver, TalkBack | WCAG A · 4.1.2 | ⚠️ Théoriquement OK · tests utilisateurs réels à faire |
Ce qui n'est pas encore conforme ou non vérifié
| Critère | Niveau | État |
| Audit professionnel externe (cabinet RGAA) | — | ❌ Non réalisé · prévu dans les 12 mois |
| Contraste texte (4,5:1) audité partout | WCAG AA · 1.4.3 | ⚠️ Audit partiel · variable --lime-text introduite mais non auditée systématiquement |
| Contraste éléments non-texte (3:1) | WCAG AA · 1.4.11 | ⚠️ Non audité |
| Resize text 200 % sans perte de fonction | WCAG AA · 1.4.4 | ⚠️ Non testé sur l'ensemble des écrans |
| Reflow 320 px CSS sans scroll horizontal | WCAG AA · 1.4.10 | ⚠️ Partiellement testé · ajustements en cours |
| Suggestions structurées sur erreurs (au-delà du message texte) | WCAG AA · 3.3.3 | ❌ Non implémenté |
| Tests réels utilisateur avec lecteurs d'écran | — | ❌ Non réalisés (programmés post-30 fondateurs) |
| Sous-titres / transcripts pour contenu vidéo | WCAG A · 1.2.x | ⚠️ Pas de vidéo embarquée actuellement · sera fait si vidéo ajoutée |
Comment nous signaler un problème
Si vous rencontrez un défaut d'accessibilité (élément non navigable au clavier, contraste insuffisant, contenu mal lu par un lecteur d'écran, etc.), écrivez-nous à pedro.berbel@dezvolta.org avec :
- L'URL de la page concernée
- Le navigateur / OS / lecteur d'écran utilisé (si applicable)
- La description du problème ou de l'élément bloquant
Engagement de réponse : sous 5 jours ouvrés. Correction : selon la gravité, entre 1 jour (bloquant) et 30 jours (amélioration).
Voies de recours
Cette procédure est à utiliser dans le cas suivant : vous avez signalé au responsable du site un défaut d'accessibilité qui vous empêche d'accéder à un contenu ou à un service, et vous n'avez pas obtenu de réponse satisfaisante. Vous pouvez :
- Écrire un message au Défenseur des droits
- Contacter le délégué du Défenseur des droits dans votre région
- Envoyer un courrier à : Défenseur des droits, Libre réponse 71120, 75342 Paris CEDEX 07
Ce document décrit l'état de la sécurité technique et juridique au 9 mai 2026. Il est mis à jour à chaque évolution structurelle. Il n'engage pas DEZVOLTA sur des résultats ni sur l'absence de failles non identifiées. Pour toute observation ou signalement de faille de sécurité (responsible disclosure), écrire à pedro.berbel@dezvolta.org — réponse sous 48h ouvrées.