15 ene 2026·7 min de lectura

Errores de caché en cliente: deja de mostrar datos de otro usuario

Aprende a evitar errores de caché del lado del cliente que muestran datos de otro usuario auditando claves de caché, reglas de invalidación y casos en dispositivos compartidos.

Errores de caché en cliente: deja de mostrar datos de otro usuario

Cómo se ve “datos de usuario equivocados” en apps reales

Este fallo suele aparecer como un momento de “espera, ¿por qué estoy viendo eso?”. Alguien abre la app y ve el nombre, avatar, dirección o último pedido de otra persona. A veces solo parpadea un segundo antes de que la pantalla se corrija. Otras veces se queda hasta que se hace un refresco completo o se reinstala la app.

A menudo lo verás durante:

  • Cerrar sesión y luego iniciar sesión con otra cuenta
  • Cambiar de espacios de trabajo/u organización
  • Cambios de rol (de admin a miembro, o al revés)
  • Renovación de token y flujos de “recordarme” en dispositivos compartidos

Un ejemplo simple: pruebas tu app en un iPad compartido. Inicias sesión como Cliente A, miras pedidos y luego cierras sesión. Un compañero inicia sesión como Cliente B y abre Pedidos. La app muestra la lista del Cliente A porque la respuesta cacheada se guardó con una clave genérica como orders en lugar de algo con alcance como orders:userId.

No es solo un fallo de UI. Es un problema de privacidad. Incluso un destello breve puede exponer datos personales como correos, direcciones, facturas o tickets de soporte. En industrias reguladas puede convertirse en un problema de cumplimiento. Incluso si no se filtra información sensible, la confianza se pierde rápido.

El objetivo es sencillo: cada persona debe ver solo sus propios datos, siempre — tras refrescos, cambios de pestaña, modo offline y inicios de sesión en dispositivos compartidos.

Dónde ocurre el caching del lado del cliente (mapa rápido)

Cuando una app muestra los datos de otra persona, la causa rara vez es “la caché” en general. Es uno de varios sitios donde el estado puede persistir tras cambios de identidad. Aquí tienes un mapa rápido para mirar en los lugares correctos.

1) La caché HTTP integrada del navegador

Los navegadores pueden cachear peticiones GET según la URL, cabeceras y reglas de caché. Si tus respuestas de API varían por usuario pero son cacheables, el navegador podría reproducir la última respuesta incluso después de cerrar sesión e iniciar otra.

Esto es menos común en APIs JSON autenticadas (normalmente no cacheables), pero puede ocurrir por cabeceras faltantes o proxies/CDN mal configurados.

2) Cachés a nivel de app que controlas

La mayoría de problemas de “usuario equivocado” vienen de cachés dentro de tu app:

  • Estado en memoria (stores globales, singletons, variables a nivel de módulo)
  • localStorage/sessionStorage (persiste entre pestañas y recargas)
  • IndexedDB (común en apps offline-first)
  • “Respuestas guardadas” almacenadas por rendimiento

Si cualquiera de estos usa claves demasiado amplias (o no usa clave), una cuenta puede ver los datos de otra en un dispositivo compartido.

3) Librerías de fetching de datos con cachés de queries

Librerías como React Query, SWR, Apollo y RTK Query cachean resultados usando una clave que das (o generan). Si esa clave no incluye el contexto de identidad actual, la librería puede servir un resultado cacheado de la sesión anterior.

Esto suele verse así: “Cambio de cuenta y el widget de perfil sigue mostrando el nombre antiguo hasta que se refresca”.

4) Service workers y cachés offline

Los service workers pueden cachear HTML, respuestas de API y assets. Si las reglas de caché son demasiado amplias, pueden cachear respuestas personalizadas y reproducirlas offline o durante una conexión inestable.

5) Desajustes entre SSR y la hidratación CSR

Si renderizas en el servidor, el cliente puede hidratar usando estado obsoleto de una sesión anterior (o de un store persistido). Un patrón común es la UI cargando datos cacheados del usuario primero y luego “corrigiendo” tras una petición. Esa “corrección” aún puede ser una fuga de privacidad.

Audita tus claves de caché para que los usuarios no colisionen

La mayoría de bugs de usuario equivocado empiezan con una clave de caché demasiado amplia. Si dos sesiones diferentes pueden producir la misma clave, la app puede devolver “correctamente” la respuesta cacheada equivocada.

