Skip to content

Security: capitaharlock/evolvea

Security

SECURITY.md

Modelo de seguridad — Evolvea

Notas para uno mismo. El código es público, los datos no.

Capas

  1. Bearer token único (ACCESS_TOKEN). Todo endpoint salvo /api/health lo requiere. Se valida con comparación de strings constante por tamaño en el Worker.
  2. CORS allowlist explícita. Solo evolvea.pages.dev, sus previews *.evolvea.pages.dev y localhost pueden recibir respuesta del navegador. Otros orígenes se ignoran (no se devuelve Access-Control-Allow-Origin).
  3. Rate limiting in-memory por IP dentro del Worker:
    • Sin auth válida: 10 req / min / IP
    • Endpoints LLM (caros): 30 req / min / IP
    • Resto autenticados: 200 req / min / IP
    • Limitación: cada isolate de Cloudflare tiene su propio mapa. Para máxima dureza, activar Rate Limiting Rules en el dashboard de Cloudflare a nivel de zona/worker.
  4. Cifrado en reposo para credenciales Garmin (AES-GCM con ENCRYPTION_KEY). Nunca se devuelven al cliente.
  5. Whitelist de columnas escribibles en db.updateProfile(). Defiende contra inyección por nombre de columna en el PATCH del perfil.

Lo que NO viaja al cliente

GET /api/profile strip-ea estos campos antes de responder:

  • llm_api_key, nutrition_api_key
  • garmin_email_enc, garmin_password_enc

Las API keys de los LLM siempre las usa el Worker server-side (env.OPENROUTER_API_KEY, env.ANTHROPIC_API_KEY, etc.).

Rotación del ACCESS_TOKEN

Si crees que se ha filtrado el token (lo viste en una captura, lo metiste en un repo público sin querer, etc.):

# 1. Genera uno nuevo
openssl rand -base64 48

# 2. Pégalo en api/.dev.vars (reemplaza la línea ACCESS_TOKEN=...)
# 3. Sube al Worker:
cd api
echo "$NUEVO_TOKEN" | npx wrangler secret put ACCESS_TOKEN

# 4. Actualízalo en el cliente. En la app, ve a Ajustes → Conexión
#    (o ejecuta en la consola del navegador):
localStorage.setItem('rjj_token', 'EL_NUEVO_TOKEN');

Lo que NO está protegido contra

  • Suplantación si pierdes el token: si el token cae, el atacante tiene acceso total a tus datos. Rota.
  • DDoS distribuido: el rate limit in-memory es per-isolate. Un atacante con muchas IPs distintas puede saltárselo. Mitigación: Cloudflare rate-limiting rules a nivel zona (gratis hasta 10k req/mes).
  • Cosechado de respuestas de IA: si el token cae, el atacante puede gastar tu cupo de OpenRouter. Mitigación: poner un límite de gasto en OpenRouter.

Reporte de vulnerabilidades

Si encuentras un fallo de seguridad, abre un issue privado en GitHub o escríbeme a rjj@proars.com.

There aren't any published security advisories