Saltar al contenido
AI Workforce OS
ES EN
Crear cuenta

Seguridad en AI Workforce OS

Estos son los controles de seguridad que existen hoy, tal como se pueden comprobar en el código y en la configuración de despliegue. Al final hay una tabla con lo que todavía no tenemos. No tenemos certificaciones (ni SOC 2 ni ISO 27001) ni afirmamos cumplir ningún marco.

13 min de lectura

En esta página
  1. Cómo leer esta página
  2. Aislamiento entre organizaciones
  3. Inicio de sesión y sesiones
  4. Identidad para empresas: SSO, MFA y SCIM
  5. Roles y permisos
  6. Bóveda de secretos
  7. Aprobaciones humanas
  8. Topes de gasto y controles de operación
  9. Auditoría verificable
  10. Datos hacia modelos de IA y contenido no confiable
  11. Ejecución de código
  12. Cifrado en tránsito y cabeceras
  13. Respaldos y desarrollo
  14. Lo que todavía no tenemos
Volver arriba

Cómo leer esta página#

Solo describimos lo que existe. Cuando un control depende de la configuración del operador, lo decimos. El diseño parte de que un modelo de lenguaje puede ser engañado por texto no confiable, así que el daño se limita con controles deterministas en el backend (Go) y no con instrucciones en el prompt: no prometemos que el modelo nunca sea influido, sino que solo puede hacer lo que el backend autoriza.

El despliegue público actual corre en un único servidor compartido. Según su configuración en el repositorio, el runtime de agentes está en modo simulación (no envía nada a proveedores de modelos) y la bóveda no tiene clave de cifrado configurada, así que no guarda credenciales reales.

Consejo

Más detalle técnico en la documentación: modelo de seguridad, y autenticación y multitenencia.

Aislamiento entre organizaciones#

Las tablas con datos de una organización usan seguridad a nivel de fila (row-level security) de Postgres con FORCE ROW LEVEL SECURITY. Cada petición corre en una transacción que fija la organización con un ajuste local (app.org_id) y las políticas filtran por él. Si no está definido, no se ve ni se escribe ninguna fila.

El servidor trabaja con un rol (app_user) que no es superusuario, no tiene BYPASSRLS y no es dueño de las tablas. Hay pruebas de integración que comprueban el aislamiento entre dos organizaciones. Es aislamiento lógico dentro de una misma base de datos, no una instancia por cliente.

Inicio de sesión y sesiones#

  • Contraseñas con Argon2id (64 MiB, 3 iteraciones, 2 hilos), que se recalculan en el siguiente inicio de sesión si se crearon con parámetros más débiles.
  • Entre 10 y 128 caracteres y al menos dos clases de caracteres. Se rechazan la propia dirección de correo y una lista corta de contraseñas comunes.
  • Tras 5 intentos fallidos (contraseña o código de verificación) la cuenta se bloquea 15 minutos. Hay además límites de tasa por correo, por IP y por usuario en el inicio de sesión, el registro, la verificación en dos pasos, la recuperación de contraseña y el SSO.
  • Para cuentas inexistentes se calcula un hash equivalente, de modo que el tiempo de respuesta no revela si un correo existe.
  • El token de acceso es un JWT de 15 minutos. El de refresco es opaco, dura 30 días, se guarda solo como hash SHA-256 y viaja en una cookie HttpOnly, Secure y SameSite=Strict. Cada uso lo rota y reutilizar uno ya usado revoca toda la familia.
  • Renovar la sesión y cerrarla exigen la cabecera X-WFAI-CSRF y un origen permitido.
  • La verificación de correo (enlace de un solo uso, 24 horas) es opcional: se activa con EMAIL_VERIFICATION=true y necesita SMTP. La recuperación de contraseña usa un enlace de un solo uso válido 1 hora y cierra todas las sesiones abiertas.