Una clave segura describe tanto:

  • qué son los datos, y
  • para quién son (y bajo qué alcance).

Una buena regla: si un cambio alteraría lo que el servidor está permitido a devolver, también debe cambiar la clave de caché.

En la práctica, las claves (o namespaces) suelen necesitar incluir:

  • ID de usuario (u otro identificador estable de cuenta)
  • ID de tenant/org/workspace (para apps multi-tenant)
  • Rol o ámbito de permisos (admin vs miembro)
  • Locale (si el contenido cambia por idioma/región)
  • Forma de la consulta como filtros y paginación

Evita claves como me, profile, dashboard o inbox a menos que estén explícitamente con alcance por usuario.

  • Malo: profile o me
  • Bueno: user:123:org:55:profile

Misma idea con listas:

  • Malo: orders?page=1
  • Bueno: user:123:org:55:orders?status=open&page=1

Para detectar colisiones rápidamente, busca cadenas de clave compartidas y dónde se reutilizan. Si puedes, registra la clave calculada en tiempo de ejecución, cambia de cuenta y compara.

Reglas de invalidación de caché que coincidan con acciones reales de usuario

La mayoría de bugs de usuario equivocado no son complicados. La app sigue usando datos que eran correctos hace cinco minutos, pero para otra persona.

Empieza por decidir qué debe borrarse (o re-escribirse) cuando cambia la identidad. Cerrar sesión es obvio, pero el cambio de cuenta es la trampa común: la UI actualiza la insignia de “cuenta actual” mientras las queries cacheadas siguen apuntando al usuario previo.

Una regla simple que funciona bien: cuando cambia el “contexto de usuario actual” (ID de usuario, ID de org, ID de workspace), trátalo como un mini reinicio de los datos con alcance por usuario.

Desencadenantes prácticos para conectar:

  • Login, logout, cambio de cuenta: borra cachés con alcance por usuario, cancela peticiones en vuelo, vuelve a obtener lo esencial.
  • Cualquier cambio en lo que el usuario puede ver: actualizaciones de rol/permiso, cambios de org/proyecto.
  • Eventos de auth: fallos en refresh de token, reautenticación forzada, respuestas de “sesión expirada”.

Los TTL no son solo ajustes de rendimiento. Son controles de privacidad. El contenido público puede vivir más tiempo, pero cualquier cosa ligada a identidad (perfil, facturación, permisos, actividad reciente) debería expirar rápido, sobre todo en dispositivos compartidos.

Mantén los resets de caché fáciles de llamar desde un solo lugar. Crea una función única (por ejemplo, resetUserState()) que limpie las cachés correctas y reinicialice la app, y llámala desde los flujos de login/logout/cambio de cuenta. Cuando la lógica de reset está dispersa, un camino acabará quedándose sin limpiar.

Paso a paso: reproducir y depurar el problema

Lock down sensitive data
Harden your app against exposed secrets, weak auth flows, and risky client storage.

La manera más rápida de arreglar estos fallos es provocarlos bajo demanda. Usa un perfil de navegador (o un dispositivo de prueba compartido) y dos cuentas de prueba con datos claramente distintos (nombre distinto, avatar y al menos un registro único).

Anota los clics exactos mientras lo haces. Los pequeños detalles importan: qué pestaña abriste primero, si usaste atrás/adelante y si cerraste sesión o solo cambiaste de cuenta.

Un runbook que suele exponer la fuga:

  • Inicia sesión como Cuenta A y visita la página que luego muestra datos equivocados.
  • Sin cerrar la pestaña, cierra sesión. Inicia sesión como Cuenta B. Revisa la misma página usando la misma ruta de navegación (incluyendo atrás/adelante si la usaste).
  • Inspecciona el almacenamiento del navegador (Local Storage, Session Storage, IndexedDB) y los paneles de caché. Busca entradas cacheadas que no cambiaron tras el cambio.
  • Añade logs temporales alrededor de lecturas y escrituras de caché: registra la clave de caché, el identificador de usuario actual y de dónde vino la data (memoria, almacenamiento, red).
  • Revisa el panel Network. Si la respuesta del servidor es para la Cuenta B pero la UI muestra la Cuenta A, el bug está en el cliente.

