← Documentation

Security · reglas para un repo PÚBLICO con keys de pago detrás

Este repo será público desde el día 1. Estas reglas se aplican antes del primer push y en cada parte.

1. Qué es secreto y qué no

Variable Dónde vive Cliente? Notas
ALCHEMY_KEY Vercel env (Production/Preview) + .env.local NUNCA Crear app Alchemy nueva SOLO para servidor. Sin NEXT_PUBLIC_. Activar en Alchemy: límite de CU/día y alertas de uso
ANTHROPIC_API_KEY Vercel env + .env.local NUNCA Solo se usa en app/api/ask/route.ts. Poner spend limit en la consola de Anthropic
SUPABASE_SECRET_KEY Vercel env + .env.local NUNCA Formato nuevo sb_secret_.... Bypassa RLS. Solo server
NEXT_PUBLIC_ONCHAINKIT_API_KEY Vercel env + .env.local Sí (por diseño) Es pública por diseño; en el portal CDP restringir a los dominios permitidos
NEXT_PUBLIC_SUPABASE_URL / PUBLISHABLE_KEY Vercel env Sí (por diseño) Formato nuevo sb_publishable_.... Seguras solo si RLS está activo en TODAS las tablas
NEXT_PUBLIC_DEMO_WALLET Vercel env No es secreto

Regla: si una variable empieza por NEXT_PUBLIC_, asume que está impresa en la home. Nada de pago va con ese prefijo.

2. Git y GitHub

  • .gitignore ya excluye .env* (salvo .env.example). Nunca comitear .env.local. .env.example solo con valores vacíos.
  • Antes del primer push: instalar gitleaks y añadir hook pre-commit (gitleaks protect --staged). Correr gitleaks detect sobre todo el historial antes de hacer público el repo.
  • En GitHub: activar Secret scanning + Push protection (Settings → Code security), Dependabot alerts, y branch protection en main (PR obligatorio o al menos no force-push).
  • Si una key se filtra (aunque sea 1 minuto): rotarla de inmediato en el proveedor. Borrar el commit no sirve.
  • No subir capturas de pantalla ni logs con headers/keys al repo o a X.

3. Vercel

  • Env vars solo en el dashboard de Vercel (cifradas), separadas por entorno. No en vercel.json, no en el código.
  • Desactivar "Automatically expose System Environment Variables" si no se usan.
  • Revisar en cada deploy que el bundle del cliente no contiene secretos: grep -r "sk-ant\|ALCHEMY" .next/static debe devolver vacío.

4. API routes (superficie pública que gasta dinero)

  • Rate limit por IP en TODAS las rutas (lib/rateLimit.ts): /api/portfolio 10/min, /api/ask 5/min, /api/pools 30/min.
  • /api/ask: max_tokens acotado, historial limitado a N mensajes, sin ejecutar nada que venga del usuario, tools de solo lectura, timeout. Presupuesto diario global (contador en memoria o Supabase) que corta el endpoint si se excede.
  • Validar toda entrada (^0x[0-9a-fA-F]{40}$ para direcciones, rangos numéricos en simulate). Responder 400, nunca 500 con stack trace.
  • Caché en memoria por wallet (TTL 5 min) para no repetir escaneos caros.
  • CORS: mismo origen. No exponer las rutas como API pública en el MVP.

5. Supabase (cuando se active)

  • RLS habilitado en todas las tablas (el schema.sql ya lo trae). Métrica de "capital conectado": tabla wallet_snapshots escrita solo desde el servidor con service role; lectura pública solo del agregado vía una vista o función, nunca de las filas.

6. Dependencias

  • npm audit antes de cada release. Versiones fijadas exactas en package.json.
  • Instalar solo paquetes conocidos (OnchainKit, wagmi, viem, ethers, recharts, Anthropic SDK, Supabase).

Evaluación de vulnerabilidades · 5 sep 2026

Auditoría inicial: 38 vulnerabilidades, 3 críticas y 4 altas. Casi todas son transitivas del árbol de conectores de wallet que arrastra OnchainKit (WalletConnect, MetaMask SDK, Reown AppKit, Farcaster Mini App SDK y, por esa vía, @solana/web3.js), no de código nuestro.