Identidad para empresas: SSO, MFA y SCIM#

  • Inicio de sesión único con cualquier proveedor OpenID Connect (Okta, Entra ID, Google Workspace…): flujo de código con PKCE, state y nonce, y tokens firmados solo con RS256 o ES256. El secreto de cliente se guarda cifrado en la bóveda.
  • Dominios verificados con un registro DNS TXT, que se vuelve a comprobar cada 24 horas. El SSO y la creación de cuentas por dominio solo funcionan con dominios verificados.
  • Verificación en dos pasos con app de autenticación (TOTP) y 8 códigos de recuperación. Una organización puede exigirla a todos sus miembros: quien no la tenga debe activarla antes de recibir sesión.
  • Una organización puede imponer el SSO y desactivar el inicio de sesión con contraseña. Los owners conservan la contraseña como acceso de emergencia.
  • Aprovisionamiento SCIM 2.0 (usuarios y grupos) con un token por organización guardado como hash. Desactivar a una persona quita su membresía y revoca sus sesiones en esa organización al momento.

Nota

La política de MFA o SSO obligatorio se comprueba al iniciar sesión con contraseña y al cambiar de organización; las sesiones que ya estaban abiertas no se cierran al activarla. SAML no está implementado.

Roles y permisos#

Cada membresía tiene uno de cuatro roles: owner, admin, member o viewer, cada uno un superconjunto estricto del anterior. Los permisos tienen la forma recurso:acción y se comprueban en el servidor antes de cada operación. El rol se lee de la base de datos en cada petición, así que degradar o quitar a un miembro surte efecto al instante.

Un admin solo puede asignar los roles member y viewer y no puede cambiar su propio rol, y el último owner no puede eliminarse ni degradarse. Una persona puede pertenecer a varias organizaciones con un rol distinto en cada una. No hay roles personalizados.

Bóveda de secretos#

Los tokens OAuth, las claves de API de las integraciones y las claves de IA propias se cifran con AES-256-GCM en un esquema de sobre: una clave de cifrado de claves (KEK) que vive fuera de la base de datos envuelve una clave de datos por organización, y esta cifra cada secreto con un nonce aleatorio. Los datos autenticados atan cada texto cifrado a su organización y a su uso, de modo que copiado a otra fila u organización no se descifra.

Sin CONNECTIONS_KEK la bóveda falla cerrada: no guarda ni lee secretos reales. La KEK se rota con CONNECTIONS_KEK_PREVIOUS y las claves de datos también pueden rotarse. Revocar una conexión OAuth la suspende, llama al endpoint de revocación del proveedor y destruye el texto cifrado; si el proveedor falla, se reintenta.

Las credenciales de las integraciones nunca viajan al runtime de agentes ni al modelo. La clave de IA propia de una organización sí se envía al runtime para llamar al proveedor, nunca dentro del prompt. Con la misma bóveda se cifran el secreto de cliente SSO, los secretos de firma de webhooks y las URL de avisos de Slack y Teams.

Aprobaciones humanas#

Un agente puede pedir una acción, pero nunca aprobarla. Deciden personas con rol admin u owner. Cada aprobación queda ligada por hash a los argumentos exactos, se consume una sola vez y se vuelve a validar antes de ejecutar. Caduca a los 30 minutos por defecto (APPROVAL_TIMEOUT) y caducar cuenta como rechazo; las aprobaciones de proyectos no caducan por defecto y envían recordatorios cada hora.

Hay cuatro niveles de autonomía por agente (suggest, approve_each, rules, autonomous). Las acciones de integraciones con efectos externos e irreversibles siempre piden aprobación, y un correo aprobado espera al menos 60 segundos antes de salir, durante los que todavía se puede cancelar. Cada organización puede añadir reglas:

  • umbrales de monto y acciones prohibidas;
  • aprobación obligatoria para destinatarios nuevos;
  • un rol mínimo más alto para decidir ciertas acciones;
  • doble aprobación, con dos personas distintas y sin que decida quien pidió la acción;
  • aprobar por sesión (8 horas) o por proyecto (30 días), solo para acciones internas, reversibles y de riesgo bajo o medio.

Nota

También se puede aprobar desde el correo, Slack o Teams con enlaces firmados (HMAC-SHA256), de un solo uso y válidos 24 horas. Abrir el enlace no decide nada: hace falta confirmar. Estos enlaces nunca se ofrecen para acciones de alto riesgo, doble aprobación, rol mínimo o ejecución de código. La opción que impide aprobar tus propias solicitudes viene apagada, salvo con doble aprobación.