Una señal clara: si ambos usuarios golpean la misma clave como profile:me, podrías leer el perfil del Usuario A después de que el Usuario B inicie sesión. Registrar la clave más el ID de usuario actual deja eso claro.

Casos límite en dispositivos compartidos y multi-cuenta para probar

Los dispositivos compartidos son donde esto se vuelve embarazoso rápido. “Cerrar sesión” a menudo borra un token, pero no los datos cacheados que se obtuvieron con ese token.

Un ejemplo realista: pruebas la app en la tablet familiar. Cierras sesión, otra persona inicia sesión y la pantalla principal parpadea brevemente mostrando tu dashboard antes de actualizarse. Aunque se corrija, ese parpadeo es una fuga de privacidad.

El uso multi-cuenta en el mismo navegador es otro punto problemático. Dos pestañas pueden acabar con estados de sesión distintos, especialmente si una pestaña refresca tokens o rehidrata estado mientras la otra aún renderiza datos antiguos. Si tu caché es global (no ligada a identidad), las colisiones se vuelven probables.

El botón atrás es un caso especial. Algunos navegadores mantienen páginas en memoria usando la back-forward cache (bfcache). Tras cerrar sesión, un usuario puede pulsar Atrás y ver una pantalla previa con sesión iniciada al instante — incluyendo datos cacheados — antes de que tu app vuelva a ejecutar las comprobaciones de auth.

Ejecuta estas pruebas antes de lanzar:

  • Inicia sesión como Usuario A, abre una página con muchos datos, cierra sesión y luego inicia sesión como Usuario B sin recargar el navegador.
  • Repite en un dispositivo compartido y también cierra y vuelve a abrir la pestaña después de cerrar sesión.
  • Abre dos pestañas: inicia como A en la pestaña 1, B en la pestaña 2, luego refresca ambas y observa si hay UI mezclada.
  • Tras cerrar sesión, pulsa Atrás y confirma que nunca ves los datos de A, ni siquiera brevemente.

Trampas del service worker y caching offline

Los service workers son geniales para velocidad, pero también pueden reproducir los datos de la persona equivocada. El mayor riesgo es usar patrones cache-first o stale-while-revalidate en peticiones que dependen de quién ha iniciado sesión.

Ejemplo: una tablet compartida en una tienda. El Usuario A inicia sesión y abre el dashboard, luego cierra sesión. El Usuario B inicia sesión más tarde, pero el service worker sirve una respuesta cacheada para /api/me o /api/orders antes de que termine la actualización en red. Por un momento (o más, si la red falla), B ve los datos de A.

Cache-first y stale-while-revalidate suelen ir bien para ficheros públicos y estáticos (app shell, iconos, CSS). Son arriesgados para endpoints con alcance por usuario, especialmente cuando la URL no incluye un identificador de usuario y depende de cookies o bearer tokens.

Cuando dudes, evita cachear todo lo relacionado con identidad:

  • Endpoints como /api/me, /api/profile, /api/billing, /api/orders
  • Cualquier petición con cabecera Authorization
  • Cualquier respuesta que devuelva PII (emails, direcciones, facturas)

Si cambias reglas de login, logout, refresh de token o roles, trátalo también como un cambio rompedor para tus cachés. Versiona cachés (por ejemplo, app-v5) y elimina cachés antiguas en activate. Si no, respuestas viejas pueden seguir apareciendo tras creer que arreglaste el bug.

El modo offline necesita cuidado extra. Mantén los datos offline estrictamente por usuario y bórralos al cerrar sesión. Si almacenas peticiones en cola o respuestas de API cacheadas, incluye el ID de usuario actual en la clave de almacenamiento y rechaza lecturas cuando cambia el usuario conectado.

Comprobaciones de seguridad y privacidad (simples pero críticas)

Get expert remediation
We combine AI tools with human verification and a 99% success rate on repairs.

Cuando el caching del cliente muestra los datos de otra persona, trátalo primero como un incidente de seguridad y luego como un bug de UI.

La regla clave: nunca confíes en la caché del cliente para decidir quién puede ver algo. El estado cacheado puede estar obsoleto, contaminado o copiado entre sesiones. La autorización debe aplicarse en el servidor, cada vez.