Acción tomada: overrides en package.json forzando axios@1.20.0, ws@8.21.3 y elliptic@6.6.1. Resultado: 0 críticas, 1 alta, con el build intacto.

Paquete Severidad De dónde viene Evaluación
elliptic era crítica @ethersproject/signing-key ← ethers v5 Resuelto por override a 6.6.1. Además, el motor nunca firma nada ni maneja claves privadas: los avisos son sobre firmar o verificar con entradas malformadas
axios era alta @coinbase/cdp-sdk ← conector baseAccount Resuelto por override a 1.20.0. Ese SDK está en el árbol por el botón de conectar wallet; no lo llamamos
ws era alta @ethersproject/providers (WebSocketProvider) y WalletConnect Resuelto por override a 8.21.3. No usamos WebSocketProvider ni corremos un servidor ws, que es contra lo que van esos DoS
postcss alta dentro de next Aceptada. Es herramienta de build, no de runtime, y el ataque requiere CSS controlado por un atacante en tiempo de compilación. El CSS lo escribimos nosotros. El arreglo exige Next 16, que es un cambio mayor a tres días del deadline
resto (29 moderadas, 14 bajas) árbol de conectores de wallet Aceptadas para el MVP. Son rutas de código que la app no ejecuta: relay de WalletConnect, SDK de MetaMask, Solana

Deuda registrada: ethers v5 está en fin de vida y es el origen de dos de las críticas originales. Migrar el motor a viem o a ethers v6 es trabajo post-aplicación, no de esta semana.

Revisar de nuevo antes de la fase Act (ejecución de transacciones). En cuanto la app firme algo, la evaluación de elliptic y del árbol de wallet cambia por completo: hoy es aceptable justamente porque la app es de solo lectura.

Segunda pasada · 7 sep 2026

Punto de partida: 44 avisos (1 alta, 29 moderadas, 14 bajas). Tres overrides nuevos, sin tocar una sola versión mayor: 0 altas, 0 moderadas, 14 bajas, y las 14 bajas son un solo aviso.

Paquete Severidad Qué se hizo
postcss alta ×2 + moderada ×2 La entrada anterior la dio por aceptada creyendo que exigía Next 16. Estaba mal: Next traía su propia copia 8.4.31 mientras el proyecto ya dependía de 8.5.28, que no es vulnerable. "postcss": "$postcss" hace que Next use la nuestra. Un solo postcss en el árbol y la alta desaparece, sin cambio mayor
stream-json moderada DoS O(profundidad²) con JSON anidado. Llega por jayson@solana/web3.js ← Farcaster Mini App SDK. Override a ^3.6.0
decode-uri-component moderada DoS por porcentajes malformados, vía query-string ← WalletConnect. Override a ^0.5.0
uuid moderada Falta un chequeo de límites en v3/v5/v6 cuando se pasa buf. Llega por MetaMask SDK y jayson. Override a ^11.1.1. Nada nuestro llama a uuid, y los conectores usan v4, que no está afectada; se arregla igual porque el override resuelve limpio
elliptic baja Aceptada, y no tiene arreglo: el aviso cubre todas las versiones publicadas. Entra por @ethersproject/signing-key ← ethers v5. Quitarla significa migrar el motor a ethers v6. Contra qué protege: firmar o verificar con entradas malformadas. Verificado por grep en src/core, src/lib y src/app: no existe new ethers.Wallet, ni signMessage, ni signTransaction, ni getSigner, ni ninguna clave privada. El motor solo lee la cadena

Las 14 bajas restantes son el árbol de @ethersproject/* colgando de ese único aviso de elliptic: un paquete por dependencia, no catorce problemas.

Comprobado después de los overrides: npm run typecheck, npm test (6 pruebas) y npm run build pasan. Como los conectores de wallet solo se ejercitan en el navegador, el botón de conectar se verifica en producción tras el deploy, no en el build.

7. Producto

  • La app es de solo lectura: nunca pide firmas, nunca pide seed phrases, nunca construye transacciones. Decirlo en la UI.
  • Disclaimers: informational only; tokenized stocks only in eligible jurisdictions outside the US.

Security · Informational only, not investment advice.