Topes de gasto y controles de operación#

Antes de cada llamada al runtime se reserva el costo máximo estimado contra la solicitud, el agente y la organización, y después se concilia con el mayor valor entre el costo informado por el runtime y el recalculado por el backend. Al llegar a un tope, el trabajo se pausa hasta que una persona decida. Cada llamada lleva además su propio tope de costo, y hay límites de profundidad de delegación, reintentos, tiempo por llamada y llamadas en paralelo por organización.

El horario de operación impide empezar trabajo nuevo fuera de las horas abiertas. La detección de anomalías aplica cuatro reglas explicables (pico de gasto, ráfaga de peticiones de herramientas, aprobaciones rechazadas en serie y dominios de destinatario nuevos) y registra cada hallazgo; no bloquea por sí sola y el congelamiento automático viene apagado.

El modo solo lectura, de la organización o de un agente, deniega los efectos externos. El kill switch tiene dos niveles, freeze y lockdown: cualquier admin u owner puede activarlo, solo un owner puede levantarlo y con un motivo escrito. El operador también puede imponerlo con KILL_SWITCH, y entonces ninguna llamada a la API lo levanta. Las acciones retenidas vuelven a la cola de aprobación; una llamada ya enviada al runtime termina.

Auditoría verificable#

La auditoría es una cadena de hash por organización: cada entrada incluye el SHA-256 de la anterior, así que modificar, borrar, reordenar o insertar una entrada rompe la cadena. Para el rol de la aplicación es de solo anexado (UPDATE y DELETE revocados, más disparadores). Antes de encadenarse, cada entrada pasa por un depurador que sustituye el contenido y las claves con aspecto de credencial por [redacted] y trunca los textos largos.

Se auditan, entre otros, las aprobaciones, las ejecuciones y denegaciones de herramientas, las decisiones de política, los cambios de controles, los cambios de identidad (SSO, MFA, recuperación de contraseña, invitaciones) y las exportaciones y borrados. El inicio y cierre de sesión con contraseña todavía no se auditan.

  • Verificación: GET /api/v1/audit/verify recalcula la cadena. Si guardas fuera del sistema la cabeza de la cadena (número y hash), puedes pasarla como ancla para detectar incluso una reescritura completa.
  • Exportación para admins y owners en JSONL, CSV o un ZIP que incluye el resultado de la verificación. La exportación no va firmada.
  • Retención opcional: un owner puede purgar entradas de más de 365 días como mínimo. La cadena sigue siendo verificable desde un punto de control, pero el contenido purgado ya no se puede probar: guarda una exportación si lo necesitas.

Datos hacia modelos de IA y contenido no confiable#

Antes de que el texto llegue al modelo se enmascaran credenciales y números de tarjeta, y el backend enmascara además códigos de un solo uso. El contenido externo (correos, respuestas de API, archivos, páginas web) se normaliza, se neutralizan sus imágenes y enlaces markdown y se envuelve en un bloque delimitado como datos. Una puntuación heurística de inyección marca la tarea y añade motivos de aprobación a las acciones con efectos; es una señal, no la barrera. La barrera son los permisos, las aprobaciones y los límites.

El operador fija un techo de proveedores de IA (ALLOWED_PROVIDERS) y cada organización puede restringirlo más; un proveedor excluido no se llama ni como respaldo. Una organización puede usar su propia clave de IA, y mientras esté activa solo responde esa clave, o apuntar a un endpoint propio compatible con OpenAI.

La navegación web de los agentes viene apagada por organización. Cuando se activa, las peticiones salen del backend con una protección contra SSRF que bloquea direcciones privadas, de loopback y de enlace local en el momento de conectar; los webhooks salientes usan la misma protección y solo admiten HTTPS.

Ejecución de código#