Un chequeo rápido: si alguien cambia el ID de usuario en una petición (o reproduce una petición vieja), ¿el servidor sigue devolviendo datos? Si sí, no tienes solo un problema de UI.

Comprobaciones mínimas que vale la pena ejecutar:

  • Verifica que cada endpoint compruebe identidad en el servidor y escale los datos a esa identidad.
  • Confirma que cerrar sesión invalida sesiones y refresh tokens en el servidor, no solo el estado de la UI.
  • Reduce datos sensibles en almacenamiento de larga duración (localStorage, IndexedDB). Manténlos en memoria cuando sea posible.
  • Asegúrate de que las respuestas cacheadas no se compartan entre cuentas en el mismo dispositivo.
  • Busca en el código secretos expuestos o tokens hardcodeados.

Un ejemplo más: si la UI muestra brevemente un /api/me cacheado tras cerrar sesión, eso es grave. Si además el servidor acepta tokens viejos, empeora: la siguiente persona podría cargar datos reales, no solo píxeles obsoletos.

Errores comunes que causan datos de usuario equivocados

Los bugs de usuario equivocado suelen venir de un problema subyacente: la app olvida que los datos cacheados deben ligarse a una identidad, no solo a una pantalla.

Causas comunes:

  • Un store global o singleton sobrevive al logout, de modo que el siguiente login hereda los datos del último usuario.
  • Peticiones iniciadas antes del logout terminan después y sus respuestas se escriben en la caché de la nueva sesión.
  • Las claves de caché son demasiado genéricas (/me, dashboard) y no incluyen usuario, tenant, rol o entorno.
  • Actualizaciones optimistas escriben en una caché compartida sin comprobar el scope del usuario activo.
  • El logout solo borra lo que ves (estado de UI) pero deja la fuente de verdad intacta (caché en memoria, storage, cachés del service worker).

Dos comprobaciones rápidas que detectan muchos de estos:

  1. Cierra sesión y luego inicia con otro usuario mientras limitas la red. Observa qué se renderiza antes de que termine la primera llamada nueva a la API.
  2. Provoca una petición lenta, cierra sesión a mitad de la carga y vuelve a iniciar sesión. Si la respuesta lenta llega y actualiza la nueva sesión, tienes un problema de escrituras en vuelo.

Lista de verificación rápida antes de publicar: caché e identidad

Catch wrong-user data fast
Send your repo for a free audit and find the exact cache and auth leaks.

Antes de desplegar un fix, haz una pasada final centrada en la identidad. Tras cualquier cambio de auth, la app no debe mostrar datos del usuario previo — ni siquiera brevemente.

Prueba en el mismo dispositivo y perfil de navegador (ahí es donde aparecen la mayoría de sorpresas):

  • Haz un intercambio A→B: inicia como Usuario A, abre pantallas con muchos datos, cierra sesión, luego inicia como Usuario B y revisita las mismas pantallas.
  • Confirma que las claves de caché tienen alcance por identidad dondequiera que almacenes resultados (cachés en memoria, query caches, localStorage, IndexedDB).
  • Haz que el logout sea un reinicio completo: borra tokens, refresh tokens, respuestas cacheadas de API, stores persistidos y valores de “última cuenta seleccionada”.
  • Trata el cambio de cuenta como más importante que la navegación: invalida queries por usuario, cancela peticiones en vuelo y refetch bajo la nueva identidad.
  • Revisa el comportamiento del service worker: versiona caches en cada despliegue y no sirvas respuestas de API específicas de usuario desde una caché compartida.

Después, inspecciona elementos de identidad “pegajosos” como menús de perfil, elementos recientes y badges de notificaciones. A menudo provienen de una caché distinta al feed principal.

Próximos pasos: hacer que la solución perdure

Elige una regla de aceptación y hazla innegociable: tras el logout (o cambio de cuenta), la app no debe mostrar ningún dato del usuario anterior, ni siquiera por un momento. Usa esa frase para guiar tus pruebas manuales y tus tests automáticos.

Un orden práctico de trabajo que detecta la mayoría de problemas:

  • Arregla primero las claves de caché para que tengan alcance por usuario/org/rol.
  • Haz que el logout y el cambio de cuenta borren cachés por usuario, reinicien el estado en memoria y cancelen peticiones en vuelo.
  • Revisa las reglas del service worker y quita el cacheo de endpoints autenticados a menos que sea intencional.
  • Añade una prueba automatizada “Usuario A luego Usuario B” para evitar regresiones.

