← Todos los checks
SeguridadSeveridad típica: Alto

Tokens en almacenamiento local

Detecta si tu JavaScript guarda tokens en localStorage/sessionStorage, vulnerables a robo vía XSS.

Qué comprueba

Este escáner detecta si tu JavaScript guarda tokens de sesión o autenticación en localStorage o sessionStorage del navegador. Identifica cuando las credenciales de acceso se almacenan en un lugar accesible desde el propio código de la página.

Por qué importa

Los datos guardados en localStorage son accesibles por cualquier JavaScript que se ejecute en la página, así que si hay un fallo de XSS un atacante puede robar el token y suplantar al usuario. Es un lugar mucho menos seguro para credenciales que una cookie bien protegida.

Cómo se arregla

Siempre que puedas, guarda los tokens de sesión en cookies con los atributos HttpOnly y Secure, que el JavaScript no puede leer. Si necesitas usar tokens en el cliente, reduce su duración y combina esto con una buena protección frente a XSS.

Cómo funciona esta comprobación

Scanaris lee el JavaScript de tu página principal, incluidos los scripts que carga desde tu dominio, y busca llamadas a localStorage.setItem o sessionStorage.setItem cuya clave sugiera una credencial: token, jwt, auth, secret, password, api_key, access, refresh o bearer. Si encuentra una, abre un hallazgo de severidad baja. Es baja porque guardar un token en el navegador no es una brecha por sí misma; se convierte en una cuando se combina con cualquier inyección de script, y por eso merece la pena saberlo.

Por qué importa

Todo lo que hay en localStorage lo puede leer cualquier código que se ejecute en tu página: tus scripts, los de terceros que cargas (analítica, chats, widgets) y cualquier script que un atacante consiga inyectar. Una sola vulnerabilidad XSS, en tu código o en una dependencia, basta para que localStorage.getItem('token') viaje a un servidor ajeno y alguien use la sesión de tu usuario desde otro sitio, sin su contraseña y sin que lo note. Una cookie con HttpOnly es invisible para JavaScript, así que ese mismo XSS no puede robarla; puede hacer peticiones mientras la página está abierta, que es malo, pero no llevarse la sesión.

De dónde viene normalmente

De la configuración por defecto de muchas librerías de autenticación en aplicaciones de una sola página. El cliente de Supabase para el navegador guarda la sesión en localStorage si no le dices otra cosa, igual que muchos ejemplos de JWT "hecho a mano" con Express. Lovable, Bolt y v0 generan ese patrón porque es el que aparece en la documentación de inicio rápido.

Cómo arreglarlo

  • Sesión en cookies HttpOnly. Si tienes servidor (Next.js, Nuxt, Express, una Edge Function), que sea él quien reciba el token del proveedor y lo guarde en una cookie con HttpOnly, Secure y SameSite=Lax. El navegador la envía sola y nunca la ve.
  • Con Supabase: en Next.js o Nuxt usa @supabase/ssr, que guarda la sesión en cookies; en una SPA pura sin servidor, acepta el riesgo y compénsalo con una CSP estricta, porque no hay otro sitio donde guardarla.
  • Tokens cortos y refresco seguro. Si el token de acceso tiene que vivir en memoria o en storage, que caduque en minutos y que el de refresco vaya en una cookie HttpOnly.
  • Memoria en lugar de storage. Guardar el token en una variable de JavaScript (no en storage) lo protege de scripts que lean storage, aunque no de un XSS activo en la misma página. Mejor que localStorage, peor que una cookie.
  • Reduce la superficie de XSS. Una CSP sin 'unsafe-inline' en script-src, sanear cualquier HTML de usuario y revisar los scripts de terceros que cargas. Es la defensa que hace que el token en storage no importe.

Comprueba que está arreglado

curl -s https://tudominio.com | grep -oE 'src="[^"]+\.js[^"]*"' | cut -d'"' -f2 | head -3
curl -s https://tudominio.com/assets/index-XXXX.js | grep -oE "(local|session)Storage\.setItem\([^)]{0,60}" | head

Si el segundo comando devuelve líneas con token, auth o similares en la clave, el patrón sigue ahí. En las herramientas del navegador, pestaña Aplicación, puedes ver qué guarda tu app en storage tras iniciar sesión.

Preguntas frecuentes

Supabase guarda la sesión en localStorage por defecto. ¿Está mal?

Es el compromiso que asume una SPA sin servidor. Si tienes servidor, cambia a @supabase/ssr. Si no, cuida la CSP y los scripts de terceros: ese token es tan seguro como la página que lo rodea.

¿sessionStorage es más seguro que localStorage?

Solo en duración: se borra al cerrar la pestaña. Cualquier script de la página lo lee igual.

¿Por qué es severidad baja si puede robar la sesión?

Porque requiere otra vulnerabilidad (un XSS) para explotarse. El check te avisa para que decidas con información; si tu web ya tiene una CSP estricta y no muestra contenido de usuario sin sanear, el riesgo real es pequeño.

Compruébalo en tu web

Escanea tu web gratis y mira si este y otros 44 checks pasan, con un prompt de arreglo por cada fallo.

Escanear mi web gratis

Del blog

Checks relacionados