Seguridad y BYOK
Esta página documenta el modelo de seguridad de principio a fin: la promesa BYOK, el vault local, los sobres de handoff, la autenticación, el endurecimiento de requests y el modelo de confianza del bridge.
¿Nuevo en el lado de IA? Lee primero Conceptos de IA desde cero — los agentes actúan con herramientas sobre tu máquina/servicios, que es exactamente por qué existe todo este consentimiento, cifrado y auditoría.
La promesa BYOK
Sección titulada «La promesa BYOK»“Tus API keys se cifran localmente con AES-GCM y jamás viajan a nuestros servidores.”
Esta es una afirmación contractual (visible en el copy de confianza del producto). La implementación está diseñada para que la afirmación se sostenga por construcción:
- Las claves viven en un vault cifrado en tu navegador (
synthhires-credentials+ espejo), AES-256-GCM. - Para cada request, la clave se envuelve en un sobre de handoff E2EE de un solo uso y con expiración y se envía solo para esa request.
- El servidor desempaqueta, usa y descarta — la clave en texto plano nunca se almacena ni se registra en el servidor.
Los conceptos detrás de la seguridad
Sección titulada «Los conceptos detrás de la seguridad»Como los agentes tienen herramientas que actúan (ver Runtimes) y como la plataforma es BYOK (las llamadas de modelo corren contra tus claves), el modelo de seguridad protege dos cosas distintas:
- Tus claves nunca salen de tu dispositivo. El modelo se relaciona a través de un proxy que solo recibe un sobre de handoff E2EE de corta vida y de un solo uso — tu clave se desempaqueta para una request y se descarta. No es un añadido; es el contrato del que depende toda la plataforma.
- Los agentes actúan bajo consentimiento. Un bucle autónomo llamando a
desktop.shell.execute,mobile.sms.sendo una API externa es genuinamente poderoso, así que cada capacidad está acotada, sujeta a consentimiento, auditada y revocable. La frontera de confianza se dibuja antes de dar la herramienta al modelo, no después.
Ambas ideas — nunca tenemos tus claves en texto plano y las herramientas solo corren con consentimiento explícito — son las que hacen aceptable dar manos a un modelo. Ver Conceptos de IA → Llamadas a funciones/herramientas para entender por qué existen las herramientas.
El vault local (src/lib/credentials.ts + kdf.ts)
Sección titulada «El vault local (src/lib/credentials.ts + kdf.ts)»Derivación de claves
Sección titulada «Derivación de claves»- v1 (legacy):
deriveLegacyV1Key()— derivación local del dispositivo. Sigue siendo legible por compatibilidad. - v2 (endurecida):
deriveVaultKey(salt, VAULT_KDF_SECRET)— combina un salt del dispositivo (getOrCreateVaultSalt()) con un secreto proporcionado por el servidor obtenido del endpoint de vault-secret. Los blobs v2 llevan el prefijov2:.
Resiliencia
Sección titulada «Resiliencia»- Leer antes de escribir: las escrituras v2 solo ocurren cuando el secreto del servidor es alcanzable en esta sesión; las lecturas caen a v1 para que una caída transitoria del secreto nunca “desconecte” BYOK.
- Auto-curación: si un blob falla con la clave activa, el cliente prueba secretos históricos/dev conocidos; al acertar, marca migración y re-cifra con la clave actual en el siguiente guardado.
- Sin borrados silenciosos: los blobs ilegibles se preservan como entradas crudas en lugar de borrarse, para que una lectura corrupta no pueda destruir datos.
Cloud sync (solo con opt-in explícito)
Sección titulada «Cloud sync (solo con opt-in explícito)»El opt-in por proveedor (synthhires:vault:cloud-sync-opt-in) puede reflejar una clave en /api/vault (vault_entries en servidor). Sin ese consentimiento explícito, ninguna clave se sube jamás. migrateToServer solo toca los proveedores con opt-in.
Sobres de handoff
Sección titulada «Sobres de handoff»buildVaultHandoff(provider) (credentials.ts):
- Obtiene el JWK público E2EE del servidor (
/api/handoff-pubkey). - Envuelve la clave en texto plano con la clave pública, sella
issuedAt. - Devuelve
{ provider, ephemeralPublicJwk, encryptedBlob, issuedAt }— el sobre viaja con la request de chat. - El servidor descifra con su clave privada, usa la clave para la llamada al proveedor y la descarta. El sobre es de un solo uso por diseño (clave efímera por sobre).
Autenticación
Sección titulada «Autenticación»- Magic link + códigos OTP (
src/lib/auth.ts): sign-in por email con códigos de verificación (tablaverification_codes: expiración + contador de intentos). - Sesiones (tabla
sessions): tokens de sesión en servidor con expiración;authStorerestaura desdesessionStoragede forma síncrona y reconcilia con/api/auth/meen segundo plano. - La puerta de auth: toda ruta API empieza con
await requireResolvedAuth(cookies, request)(src/lib/auth-server.ts) — la única puerta; una línea mal ahí rompe todas las rutas (está en la lista de no-editar). - Modo invitado/local: los usuarios sin autenticar pueden usar la plataforma localmente; las sesiones se guardan solo en el navegador.
Endurecimiento de requests
Sección titulada «Endurecimiento de requests»- CORS / rate limits / redacción viven en
src/lib/security.ts. - Redacción de logs: todo el logging sensible pasa por el sumidero único
src/lib/log-redaction.ts— claves, tokens y PII nunca llegan a los logs en texto plano. - Sanitización de errores: los errores de stream pasan por
safeErrorLogantes de mostrarse. - Retries acotados: el retry handler aplica máximo 3 intentos con backoff explícito para 429/5xx — sin bucles infinitos.
Modelo de confianza del bridge
Sección titulada «Modelo de confianza del bridge»El bridge de escritorio/móvil (repo Rust externo) se conecta solo saliente:
- Sin puertos de entrada: WebSocket 100% saliente, TLS 1.3.
- Capacidades limitadas:
desktop.shell.execute,desktop.fs.read,mobile.sms.send, … — cada una requiere consentimiento (frames consent_prompt/consent_response) y queda en el log de auditoría (device_action_log). - Filtro de comandos destructivos: el daemon filtra comandos destructivos antes de ejecutarlos.
- Revocación: revocar un dispositivo mata su token (
device_tokens) y cierra la conexión. - Emparejamiento: los códigos de emparejamiento (
pairing_codes) son de un solo uso; el dispositivo prueba posesión del código antes de recibir un token.
Checklist de no-regresión
Sección titulada «Checklist de no-regresión»- Nunca debilitar el copy de confianza BYOK ni el flujo de cifrado.
- Nunca almacenar claves de proveedores en servidor fuera de
vault_entries(cifradas en reposo, solo con opt-in). - Nunca saltar
requireResolvedAuthen una ruta API nueva. - Nunca registrar claves/tokens crudos — pasar por
log-redaction.ts.