Si trabajas con una base de código generada por IA (de herramientas como Lovable, Bolt, v0, Cursor o Replit), estos problemas de identidad y caché son especialmente comunes porque los patrones se copian de forma inconsistente entre pantallas. FixMyMess (fixmymess.ai) se centra en diagnosticar y reparar exactamente estos problemas — colisiones de claves de caché, limpieza rota al cerrar sesión y errores en las cachés de service worker — y puede empezar con una auditoría de código gratuita para localizar dónde vienen los datos de usuario equivocados.

Preguntas Frecuentes

Why does my app show another user’s data after logout and login?

Suele ser una colisión de caché o de estado: datos obtenidos para el Usuario A se almacenan bajo una clave que también usa el Usuario B, o no se borran cuando cambia la identidad. Como resultado, la app lee correctamente datos cacheados, pero de la persona equivocada.

What should a “safe” cache key include to prevent user collisions?

Incluye tanto qué datos son como para quién son. Un valor por defecto seguro es identificar por ID de usuario más tenant/org/workspace y cualquier contexto que cambie permisos (por ejemplo, rol). Además agrega filtros de consulta y paginación para que las listas no colisionen.

What exactly should happen on logout or account switching?

Trátalo como un mini reinicio del estado vinculado al usuario. Borra o vuelca las cachés por usuario, cancela solicitudes en vuelo, reinicia cualquier almacén persistido y vuelve a obtener las consultas esenciales bajo la nueva identidad para que nada antiguo pueda renderizar primero.

How do I fix this if I’m using React Query, SWR, Apollo, or RTK Query?

Asegúrate de que la clave de la consulta cambie cuando cambie el contexto de usuario y limpia o invalida explícitamente las queries al cerrar sesión o cambiar de cuenta. Considera desactivar comportamientos de “keep previous data” para queries ligadas a identidad para evitar destellos de datos antiguos.

Can a service worker cause wrong-user data, and how do I prevent it?

Sí. Por defecto, no caches respuestas de API específicas del usuario en el service worker. Cachea el app shell y los activos estáticos, pero deja que las solicitudes autenticadas vayan a la red. Además, elimina cachés antiguas en el evento activate para que respuestas viejas no reaparezcan tras despliegues.

How can SSR/CSR hydration cause a brief “flash” of the wrong profile?

Sí. Si hidratas la UI desde estado persistido en el cliente o reutilizas estado renderizado en el servidor de una sesión anterior, el cliente puede mostrar información de usuario obsoleta antes de que termine la primera petición. Solución: guarda el estado persistido por usuario y retrasa la visualización de campos sensibles hasta confirmar la identidad.

What’s the fastest way to reproduce and debug a wrong-user data leak?

Reprodúcelo con un perfil de navegador y dos cuentas de prueba, y registra lecturas/escrituras de caché con la clave calculada y el ID de usuario actual. Si la respuesta de red es correcta para el Usuario B pero la UI muestra al Usuario A, estás sirviendo estado cliente obsoleto o leyendo la clave equivocada.

Which shared-device and multi-tab edge cases should I test before shipping?

Usa el mismo dispositivo o perfil de navegador, cambia cuentas sin cerrar pestañas, prueba la navegación atrás/adelante y limita la red para exponer condiciones de carrera. También prueba dos pestañas con diferentes cuentas porque las cachés globales y la renovación de tokens pueden mezclar contextos.

Is this just a UI bug, or a real security issue?

Haz que el servidor aplique autorización en cada petición, aunque la UI normalmente oculte datos. Trata el fallo del cliente como un incidente de privacidad, verifica que tokens/sesiones se invaliden al cerrar sesión y reduce lo que almacenas a largo plazo en localStorage o IndexedDB.

How can FixMyMess help if this came from an AI-generated codebase?

Las bases de código generadas por IA suelen tener patrones inconsistentes de estado y claves de caché, así que estas fugas pueden ser difíciles de localizar. FixMyMess puede empezar con una auditoría de código gratuita para identificar la colisión o la escritura obsoleta, y luego reparar la limpieza de logout, el alcance de caché y las reglas del service worker para eliminar el destello de datos de otros usuarios.