Modelo de amenazas y autoatestación OWASP ASVS L1
Las amenazas que Vaulted está diseñado para vencer, las que no, y una atestación control por control frente a una base de referencia del sector.
Versión 1.0 · Publicado el 2026-04-27 · Origen: main · Autor: Maxim Novak
Acerca de este documento
Esto es una autoatestación, no una auditoría de terceros. Existe para que puedas ver exactamente qué afirma proteger Vaulted, qué no, y cómo cada decisión de diseño se corresponde con controles reconocidos. Encargaremos una revisión independiente y publicaremos su informe junto a esta página cuando el presupuesto lo permita. Hasta entonces, puedes verificar tú mismo la afirmación central de conocimiento cero en cinco minutos con las DevTools del navegador.
1. Alcance y supuestos
Este modelo cubre el despliegue de producción de vaulted.fyi incluyendo su frontend web, sus rutas de API y el almacenamiento en Upstash Redis. También cubre el CLI publicado y el servidor MCP en la medida en que interactúan con la misma API.
Fuera del alcance:
- El dispositivo del usuario (navegador, sistema operativo, extensiones, portapapeles, pantalla).
- El canal de comunicación por el que se entrega el enlace compartido (correo, Slack, SMS, etc.).
- El manejo posterior del texto plano por parte del destinatario.
- Vulnerabilidades en Vercel o Upstash por debajo de la superficie de API que consumimos.
2. Activos y fronteras de confianza
Activo principal: el secreto en texto plano. Nunca debe llegar al servidor, persistir fuera de los navegadores del remitente y del destinatario, ni ser recuperable solo a partir del estado del lado del servidor.
Activos secundarios: el texto cifrado, los IV, los contadores de vistas, las marcas de tiempo de expiración y la integridad / disponibilidad del servicio.
Fronteras de confianza (en orden decreciente de confianza):
- Navegador del remitente — de confianza con el texto plano y la clave.
- Navegador del destinatario — de confianza con el texto plano y la clave tras introducir el enlace.
- Red entre el cliente y el servidor — no confiable; mitigado por TLS 1.3 y por la decisión de diseño de que solo el texto cifrado la atraviesa.
- Servidor de Vaulted (nosotros) — de confianza parcial. Tratado como un almacén pasivo de texto cifrado. El modelo de amenazas asume que el propio Vaulted podría verse comprometido sin exponer el texto plano.
- Upstash Redis — mismo nivel de confianza que el servidor. Solo bloques cifrados.
3. Actores de amenaza
Observador pasivo de la red. ISP, actor en la ruta con acceso a metadatos de TLS. Vencido por TLS y por la ausencia de texto plano o clave en el cable.
Atacante activo de la red. Puede intentar un MitM. Vencido por TLS, la precarga de HSTS y la validación de certificados. Un compromiso exitoso de TLS sigue revelando solo texto cifrado.
Servidor comprometido / operador hostil. Nos incluye a nosotros. No puede leer los secretos almacenados porque la clave nunca llega. Puede denegar el servicio o modificar el bundle de JS servido, lo que se aborda en los riesgos residuales más abajo.
Atacante no autenticado con un enlace compartido válido. Por diseño, cualquiera con el enlace completo puede descifrar. Los límites de vistas, la expiración y la frase de contraseña opcional reducen la ventana. Es una propiedad deliberada, no un fallo.
Atacante dirigido contra un remitente o destinatario concreto. Puede explotar el dispositivo, el canal de entrega o el manejo del texto plano por parte del destinatario tras el descifrado. Fuera del control de Vaulted; documentado por honestidad.
4. Controles
- AES-256-GCM del lado del cliente con IV aleatorios de 96 bits de
crypto.getRandomValues. - Claves de 256 bits generadas por secreto mediante
crypto.subtle.generateKey; colocadas en el fragmento de la URL, nunca transmitidas. - Envoltorio opcional con frase de contraseña usando PBKDF2 (recuento de iteraciones alto) y envoltura de clave AES-GCM.
- Aplicación atómica del recuento de vistas mediante el
HINCRBYde Redis con eliminación en la misma transacción al alcanzar el límite. - Expiración automática basada en TTL limitada a 30 días; sin prórroga tras la creación.
- Límite de tasa por IP con ventana deslizante en los endpoints de creación y visualización.
noindexen las páginas de visualización /s/[id] para que las URL de los secretos no puedan filtrarse a través de las búsquedas.- TLS 1.3 con precarga de HSTS, cabeceras de seguridad robustas, sin registro de IP más allá de las ventanas de límite de tasa.
5. Riesgos residuales (no defendidos)
Son decisiones de frontera deliberadas, documentadas para que los usuarios puedan decidir si Vaulted encaja en su modelo de amenazas.
- Compromiso del dispositivo. Un keylogger, un navegador infectado o una extensión hostil pueden leer el texto plano tras el descifrado.
- Filtración del canal de entrega. Si el enlace compartido se reenvía, se archiva o se cita en un hilo de correo respondido, ese canal se convierte en la superficie de ataque.
- Sustitución dirigida del bundle. Una CDN o un edge de Vercel comprometidos podrían servir un JS distinto a un usuario concreto. La Subresource Integrity y las compilaciones reproducibles son mitigaciones parciales y están en la hoja de ruta.
- Comportamiento del destinatario. Una vez descifrado, el destinatario puede copiarlo, capturarlo o reenviarlo.
- Frase de contraseña débil. Si se usa, una frase de contraseña débil es vulnerable a fuerza bruta por cualquiera que tenga la clave envuelta.
- Coacción / tortura. Fuera del alcance de cualquier control técnico.
6. Autoatestación OWASP ASVS L1
La matriz siguiente asigna la implementación de Vaulted a una selección de requisitos de OWASP ASVS nivel 1. Las categorías que no aplican (sesiones, autenticación, carga de archivos) se marcan como N/A con una breve justificación en lugar de omitirse, para que la ausencia de una entrada no se interprete como evasión.
| ID | Categoría | Requisito | Estado | Evidencia |
|---|---|---|---|---|
| V1.1.1 | Arquitectura | SDLC seguro con modelado de amenazas para la aplicación | Pass | Este documento. Revisado en cada cambio material de la arquitectura. |
| V1.4.1 | Arquitectura | Los puntos de aplicación de confianza imponen los controles de acceso | Pass | Los manejadores de rutas de la API validan las entradas y consumen vistas de forma atómica mediante Redis HINCRBY en src/lib/redis-secrets-store.ts. |
| V2.10.x | Autenticación | Autenticación de servicio / usuario | N/A | Vaulted es anónimo. Sin cuentas de usuario, sin autenticación de servicio a servicio. La autorización se basa en el conocimiento del ID del secreto y de la clave del fragmento de la URL. |
| V3.x | Gestión de sesiones | Requisitos de gestión de sesiones | N/A | Sin sesiones, sin cookies para estado autenticado. |
| V5.1.3 | Validación de entradas | Validación de entradas en la capa de servicio de confianza | Pass | Validación manual en tiempo de ejecución en src/app/api/secrets/route.ts. Payload ≤ 1000 caracteres aplicado en el servidor; máximo de vistas y TTL acotados. |
| V5.2.5 | Saneamiento | Codificación de salida según el contexto (HTML, JS, URL) | Pass | React escapa por defecto todos los valores interpolados. Las únicas llamadas a dangerouslySetInnerHTML renderizan literales JSON-LD construidos en el servidor a partir de datos tipados. |
| V6.2.1 | Criptografía almacenada | Usar algoritmos criptográficos aprobados con valores predeterminados seguros | Pass | AES-256-GCM mediante la Web Crypto API. NIST SP 800-38D. Véase src/lib/crypto.ts. |
| V6.2.2 | Criptografía almacenada | Generación de números aleatorios criptográficamente fuerte | Pass | crypto.getRandomValues para los IV y el material de clave. crypto.subtle.generateKey para las claves AES. |
| V6.2.5 | Criptografía almacenada | Sin primitivas criptográficas inseguras u obsoletas | Pass | Sin MD5, SHA-1, DES, RC4, ECB ni CBC sin MAC en ninguna parte de la ruta criptográfica. |
| V6.3.1 | Criptografía almacenada | Claves protegidas frente al acceso no autorizado | Pass | La clave de cifrado nunca llega al servidor. Vive solo en el fragmento de la URL, procesada en el cliente según el RFC 3986. Una frase de contraseña opcional envuelve la clave con PBKDF2 antes de compartirla. |
| V7.1.1 | Manejo de errores y registro | Sin información sensible en los registros | Pass | El servidor solo registra la forma de la solicitud y las decisiones del límite de tasa. Sin texto cifrado, sin IDs de secreto de forma que puedan correlacionarse, sin IP persistidas más allá de la ventana del límite de tasa. |
| V7.4.1 | Manejo de errores y registro | Mensajes de error genéricos | Pass | Las rutas de la API devuelven códigos de estado HTTP genéricos y cadenas de error breves. No se filtran trazas de pila ni estado interno. |
| V8.1.1 | Protección de datos | Datos sensibles identificados y protegidos | Pass | El servidor nunca recibe el texto plano. El texto cifrado se almacena cifrado en reposo en Upstash Redis, con eliminación basada en TTL y aplicación atómica del límite de vistas. |
| V8.3.1 | Protección de datos | Datos sensibles no expuestos en URLs ni referrers | Pass | La clave de cifrado vive en el fragmento de la URL; los fragmentos nunca se envían al servidor y los navegadores los eliminan de document.referrer según el RFC 3986 §3.5. |
| V9.1.1 | Comunicaciones | TLS para toda la conectividad del cliente | Pass | TLS 1.3 aplicado en el edge de Vercel. HSTS precargado. Las solicitudes HTTP se redirigen a HTTPS. |
| V10.3.2 | Código malicioso | Código de la aplicación revisado en busca de código malicioso | Pass | Base de código de un único mantenedor. Todos los commits son del propietario del proyecto; commits firmados cuando es posible. Las actualizaciones de dependencias mediante Dependabot se revisan antes de fusionarlas. |
| V11.1.1 | Lógica de negocio | Flujos de lógica protegidos frente al abuso | Pass | Límite de tasa por IP mediante Upstash Ratelimit (10 creaciones/min, 30 vistas/min). Los contadores de vistas se decrementan de forma atómica. |
| V12.x | Archivos y recursos | Requisitos de carga y procesamiento de archivos | N/A | Vaulted no acepta cargas de archivos. |
| V13.2.1 | API y servicios web | Los endpoints RESTful validan el esquema de la solicitud | Pass | Todos los manejadores POST/GET validan los parámetros de ruta, la forma del cuerpo y el content-type antes de procesar. |
| V14.4.3 | Configuración | Cabeceras de seguridad estándar configuradas | Pass | HSTS, X-Content-Type-Options, Referrer-Policy y Permissions-Policy establecidas mediante la configuración de Next.js. Content-Security-Policy aplicada por solicitud en src/proxy.ts con un script-src strict-dynamic basado en nonce; las rutas de la API reciben una política restrictiva default-src none. |
La numeración sigue la estructura de ASVS 4.0. La lista es seleccionada, no exhaustiva: el objetivo es ser honestos sobre los controles que aplican de forma significativa a un almacén de texto cifrado sin estado y sin cuentas.
7. Proceso de cambios
Cualquier cambio que afecte a un elemento de este documento — nuevo endpoint, cambio criptográfico, refactorización que afecte a dependencias, cambio de infraestructura — debe desencadenar una revisión de esta página en el mismo PR. La versión y la fecha de publicación de arriba se incrementarán cuando se actualice el documento; la versión anterior permanece accesible en el historial público de git.
Firma
Este modelo de amenazas se publica de buena fe por parte del mantenedor de Vaulted. Se invitan explícitamente errores, omisiones y desacuerdos con las atestaciones anteriores: por favor, comunícalos a [email protected] o a través del programa de divulgación responsable.
Maxim Novak — mantenedor, vaulted.fyi · 2026-04-27