El código que un agente quiere ejecutar es una acción de alto riesgo que una persona debe aprobar. Existe un modo opcional, apagado por defecto, en el que el código que solo toca los archivos del propio agente se ejecuta sin aprobación; activarlo exige org:manage y una confirmación explícita del riesgo, y queda auditado.

El código corre en un contenedor sin red, con sistema de archivos de solo lectura, sin capacidades, sin escalada de privilegios, con usuario sin privilegios y con límites de procesos, memoria y CPU. gVisor es opcional.

Atención

El servicio ejecutor monta el socket de Docker del host, lo que equivale a acceso de administrador al host. Recomendamos usarlo solo en un host de confianza dedicado. No forma parte del despliegue público.

Cifrado en tránsito y cabeceras#

El tráfico público llega por HTTPS: el proxy Caddy termina TLS con certificados automáticos y envía Strict-Transport-Security de un año en el sitio y en la aplicación. En la aplicación añade X-Content-Type-Options: nosniff, X-Frame-Options: DENY y Referrer-Policy. Los archivos subidos por usuarios y los artefactos se sirven con una CSP sandbox para que no puedan ejecutar código en el origen de la aplicación.

Entre contenedores, dentro de una red privada del mismo servidor, la conexión a Postgres no usa TLS (sslmode=disable). Los secretos van cifrados a nivel de aplicación, pero no hemos verificado el cifrado en reposo de los discos del proveedor de alojamiento.

Nota

Todavía no hay una Content-Security-Policy global en la aplicación y no hemos hecho una evaluación externa de la configuración TLS.

Respaldos y desarrollo#

Un cron hace cada noche (03:30, hora del servidor) un volcado de Postgres comprimido. Se guarda en el mismo servidor con permisos restrictivos y se conserva 14 días; el script falla con un mensaje si el archivo es sospechosamente pequeño. No hay copia fuera del servidor ni un objetivo formal de tiempo o punto de recuperación.

La integración continua compila y prueba el backend y el runtime, compila el frontend y ejecuta el detector de carreras en paquetes clave, pruebas end-to-end, un linter de Dockerfiles, govulncheck y npm audit (estos dos últimos no bloquean). Las imágenes se publican etiquetadas por commit.

Lo que todavía no tenemos#

Estado honesto de lo que suelen pedir los equipos de compras. Donde dice que no existe, no existe; donde dice parcial, leer el detalle. No damos fechas porque no hay ninguna comprometida.

CapacidadEstado hoyDetalle
SOC 2 / ISO 27001No existeSin certificaciones ni auditoría externa.
Prueba de penetración externaNo existeSolo pruebas automáticas propias y escáneres de dependencias en CI.
SSO con SAMLNo existeEl SSO es solo OpenID Connect.
Roles personalizadosNo existeCuatro roles fijos.
Comprobación contra contraseñas filtradasNo existeSolo una lista corta de contraseñas comunes.
Autoservicio para exportar o borrar una cuenta individualNo existeLa exportación y el borrado son por organización; para una cuenta, solicitud a info@workforceai.es.
Elección de residencia de datosNo existeUn único servidor; no se puede elegir región.
Claves de cifrado en un KMSNo existeLa KEK se entrega por variable de entorno (CONNECTIONS_KEK).
Exportación de auditoría firmada o anclada fueraParcialLa verificación acepta un ancla que guardes tú; la plataforma no firma ni ancla la cabeza de la cadena.
Respaldos fuera del servidor y pruebas periódicas de restauraciónNo existeLos volcados nocturnos viven en el mismo servidor.
Alta disponibilidadNo existeUna sola instancia.
Escaneo de secretos y análisis estático en CINo existeHay govulncheck, npm audit y linter de Dockerfiles, pero no escaneo de secretos ni CodeQL.
Página pública de estadoNo existeSin historial público de incidentes ni de disponibilidad.
Documentos legales publicados (privacidad, términos, DPA)En revisiónBorradores pendientes de revisión por un abogado.
Aislamiento fuerte del ejecutor de códigoParcialContenedor restringido, pero el ejecutor tiene acceso al socket de Docker del host.

Consejo

Para reportar una vulnerabilidad, consulta la página de divulgación de vulnerabilidades o escribe a info@workforceai.es.