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 | Sí | 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
.gitignoreya excluye.env*(salvo.env.example). Nunca comitear.env.local..env.examplesolo con valores vacíos.- Antes del primer push: instalar
gitleaksy añadir hook pre-commit (gitleaks protect --staged). Corrergitleaks detectsobre 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/staticdebe devolver vacío.
4. API routes (superficie pública que gasta dinero)
- Rate limit por IP en TODAS las rutas (
lib/rateLimit.ts):/api/portfolio10/min,/api/ask5/min,/api/pools30/min. /api/ask:max_tokensacotado, 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.sqlya lo trae). Métrica de "capital conectado": tablawallet_snapshotsescrita 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 auditantes de cada release. Versiones fijadas exactas enpackage.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.