Migas de Sentry seguras frente a PII: reportes de errores sin filtración de datos
Configura migas de pan seguras en Sentry con scrubbers, seguimiento de releases y contexto útil para que los errores sean accionables sin registrar secretos ni datos personales.

Qué suele fallar en los reportes de errores y la privacidad
Los reportes de errores deberían ayudarte a arreglar fallos más rápido. Pero a menudo recopilan más información de la que querías compartir, sobre todo cuando añades migas de pan.
Las migas de pan son pequeñas notas sobre lo que ocurrió justo antes del fallo: qué pantalla se abrió, qué botón se pulsó, qué llamada a la API falló. Son útiles porque convierten un error vago en una secuencia que puedes reproducir.
El problema es que muchas apps tratan las migas de pan como logs normales. Los datos privados se cuelan en silencio. Una miga puede incluir una URL completa con parámetros de consulta, un volcado de cabeceras o un payload de formulario. Eso puede exponer datos personales (emails, teléfonos, direcciones) y secretos (claves API, cookies de sesión, tokens de restablecimiento de contraseña). Una vez que esos datos llegan a una herramienta de errores, pueden almacenarse, ser buscables y visibles para todo el equipo.
Los puntos de filtración suelen parecer inocuos en una revisión de código:
- URLs con identificadores o tokens de restablecimiento en la query string
- Cabeceras como Authorization, Cookie o X-API-Key
- Campos de formularios de registro y pago
- Variables de GraphQL o cuerpos JSON de petición
- Logs de depuración que imprimen variables de entorno o configuración
Un modelo mental simple ayuda: recoge comportamiento, no identidad. Registra que “el registro falló tras enviar” y “POST /api/signup devolvió 500”, no el email del usuario, el cuerpo completo de la petición ni ningún token.
Esto empeora en prototipos generados por IA. Es común ver utilidades que imprimen objetos completos “solo para depurar”, incluyendo secretos y registros de usuarios. Arreglar el fallo es solo la mitad del trabajo. Evitar una filtración silenciosa de datos es la otra mitad.
Qué capturar (y qué nunca capturar)
Los buenos reportes de errores se centran en el mínimo conjunto de hechos que explica qué se rompió. Si puedes responder “qué acción ocurrió, dónde falló y qué versión la lanzó”, normalmente tienes suficiente para arreglar el bug sin recopilar datos personales.
Ayuda separar:
- Eventos de negocio: lo que el usuario intenta hacer (crear cuenta, subir archivo, pagar)
- Eventos técnicos: lo que hizo la app (cambio de ruta, petición a la API, validación fallida)
Para migas de pan PII-seguras en Sentry, favorece eventos técnicos más una etiqueta de negocio gruesa. Evita la historia completa del usuario.
Una política práctica de captura:
- Seguro capturar: nombre de pantalla/ruta, ID de botón (no el texto del botón), claves de feature flag, ruta del endpoint de la API (sin query string), método HTTP y código de estado, tiempos (ms), conteo de reintentos, estado de la app como offline/online.
- Riesgoso: URLs completas con parámetros, cuerpos de petición/respuesta, campos de formularios introducidos por el usuario, email/teléfono/dirección, mensajes de error crudos que puedan reflejar la entrada.
- Nunca debe salir de la app: contraseñas, enlaces mágicos, tokens de sesión, tokens de refresco, claves API, datos de tarjeta de pago, identificaciones gubernamentales.
Un ejemplo concreto para un registro roto:
- Miga segura: “POST /api/signup -> 400, validation_failed, release 1.8.3”
- Miga riesgosa: “POST /api/signup body={email:..., password:...}”
La primera te dice dónde mirar. La segunda crea una filtración de datos.
Una clasificación simple de datos para migas y errores
Las migas de pan PII-seguras funcionan mejor cuando el equipo comparte una norma: cada valor que captures pertenece a una de tres categorías: seguro por defecto, seguro solo tras redacción, o jamás permitido. Si alguien puede nombrar la categoría en segundos, evitas filtraciones por “pensamos que estaba bien”.
Tres buckets a los que la mayoría de equipos puede apegarse
- Nunca capturar: credenciales y secretos (contraseñas, tokens de sesión, claves API, cabeceras de autorización, llaves privadas) y datos altamente sensibles (números completos de tarjeta, CVV, datos de salud).
- Capturar solo en forma reducida: datos personales que identifican a alguien (email, teléfono, IP, nombre completo, dirección). Si realmente los necesitas, hashéalos, trúncalos o sustitúyelos por una referencia interna estable.
- Seguro capturar: contexto técnico que ayuda a depurar (feature flags, nombre de ruta, botón pulsado, región del servidor, código de error).
Ejemplos que suelen funcionar:
- Email: forma reducida (o no capturarlo)
- Internal user_id: a menudo OK si no es adivinable
- Dirección IP: a menudo considerado dato personal
- Token de sesión: nunca
- Clave API: nunca
Una política de redacción que la gente realmente siga
Mantenla corta y coherente entre logs, migas de pan y eventos de error:
- Enumera los campos exactos que permites (por ejemplo: user_id, org_id, release, route, feature).
- Enumera los campos que siempre redacciones (token, password, authorization, cookie, secret, key).
- Anota dónde aparecen esos campos (cuerpo de petición, cabeceras, query string, almacenamiento local, entradas UI).
El mayor modo de fallo es “loguear el objeto entero”. Si ves ese patrón en una base de código heredada, trátalo como urgente: elimínalo primero y luego añade salvaguardas para que no vuelva.
Paso a paso: configuración base de Sentry con valores seguros por defecto
Elige una herramienta de reporte de errores y úsala de forma consistente. Sentry es común, pero el mismo enfoque aplica en otras. El objetivo es simple: cada error debe decir claramente dónde ocurrió y qué build lo lanzó.
Empieza estandarizando entornos y úsalos en todas partes: dev para trabajo local, staging para pruebas pre-lanzamiento y prod para usuarios reales. Haz que el entorno sea un valor de configuración, no algo que la gente escriba a mano.
Inicializa el SDK con valores seguros por defecto y solo las integraciones que necesitas. Una configuración mínima en el navegador podría verse así:
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,
});
Activa migas de pan que te ayuden a reproducir lo ocurrido sin convertir tus logs en un volcado de datos. Fuentes por defecto útiles son cambios de navegación, clicks del usuario, llamadas a la API (método + ruta, no URLs completas) y errores de consola.
Mantén el volumen bajo control para no ahogarte en ruido o costes. Algunos límites suelen prevenir eso:
- Limita las migas de pan (por ejemplo 50) para que una página ruidosa no domine la línea temporal.
- Recorta cadenas largas (por ejemplo 250 caracteres) para reducir filtraciones accidentales.
- Muestrea datos de performance (empieza en 5–10%) hasta saber qué necesitas.
- Añade limitación básica de tasa en el cliente para que un bucle roto no envíe miles de eventos.
Scrubbers y listas por defecto para mantener la PII fuera
El scrubbing funciona mejor cuando empiezas por una allowlist. En lugar de intentar bloquear cada posible secreto, decide qué campos de migas y errores aceptas y elimina el resto. Esa es la forma más segura de mantener las migas útiles sin recopilar datos privados.
Un valor por defecto práctico es conservar:
- Nombre del evento y un mensaje corto
- Un código de error estable (si lo tienes)
- Una plantilla de ruta (como
/users/:id) - Tags no personales (release, environment, feature flag)
Trata todo lo demás como sospechoso hasta que demuestres que es útil.
Después añade scrubbers estrictos y aburridos para los errores previsibles:
- Elimina claves que suelen llevar secretos:
password,pass,token,access_token,refresh_token,authorization,cookie,session,api_key - Redacta cabeceras de petición por defecto, luego permite solo las que realmente necesites (a menudo ninguna)
- Elimina strings de query y fragmentos (
?…y#…) a menos que haya una razón revisada para conservarlos - Normaliza identificadores de usuario: usa un id interno o un hash unidireccional, no email o teléfono crudo
- Descarta cuerpos de petición a menos que tengas una allowlist estricta para campos concretos
Ejemplo: un bug en el signup.
- Miga filtrada: “POST /signup?email=[email protected]”
- Miga más segura: “POST /signup (validation_failed, field=email)”, más un user id como
u_18429ohash_9f2c…
Sigues viendo qué ocurrió, pero no almacenas datos personales.
Seguimiento de releases que hace los errores accionables
Si un reporte de error no te dice qué versión lo lanzó, es difícil arreglarlo rápido. El seguimiento de releases ata cada evento y la traza de migas a un build para que puedas responder rápido: ¿esto empezó tras el último despliegue?
Adjunta un identificador de release a cada evento. Muchos equipos lo hacen al iniciar la app para que el release esté presente incluso si el crash ocurre en la primera pantalla.
Una regla de nombres de release que se mantenga sensata
Elige un formato de nombre que coincida con cómo ya construyes y despliegas. La consistencia importa más que la ingeniosidad.
- Usa la misma cadena de release en frontend y backend cuando sea posible
- Prefiere un SHA de git o un número de build
- Añade una etiqueta de entorno solo si tu tooling no separa ya los entornos
- Nunca incluyas emails de usuarios, nombres de tenants o URLs de peticiones en el nombre del release
Con eso, las migas PII-seguras se vuelven más útiles: puedes comparar “mismo flujo, diferente versión” sin inspeccionar datos personales.
Marca los despliegues para que los picos coincidan con cambios
Los marcadores de deploy convierten gráficos en una historia. Cuando las tasas de error suben, puedes alinear el pico con un despliegue y acotar la búsqueda al código que cambió.
Ejemplo: errores de signup suben tras el build web@3f2c1a9. Las migas muestran “pulsó Sign up”, “POST /api/signup”, luego un 500. No necesitas el email del usuario para actuar. Necesitas el release, el endpoint y el paso que falla.
Contexto accionable sin datos personales
Los buenos reportes de error responden una pregunta rápido: ¿qué ocurrió justo antes del crash? Puedes obtener esa claridad sin copiar emails, tokens, direcciones ni cuerpos de petición completos en las migas.
Empieza añadiendo unas pocas etiquetas seguras que describan la situación, no a la persona. Ejemplos útiles: estado de feature flag (on/off), tier del tenant (free/pro/enterprise), tipo de dispositivo (móvil/escritorio) y nivel de plan. Estas etiquetas convierten una pila de errores en grupos accionables.
El contexto de la petición es otra área de alta señal, pero manténlo mínimo:
- Método HTTP
- Plantilla de ruta (por ejemplo,
/projects/:id/settings, no el ID real) - Código de estado
Si añades latencia, considera redondearla (por ejemplo, 1200ms) en lugar de almacenar tiempos excesivamente detallados por sesión de usuario.
Para las migas, piensa en instantáneas de estado seguras: nombre de pantalla, número de paso en un flujo, conteo de reintentos. Eso solo puede mostrar patrones como “falla en el paso 2 tras 3 reintentos en móvil”, que suele ser suficiente para encontrar un bug lógico.
Un conjunto compacto de campos que suele ser útil y PII-seguro:
screen,flow_step,retry_countroute_template,method,status_codefeature_flag,tenant_tier,plan_level,device_typerelease,build,environment
Para conectar frontend y backend sin datos de usuario, añade un correlation ID. Genera un ID aleatorio por petición (o por sesión), envíalo en una cabecera y guárdalo como tag o extra a ambos lados. Cuando las migas muestran una petición fallida, puedes emparejarla con un error del servidor usando ese único ID.
Casos especiales: auth, pagos y prototipos generados por IA
Algunas partes de una app tienen más probabilidad de filtrar datos sensibles que otras. Si quieres migas PII-seguras, trata auth y pagos como “siempre peligrosos” y protégelos primero.
En el servidor, la opción más segura es capturar menos. Elimina cabeceras de petición que no necesites, redacta cuerpos de petición por defecto y nunca reenvíes cookies crudas en eventos de error. Si capturas temporalmente un cuerpo para depuración, permite solo claves específicas y limita el tamaño.
Para los flujos de autenticación, redacta todo lo que pueda usarse para iniciar sesión como el usuario:
- Cabeceras Authorization (Bearer tokens)
- Cookies e IDs de sesión
- JWTs, refresh tokens y tokens CSRF
- Códigos OAuth, valores state y URLs de redirección con parámetros
- Enlaces mágicos y códigos de un solo uso
En el cliente, ten cuidado con funciones “útiles” que sobre-coleccionan. Evita capturar snapshots completos del DOM, entradas de formularios o contenido del portapapeles. Prefiere migas que describan intención sin copiar datos, como “Pulsó botón Sign in” o “Validación fallida: contraseña demasiado corta”.
Los pagos requieren el mismo enfoque. Nunca registres números completos de tarjeta, CVC, datos bancarios o direcciones de facturación. Si necesitas contexto, captura resultados de alto nivel como “Proveedor de pago devolvió declined” más un código de error del proveedor.
Los prototipos generados por IA son un riesgo especial porque suelen loguear objetos completos “solo para ver qué hay dentro”, incluyendo cabeceras y variables de entorno. Si heredaste código de herramientas como Cursor, Replit, Bolt, Lovable o v0, busca console.logs y manejadores de error que vuelquen peticiones completas.
Una regla fiable: registra acciones y resultados, no payloads ni secretos.
Cómo probar que los scrubbers realmente funcionan
No asumas que los scrubbers funcionan solo porque los configuraste una vez. Trátalos como una función de seguridad: pruébalos en cada entorno (local, staging, producción) tras cualquier cambio en logging.
Envía un error controlado que incluya valores canario que nunca usarías en producción. Aún deberías poder depurar el flujo, mientras que cada valor sensible se elimina o reemplaza.
Una rutina de prueba repetible:
- Dispara una excepción de prueba que incluya un email falso (
[email protected]), un token falso (tok_test_SHOULD_NOT_LEAK) y una cadena tipo tarjeta (4242 4242 4242 4242). - Reproduce el error una vez en cada entorno y confirma que el evento llega.
- Abre la carga completa del evento y verifica mensaje, migas, cabeceras de petición y contexto extra para redacciones.
- Busca tus valores canario. No deberías encontrar coincidencias.
- Repite después de cambiar código de auth, formularios, pagos o analytics.
También revisa qué añade tu framework automáticamente. Muchas filtraciones vienen de cabeceras (Authorization, Cookie), URLs (query params) y cuerpos de formularios.
Escribe un runbook corto para cuando algo se filtre:
- deja de enviar el campo (desactiva la miga o contexto)
- aprieta los scrubbers o añade una allowlist
- elimina los eventos afectados según tu política
- vuelve a probar con canarios
- documenta la causa raíz para que no vuelva
Errores comunes que causan filtraciones accidentales
La mayoría de filtraciones de privacidad no son causa de un gran error. Surgen de pequeños valores por defecto que parecen inocuos hasta que un incidente aparece en tu herramienta de errores.
Depender de una blacklist es una trampa común. Redactas password y token, luego alguien añade ssn, dob o inviteCode y sale sin tocar. Las configuraciones más seguras empiezan con una allowlist: solo envía los campos que realmente necesitas para depurar.
Loguear URLs completas es otra fuga fácil. Los parámetros de consulta suelen llevar emails, teléfonos, tokens de restablecimiento e IDs internas. Una miga como GET /reset?email=...&token=... puede exponer exactamente lo que un atacante quiere. Prefiere plantillas de ruta y elimina query strings por defecto.
Los cuerpos de petición y respuesta contienen las peores sorpresas. Si tu SDK captura cuerpos por defecto, puedes acabar enviando formularios de registro, payloads de auth, objetos de pago, prompts de usuario y fragmentos de contenido subido.
Ten cuidado con el objeto user también. Usar email o teléfono crudos como user.id hace que cada evento sea directamente identificable. Usa un ID interno estable o un hash unidireccional y mantén los campos personales tras opt-in explícito y scrubbing.
Lista rápida antes de lanzar
Haz un repaso rápido con la mentalidad “¿qué podría revelar esto?”. Los reportes de error deben ayudarte a arreglar bugs, no convertirse en una base de datos paralela de información personal.
Un conjunto corto de comprobaciones previene la mayoría de fugas:
- Mantén las migas estructuradas y aburridas: campos fijos como
category,action,statuse IDs internos. Evita texto libre con entrada del usuario (términos de búsqueda, campos de formulario, mensajes de chat), incluso temporalmente. - Redacta secretos donde se escondan: bloquea o redacciona cabeceras Authorization, cookies, IDs de sesión, tokens CSRF, campos de contraseña, claves API y valores que coincidan con patrones de token.
- Haz cada evento accionable: confirma que
releaseyenvironmentestán adjuntos a cada error. - Plantilla rutas y doma URLs: registra
/users/:id/settingsen lugar de/users/48392/settings. Elimina query strings por defecto. - Prueba la redacción de extremo a extremo: envía un evento de prueba con secretos falsos (como
Bearer test_token_123) y un email falso, luego verifica que el panel muestre[REDACTED]o nada.
Antes del lanzamiento, elige un flujo realista (signup o checkout), dispara un error controlado y confirma que el reporte sigue teniendo suficiente contexto (plantilla de ruta, release, estado de feature flag, estado de red) para depurar sin exponer usuarios.
Ejemplo: depurar un registro roto sin exponer datos de usuarios
Una historia común: despliegas un viernes y los fallos de registro se disparan. Los usuarios ven un “Algo salió mal” después de pulsar “Crear cuenta”. Necesitas suficiente detalle para arreglarlo rápido, pero no puedes permitir filtrar emails, tokens o cabeceras de auth en tu herramienta de errores.
Con migas PII-seguras en Sentry, el informe sigue siendo accionable. El evento muestra la ruta sin el payload privado:
- Migas:
Signup screen opened->Email form submitted->POST /api/signup (400)->Magic link screen shown->POST /api/verify (401) - Contexto: environment
production, navegador y SO, estado de feature flag (on/off) y códigos de respuesta de la API - Tags:
flow=signup,provider=email_magic_link,region=us-east
Al mismo tiempo, los scrubbers redactan valores sensibles antes de que algo salga de la app. El evento debería reemplazar o eliminar:
- Valores de entrada de email y campos de “nombre”
- Token del magic link, código OTP, cookies de sesión
- Cabecera Authorization y cualquier
x-api-key
Ahora el porqué queda claro sin datos personales: los errores empezaron con el release [email protected], y la mayoría ocurre en POST /api/verify con un 401. Eso apunta a un cambio de lógica o configuración, no a comportamiento aleatorio de usuarios.
El seguimiento de releases lo acota más. Compara commits entre 1.8.2 y 1.8.3 y normalmente encontrarás un cambio pequeño como un endpoint renombrado, una cookie que dejó de establecerse o un nuevo middleware que bloquea la ruta de verify.
Próximos pasos: mantenerlo seguro a medida que la app crece
Una vez que las migas PII-seguras funcionan, trata la privacidad como un trabajo continuo. Las apps cambian rápido: nuevos endpoints, SDKs de terceros y logs de depuración añadidos en una reparación nocturna.
Asigna un responsable único para reportes de error seguros para la privacidad. No necesita hacerlo todo, pero debería ejecutar una revisión rápida con regularidad y asegurarse de que los cambios no debiliten scrubbers o allowlists.
Añade una puerta de release para que errores obvios se detecten antes de lanzar. Incluso una verificación simple en CI que escanee patrones comunes de secretos puede evitar mucha exposición accidental. Acompáñalo con una regla de code review: no loguear cuerpos de petición, cabeceras de auth ni objetos de usuario completos.
Buenas prácticas continuas:
- Revisar eventos recientes y confirmar que el scrubbing sigue funcionando
- Volver a comprobar la allowlist después de añadir nuevas migas o integraciones SDK
- Rotar claves si alguna vez se capturó algo sensible, luego endurecer filtros
- Ejecutar una auditoría dirigida tras grandes features (cambios de auth, facturación, cargas de archivos)
- Mantener una norma de equipo compartida: depurar con IDs y contadores, no con datos crudos
Si heredaste un proyecto generado por IA que es ruidoso, roto o filtra secretos, una auditoría focalizada puede ser más rápida que intentar adivinar dónde ocurre el logging. FixMyMess (fixmymess.ai) se especializa en diagnosticar y reparar codebases generados por IA y en endurecerlos para producción, incluyendo logging y reportes de errores más seguros.