Breadcrumbs Sentry sans PII : rapports d'erreurs sans fuites de données
Configurez des breadcrumbs Sentry sans PII avec des scrubbers, le suivi des releases et du contexte utile afin que les erreurs soient exploitables sans journaliser de secrets ou de données personnelles.

Ce qui cloche dans le reporting d'erreurs et la vie privée
Le reporting d'erreurs doit vous aider à corriger les bugs plus vite. Mais il collecte souvent plus que ce que vous vouliez partager, surtout quand vous ajoutez des breadcrumbs.
Les breadcrumbs sont de petites notes sur ce qui s'est passé juste avant un plantage : quel écran s'est ouvert, quel bouton a été cliqué, quel appel API a échoué. Ils sont utiles parce qu'ils transforment une erreur vague en une séquence qu'on peut rejouer.
Le problème, c'est que beaucoup d'apps traitent les breadcrumbs comme des logs ordinaires. Des données privées s'y glissent sans bruit. Un breadcrumb peut contenir une URL complète avec paramètres de requête, un dump d'en-têtes ou le payload d'un formulaire. Cela peut exposer des données personnelles (emails, numéros de téléphone, adresses) et des secrets (clés API, cookies de session, tokens de réinitialisation). Une fois ces données envoyées à un outil d'erreurs, elles peuvent être stockées, recherchables et visibles par toute l'équipe.
Les points de fuite semblent souvent inoffensifs en revue de code :
- URLs avec identifiants ou tokens de réinitialisation dans la query string
- En-têtes comme Authorization, Cookie ou X-API-Key
- Champs de formulaires des flux d'inscription et de paiement
- Variables GraphQL ou corps JSON de requêtes
- Logs de debug qui affichent des variables d'environnement ou la config
Un modèle mental simple aide : collecter le comportement, pas l'identité. Logguez «inscription échouée après soumission» et «POST /api/signup a renvoyé 500», pas l'email de l'utilisateur, le corps complet de la requête ou un token.
Ceci empire dans les prototypes générés par l'IA. Il est courant de voir des helpers qui affichent des objets entiers «juste pour debugger», incluant secrets et enregistrements utilisateurs. Corriger le crash n'est qu'une moitié du travail. Prévenir une fuite silencieuse de données en est l'autre.
Que capturer (et ce qu'il faut absolument éviter)
Les bons rapports d'erreurs se concentrent sur l'ensemble minimal de faits qui expliquent ce qui a cassé. Si vous pouvez répondre à «quelle action s'est produite, où ça a échoué et quelle version l'a livrée ?», vous avez généralement assez pour corriger le bug sans collecter de données personnelles.
Il est utile de séparer :
- Événements métier : ce que l'utilisateur essaie de faire (créer un compte, uploader un fichier, payer)
- Événements techniques : ce que l'app a fait (changement de route, requête API, validation échouée)
Pour des breadcrumbs Sentry sans PII, privilégiez les événements techniques plus une étiquette métier coarse. Évitez l'histoire utilisateur complète.
Une politique de capture pratique :
- Sûr à capturer : nom d'écran/route, ID de bouton (pas le texte du bouton), clés de feature flag, chemin d'endpoint API (sans query string), méthode HTTP et code de statut, durée (ms), nombre de retries, état de l'app comme offline/online.
- Risqué : URLs complètes avec paramètres, corps de requête/réponse, champs saisis par l'utilisateur, email/phone/adresse, messages d'erreur bruts qui peuvent refléter l'entrée.
- À ne jamais laisser sortir de l'app : mots de passe, magic links, tokens de session, refresh tokens, clés API, données de carte bancaire, identifiants gouvernementaux.
Un exemple concret pour une inscription cassée :
- Breadcrumb sûr : "POST /api/signup -> 400, validation_failed, release 1.8.3"
- Breadcrumb risqué : "POST /api/signup body={email:..., password:...}"
Le premier vous indique où chercher. Le second crée une fuite de données.
Une classification simple des données pour breadcrumbs et erreurs
Les breadcrumbs Sentry sans PII fonctionnent mieux quand l'équipe partage une règle : chaque valeur capturée appartient soit à "sûr par défaut", soit à "sûr après redaction", soit à "jamais autorisé". Si quelqu'un peut nommer la catégorie en quelques secondes, on évite les fuites du type «on pensait que c'était OK».
Trois seaux auxquels la plupart des équipes peuvent adhérer
- Ne jamais capturer : identifiants et secrets (mots de passe, tokens de session, clés API, en-têtes d'authentification, clés privées) et données hautement sensibles (numéros de carte complets, CVV, données de santé).
- Capturer seulement sous une forme réduite : données personnelles identifiantes (email, téléphone, IP, nom complet, adresse postale). Si vous en avez vraiment besoin, hashez-les, tronquez-les ou remplacez-les par une référence interne stable.
- Sûr à capturer : contexte technique aidant au debug (feature flags, nom de route, bouton cliqué, région serveur, code d'erreur).
Exemples qui tiennent généralement la route :
- Email : forme réduite (ou ne pas le capturer)
- user_id interne : souvent OK si non devinable
- Adresse IP : souvent considérée comme donnée personnelle
- Token de session : jamais
- Clé API : jamais
Une politique de redaction que les gens suivront réellement
Gardez-la courte et cohérente entre logs, breadcrumbs et événements d'erreur :
- Listez les champs exacts que vous autorisez (par exemple : user_id, org_id, release, route, feature).
- Listez les champs que vous redactez toujours (token, password, authorization, cookie, secret, key).
- Notez où ces champs apparaissent (corps de requête, en-têtes, query string, local storage, inputs UI).
Le plus grand échec est «loggez tout l'objet». Si vous voyez ce pattern dans un code hérité, traitez-le en urgence : retirez-le d'abord, puis ajoutez des garde-fous pour qu'il ne revienne pas.
Pas à pas : configuration de base de Sentry avec des valeurs sûres
Choisissez un outil de reporting d'erreurs et utilisez-le de façon cohérente dans l'app. Sentry est courant, mais la même approche s'applique ailleurs. L'objectif est simple : chaque erreur doit indiquer clairement où elle s'est produite et quelle build l'a livrée.
Commencez par standardiser les environnements et utilisez-les partout : dev pour le travail local, staging pour les tests pré-release et prod pour les vrais utilisateurs. Faites de l'environnement une valeur de config, pas quelque chose que les gens tapent à la main.
Initialisez le SDK avec des valeurs sûres et seulement les intégrations nécessaires. Un setup minimal côté navigateur peut ressembler à ceci :
Sentry.init({
dsn: "…",
environment: process.env.APP_ENV, // dev | staging | prod
release: process.env.APP_RELEASE, // e.g., git sha or build id
tracesSampleRate: 0.1, // performance sampling (start low)
sampleRate: 1.0, // error events (usually keep at 100%)
maxBreadcrumbs: 50,
maxValueLength: 250,
});
Activez les breadcrumbs qui aident à rejouer ce qui s'est passé sans transformer vos logs en dump de données. Les sources par défaut utiles sont les changements de navigation, les clics utilisateur, les appels API (méthode + route, pas les URLs complètes) et les erreurs console.
Gardez le volume sous contrôle pour ne pas noyer le tableau ou exploser les coûts. Quelques limites suffisent en général :
- Limitez le nombre de breadcrumbs (par exemple 50) pour qu'une page bruyante ne domine pas la timeline.
- Tronquez les chaînes longues (par exemple 250 caractères) pour réduire les fuites accidentelles.
- Échantillonnez les données de performance (commencez à 5-10%) jusqu'à savoir ce dont vous avez besoin.
- Ajoutez un rate limiting côté client pour qu'une boucle cassée n'envoie pas des milliers d'événements.
Scrubbers et allowlists pour garder la PII hors du scope
Le scrubbing fonctionne mieux quand on part d'une allowlist. Plutôt que d'essayer de bloquer tous les secrets possibles, décidez des champs de breadcrumb et d'erreur que vous acceptez et jetez le reste. C'est la façon la plus sûre de garder les breadcrumbs utiles sans collecter de données privées.
Un défaut pratique consiste à garder :
- Le nom de l'événement et un message court
- Un code d'erreur stable (si vous en avez un)
- Un template de route (comme
/users/:id) - Des tags non-personnels (release, environment, feature flag)
Traitez tout le reste comme suspect tant que vous n'avez pas prouvé son utilité.
Ensuite, ajoutez des scrubbers stricts et ennuyeux pour éviter les pièges prévisibles :
- Nettoyez les clés qui transportent souvent des secrets :
password,pass,token,access_token,refresh_token,authorization,cookie,session,api_key - Redigez les en-têtes de requête par défaut, puis allowlistez seulement ceux dont vous avez vraiment besoin (souvent aucun)
- Supprimez les query strings et fragments des URLs (
?…et#…) sauf raison spécifique et revue - Normalisez les identifiants utilisateurs : utilisez un user id interne ou un hash unidirectionnel, pas l'email ou le téléphone brut
- Supprimez les corps de requête sauf si vous avez une allowlist stricte pour des champs spécifiques
Exemple : un bug d'inscription.
- Breadcrumb qui fuit : "POST /signup?email=[email protected]"
- Breadcrumb plus sûr : "POST /signup (validation_failed, field=email)", plus un user id comme
u_18429ouhash_9f2c…
Vous voyez toujours ce qui s'est passé, mais vous ne stockez pas de données personnelles.
Suivi des releases qui rend les erreurs exploitables
Si un rapport d'erreur ne vous dit pas quelle version l'a livrée, il sera difficile à corriger rapidement. Le suivi des releases lie chaque événement et piste de breadcrumbs à une build pour répondre vite à la question : est-ce que ça a commencé après le dernier déploiement ?
Attachez un identifiant de release à chaque événement. Beaucoup d'équipes le font au démarrage de l'app pour que la release soit présente même si le crash arrive sur le premier écran.
Une règle de nommage des releases qui reste simple
Choisissez un format de nommage qui correspond à votre façon de builder et déployer. La cohérence importe plus que l'originalité.
- Utilisez la même chaîne de release frontend et backend quand possible
- Préférez un SHA Git ou un numéro de build
- Ajoutez une étiquette d'environnement seulement si votre tooling ne sépare pas déjà les environnements
- N'incluez jamais d'emails d'utilisateurs, de noms de locataires ou d'URLs de requête dans le nom de release
Avec cela en place, les breadcrumbs Sentry sans PII deviennent plus utiles : vous pouvez comparer «même flux, version différente» sans inspecter de données personnelles.
Marquer les déploiements pour voir les pics
Les marqueurs de déploiement transforment les graphiques en récit. Quand les taux d'erreur montent, vous pouvez aligner le pic sur un déploiement et cibler le code modifié.
Exemple : les erreurs d'inscription montent après la build web@3f2c1a9. Les breadcrumbs montrent «clicked Sign up», «POST /api/signup», puis un 500. Vous n'avez pas besoin de l'email de l'utilisateur pour agir. Il vous faut la release, l'endpoint et l'étape qui échoue.
Contexte exploitable sans données personnelles
Un bon rapport d'erreur répond rapidement à une question : que s'est-il passé juste avant le crash ? On peut obtenir cette clarté sans copier d'emails, de tokens, d'adresses ou de corps de requête complets dans les breadcrumbs.
Commencez par ajouter quelques tags sûrs qui décrivent la situation, pas la personne. Exemples utiles : état d'un feature flag (on/off), niveau du locataire (free/pro/enterprise), type d'appareil (mobile/desktop) et niveau d'abonnement. Ces tags transforment une pile d'erreurs en groupes exploitables.
Le contexte de requête est un autre domaine à fort signal, mais gardez-le minimal :
- Méthode HTTP
- Template de route (par exemple
/projects/:id/settings, pas l'ID réel) - Code de statut
Si vous ajoutez la latence, envisagez un arrondi (par exemple 1200ms) plutôt que de stocker un timing trop fin par session utilisateur.
Pour les breadcrumbs, pensez en snapshots d'état sûrs : nom d'écran, numéro d'étape dans un flow, nombre de retries. Cela suffit souvent à montrer des patterns comme «échec à l'étape 2 après 3 retries sur mobile», ce qui permet souvent de trouver un bug logique.
Un ensemble compact de champs utile et généralement sans PII :
screen,flow_step,retry_countroute_template,method,status_codefeature_flag,tenant_tier,plan_level,device_typerelease,build,environment
Pour connecter frontend et backend sans données utilisateurs, ajoutez un correlation ID. Générez un ID aléatoire par requête (ou par session), envoyez-le dans un en-tête et stockez-le comme tag ou extra des deux côtés. Quand les breadcrumbs montrent une requête qui échoue, vous pouvez la faire correspondre à une erreur serveur grâce à cet ID unique.
Cas spéciaux : auth, paiements et prototypes générés par l'IA
Certaines parties d'une app fuguent plus facilement des données sensibles que d'autres. Si vous voulez des breadcrumbs sans PII, traitez auth et paiements comme «toujours dangereux» et verrouillez-les en priorité.
Côté serveur, le défaut le plus sûr est de capturer moins. Enlevez les en-têtes de requête inutiles, redigez les corps par défaut et ne transférez jamais les cookies bruts dans les événements d'erreur. Si vous capturez temporairement un corps pour le debug, autorisez seulement des clés spécifiques et limitez la taille.
Pour les flux d'authentification, rédigez tout ce qui peut servir à se connecter en tant qu'utilisateur :
- En-têtes Authorization (Bearer tokens)
- Cookies et IDs de session
- JWTs, refresh tokens et tokens CSRF
- Codes OAuth, valeurs d'état et URLs de redirect avec params
- Magic links et mots de passe à usage unique
Côté client, soyez prudent avec les fonctionnalités «utiles» qui sur-collectent. Évitez de capturer des snapshots DOM complets, des inputs de formulaire ou le contenu du presse-papiers. Préférez des breadcrumbs qui décrivent l'intention sans copier les données, comme «Clicked Sign in button» ou «Validation failed: password too short».
Les paiements requièrent la même approche. N'enregistrez jamais de numéros de carte complets, CVC, coordonnées bancaires ou adresses de facturation. Si vous avez besoin de contexte, capturez des résultats haut niveau comme «Payment provider returned declined» avec un code d'erreur du prestataire.
Les prototypes générés par l'IA présentent un risque particulier car ils journalisent souvent des objets entiers «juste pour voir», incluant en-têtes et variables d'environnement. Si vous avez hérité de code d'outils comme Cursor, Replit, Bolt, Lovable ou v0, recherchez les console.log et handlers d'erreur qui dumpent des requêtes complètes.
Une règle fiable : loggez des actions et des résultats, pas des payloads et des secrets.
Comment tester que les scrubbers fonctionnent vraiment
Ne supposez pas que les scrubbers fonctionnent parce que vous les avez configurés une fois. Traitez-les comme une fonction de sécurité : testez-les dans chaque environnement (local, staging, production) après tout changement de logging.
Envoyez une erreur contrôlée contenant des valeurs canaries que vous n'utiliseriez jamais en vrai. Vous devriez toujours pouvoir déboguer le flux, tandis que chaque valeur sensible est supprimée ou remplacée.
Une routine de test répétable :
- Déclenchez une exception de test qui inclut un email factice (
[email protected]), un token factice (tok_test_SHOULD_NOT_LEAK) et une chaîne ressemblant à une carte (4242 4242 4242 4242). - Reproduisez l'erreur dans chaque environnement et confirmez que l'événement est reçu.
- Ouvrez le payload complet de l'événement et vérifiez le message, les breadcrumbs, les en-têtes de requête et le contexte extra pour s'assurer des redactions.
- Recherchez vos valeurs canary dans les événements. Vous ne devriez trouver aucune correspondance.
- Répétez après avoir modifié le code d'auth, de formulaires, de paiements ou d'analytics.
Vérifiez aussi ce que votre framework ajoute automatiquement. Beaucoup de fuites viennent des en-têtes (Authorization, Cookie), des URLs (params) et des corps de formulaire.
Écrivez un petit runbook pour quand quelque chose fuit :
- arrêter l'envoi du champ (désactiver le breadcrumb ou le contexte)
- durcir les scrubbers ou ajouter une allowlist
- supprimer les événements impactés selon votre politique
- retester avec des canaries
- noter la cause racine pour éviter la régression
Erreurs courantes qui provoquent des fuites accidentelles
La plupart des fuites de confidentialité ne viennent pas d'une grosse erreur unique. Elles résultent de petits défauts par défaut qui paraissent inoffensifs jusqu'à ce qu'un incident apparaisse dans votre outil d'erreurs.
S'appuyer sur une blacklist est un piège courant. Vous redigez password et token, puis quelqu'un ajoute ssn, dob ou inviteCode et cela part sans être touché. Les configurations plus sûres partent d'une allowlist : envoyez seulement les champs dont vous avez vraiment besoin pour déboguer.
Logger des URLs complètes est une autre fuite facile. Les params contiennent souvent des emails, des téléphones, des tokens de reset et des IDs internes. Un breadcrumb comme GET /reset?email=...&token=... peut exposer exactement ce qu'un attaquant recherche. Préférez des templates de route et supprimez les query strings par défaut.
Les corps de requête et de réponse contiennent les pires surprises. Si votre SDK capture les corps par défaut, vous pouvez finir par envoyer des formulaires d'inscription, des payloads d'auth, des objets de paiement, des prompts d'utilisateur et des extraits de contenu uploadé.
Faites aussi attention à l'objet user. Utiliser l'email ou le téléphone brut comme user.id rend chaque événement directement identifiant. Utilisez un ID interne stable ou un hash unidirectionnel, et gardez les champs personnels derrière un opt-in explicite et du scrubbing.
Checklist rapide avant le lancement
Faites une passe rapide avec l'état d'esprit «que cela pourrait-il révéler ?». Les rapports d'erreurs doivent aider à corriger les bugs, pas devenir une base de données d'info perso.
Une courte série de vérifications évite la plupart des fuites :
- Gardez les breadcrumbs structurés et ennuyeux : champs fixes comme
category,action,statuset IDs internes. Évitez le texte libre issu de l'utilisateur (termes de recherche, champs de formulaire, messages de chat), même temporairement. - Redigez les secrets partout où ils se cachent : bloquez ou redactez les en-têtes Authorization, cookies, IDs de session, tokens CSRF, champs password, clés API et les valeurs correspondant à vos patterns de token.
- Rendez chaque événement exploitable : vérifiez que
releaseetenvironmentsont attachés à chaque erreur. - Templatez les routes et contrôlez les URLs : enregistrez
/users/:id/settingsau lieu de/users/48392/settings. Supprimez les query strings par défaut. - Prouvez la redaction de bout en bout : envoyez un événement de test avec des secrets factices (comme
Bearer test_token_123) et un email factice, puis vérifiez que le tableau de bord montre[REDACTED]ou rien du tout.
Avant le lancement, choisissez un flux réaliste (inscription ou paiement), déclenchez une erreur contrôlée et confirmez que le rapport contient encore assez de contexte (template de route, release, état des feature flags, statut réseau) pour déboguer sans exposer d'utilisateurs.
Exemple : déboguer une inscription cassée sans exposer de données utilisateur
Histoire courante : vous déployez un vendredi et les échecs d'inscription montent. Les utilisateurs voient un vague «Something went wrong» après avoir cliqué sur «Create account». Vous avez besoin de détails suffisants pour corriger rapidement, mais vous ne pouvez pas vous permettre de faire fuiter emails, tokens ou en-têtes d'auth dans votre outil d'erreurs.
Avec des breadcrumbs Sentry sans PII, le rapport peut rester exploitable. L'événement montre le chemin sans le payload privé :
- Breadcrumbs :
Signup screen opened->Email form submitted->POST /api/signup (400)->Magic link screen shown->POST /api/verify (401) - Contexte : environment
production, navigateur et OS, état du feature flag (on/off), et codes de statut des réponses API - Tags :
flow=signup,provider=email_magic_link,region=us-east
En parallèle, les scrubbers rédigent les valeurs sensibles avant qu'elles ne quittent l'app. L'événement doit remplacer ou supprimer :
- Valeurs des champs email et «name» du formulaire
- Token du magic link, code OTP, cookies de session
- En-tête Authorization et tout
x-api-key
La cause devient claire sans données personnelles : les erreurs ont démarré avec la release [email protected], et la plupart surviennent sur POST /api/verify avec un 401. Cela pointe vers un changement logique ou de configuration, pas un comportement utilisateur aléatoire.
Le suivi des releases affine encore : comparez les commits entre 1.8.2 et 1.8.3 et vous trouverez souvent un petit changement comme un endpoint renommé, un cookie manquant ou un nouveau middleware bloquant la route de vérification.
Prochaines étapes : rester sûr à mesure que l'app grandit
Une fois les breadcrumbs sans PII en place, considérez la confidentialité comme un travail continu. Les apps changent vite : nouveaux endpoints, SDK tiers, logs de debug ajoutés pendant une correction nocturne.
Assignez un propriétaire unique pour le reporting d'erreurs respectueux de la vie privée. Il n'a pas à tout faire, mais doit exécuter une revue rapide régulièrement et s'assurer que les changements ne fragilisent pas les scrubbers ou les allowlists.
Ajoutez une porte de release pour attraper les erreurs évidentes avant shipping. Même un check CI simple qui scanne les patterns de secrets courants peut éviter beaucoup d'exposition accidentelle. Associez cela à une règle de revue de code : pas de journalisation des corps de requête, des en-têtes d'auth ou des objets user complets.
Bonnes habitudes continues :
- Revoir les événements d'erreur récents et confirmer que le scrubbing fonctionne toujours
- Reverifier l'allowlist après avoir ajouté des breadcrumbs ou intégré des SDK
- Faire tourner les clés si quelque chose de sensible a déjà été capturé, puis resserrer les filtres
- Lancer un audit ciblé après de grosses fonctionnalités (changements d'auth, facturation, uploads de fichiers)
- Conserver une norme d'équipe partagée : debugger avec des IDs et des compteurs, pas des données brutes
Si vous avez hérité d'un projet généré par l'IA qui est bruyant, cassé ou fuit des secrets, un audit ciblé peut être plus rapide que de deviner où se fait la journalisation. FixMyMess (fixmymess.ai) se spécialise dans le diagnostic et la réparation de bases de code générées par l'IA et leur durcissement pour la production, y compris la journalisation et le reporting d'erreurs plus sûrs.