Seguridad y aislamiento por workspace
La seguridad de AI Tasker no es una lista de etiquetas: es una respuesta a cuatro preguntas. Quién puede leer qué, con qué credencial, durante cuánto tiempo y con qué rastro. Esta guía describe el modelo tal como está implementado en el backend y contrastado con el contrato público del servicio el 21 de octubre de 2026: el aislamiento por workspace, el cifrado de las credenciales en reposo, la rotación de claves, el papel de la persona en las decisiones de privilegio, el feed de auditoría con doble redacción y las cuotas que cierran el perímetro. Cada código de error, cada cifra y cada nombre de variable de este texto sale del código del servicio, no de una descripción comercial.
Revisado · Publicado
El modelo de aislamiento por workspace
La unidad de aislamiento es el workspace, no la cuenta ni el agente. Una API key pertenece a un workspace: el que se resuelve en apiKey.workspaceId más, si los hay, los workspaces compartidos declarados en apiKey.workspaceIds. Todo lo que esa key alcanza está dentro de ese perímetro. No hay ninguna vía por la que una key pueda enumerar workspaces ajenos, y la comprobación ocurre en la capa de datos: cambiar de vista en el dashboard no amplía el acceso.
La credencial viaja en Authorization: Bearer atkr_… o en x-api-key: atkr_…, y el servidor no la compara con un valor guardado en claro: la busca por su hash sha256. De ahí se siguen dos comportamientos que conviene distinguir, porque son la diferencia entre "no tienes permiso" y "no existes".
- 401
INVALID_API_KEY: la key está revocada (revokedAt) o el servidor no la reconoce. La petición se corta en la autenticación, antes de tocar datos de ninguna colección. - 403
API key workspace unavailable: la key es válida, pero el workspace al que apunta no se resuelve. La petición pasa la autenticación y se frena en la resolución del workspace. - 403
WORKSPACE_ARCHIVED: la key es válida y su workspace existe, pero está archivado por el ciclo de vida (7 días sin actividad). El cuerpo de la respuesta indica la ruta de recuperación:POST /agent/lifecycle/recovery-token, autenticada con la propia API key del agente.
Un 403 WORKSPACE_ARCHIVED no es un problema de credenciales: la key sigue siendo válida y el workspace sigue ahí. Es el estado del workspace el que bloquea el acceso normal, y el cuerpo de la respuesta dice cómo pedir el token de recuperación, que es de un solo uso y dura 900 s. La ventana de recuperación permanece abierta 7 días más desde el archivo.
La jerarquía de datos es la de siempre (workspace → project → task → subtask), pero lo que decide el acceso no es el nodo donde está el dato, sino la credencial que llega: un agente con una key de su workspace escribe en su workspace y en ninguno más, aunque conozca la forma de un identificador ajeno.
Lo que acota de verdad a un agente
Conviene separar lo que una API key declara de lo que el servidor hace. Hoy, lo que acota a un agente son cinco cosas: (1) el workspace al que pertenece su key, (2) las cuotas por workspace, (3) la revocación de la key, (4) el bloqueo del workspace archivado y (5) la autorización humana para ampliar límites o tomar la propiedad del workspace.
Los scopes existen y se guardan en la key: tasks:read, tasks:write, sprints:read, sprints:write y ai:generate. Se ven en el dashboard y en GET /api/apikeys, y por defecto una key creada por una persona lleva tasks:read, tasks:write y ai:generate, mientras que el alta de un agente autónomo lleva tasks:read, tasks:write y sprints:read. Pero no se aplican hoy en ninguna ruta: no hay middleware ni endpoint que los compruebe, y el servidor MCP no filtra las 40 tools por scope, así que tools/list devuelve las 40 con cualquier key válida. Un scope es la intención declarada de la credencial, no un muro.
Si buscas un límite técnico en lugar de una declaración de intenciones, el muro es el workspace más las cuotas. Los permisos y los scopes tienen su propia guía.
Credenciales en reposo
Dos detalles sostienen la parte estática del modelo. El primero: la API key nunca se guarda en claro. Se busca por su hash sha256 (hashApiKey), de modo que ni el almacenamiento de la base de datos ni una lectura indebida de esa base devuelven una credencial utilizable. El segundo: cuando el alta de un agente guarda su credencial, esa credencial se cifra con AES-256-GCM (services/agentCredentialEncryption.js), con un IV aleatorio de 12 bytes y una clave de 32 bytes en hexadecimal tomada de la variable de entorno AGENT_CREDENTIAL_ENCRYPTION_KEY.
- IV aleatorio de 12 bytes: cifrar dos veces el mismo texto produce dos ciphertexts distintos, así que no se pueden comparar credenciales cifradas para deducir si son iguales.
- Clave de 32 bytes en hexadecimal: 64 caracteres que salen de la configuración del servicio, no de la base de datos, y que ningún endpoint devuelve.
- Fallo cerrado: si
AGENT_CREDENTIAL_ENCRYPTION_KEYno está configurada, el servicio no cifra en claro ni continúa sin cifrar: responde con el errorAGENT_CREDENTIAL_ENCRYPTION_NOT_CONFIGURED.
La ausencia de la clave de cifrado es un fallo de configuración y el comportamiento por defecto es detenerse. Un servicio que guardara credenciales sin cifrar porque falta una variable de entorno sería un incidente; por eso el camino por defecto es cerrar el paso.
Dos lecturas autenticadas, con las dos formas de enviar la credencial. La key viaja en la cabecera y el workspace se resuelve solo a partir de ella.
curl https://api.ai-tasker.theboomer.dev/agent/lifecycle/status \
-H "Authorization: Bearer atkr_…"
curl https://api.ai-tasker.theboomer.dev/api/apikeys \
-H "x-api-key: atkr_…" Rotación de claves
Una credencial que no caduca es una credencial que acaba filtrándose. La rotación está diseñada como una operación en dos manos: el agente pide un token de un solo uso y una persona con sesión de Clerk lo completa. El agente no rota su propia credencial, y esa asimetría es el punto: quien puede leer el workspace no puede decidir por su cuenta cuánto tiempo seguirá viva la credencial.
- Solicitud:
POST /agent/key-rotation-token, autenticada con la API key del agente, emite un token de un solo uso con 900 s de validez. Ese token no rota nada todavía: solo abre la puerta a la confirmación. - Vista previa:
POST /api/agent-key-rotations/preview, con sesión de Clerk, muestra los datos del agente y del workspace implicado sin revelar la clave nueva. - Confirmación:
POST /api/agent-key-rotations/confirm, con sesión de Clerk, completa la rotación y entrega la API key nueva, que se muestra una sola vez. - Rotación directa:
POST /api/agent-key-rotations/{apiKeyId}/rotate, con cabeceraIdempotency-Key, ejecuta el giro en un solo paso desde un cliente de persona y es idempotente.
La rotación cambia el hash de la key y su prefijo. La clave antigua deja de validar en el acto: la siguiente petición que la use recibe 401 INVALID_API_KEY, la misma respuesta que devuelve una clave nunca registrada. Es una rotación real, no un alias de la anterior.
La persona en el bucle
La mitad del modelo que no es código es el gobierno. Ampliar los límites de un agente, reclamar la propiedad de un workspace y aprobar una unidad de pago son acciones de persona, no de proceso. Ninguna de ellas se concede por una redirección: el alta autónoma de un agente llega con humanLinkRequired: true, es decir, el registro por sí solo no otorga ningún privilegio, y el vínculo con una persona se confirma en endpoints autenticados con Clerk.
- Subir límites: la cuota por workspace la modifica una persona desde su sesión. Un agente que se topa con el techo no puede ampliárselo ni pedir que se lo amplíen.
- Tomar la propiedad:
POST /api/agent-links/previewyPOST /api/agent-links/claimexigen sesión de Clerk. La vista previa no consume el token: permite revisar identidad, workspace y rol antes de confirmar el reclamo. - Aprobar el pago: la unidad facturable de 2,00 €/mes se aprueba cuando se acepta a una persona, se crea una API key de agente o se añade un workspace del owner. El consumo se contabiliza por operación y los reintentos por error de plataforma no se cobran.
La excepción documentada es x402: una llamada MCP aislada puede liquidarse con créditos sin una cuenta humana previa. Es la vía de pago que no pasa por una confirmación de persona, y tampoco da acceso a un workspace, porque es una llamada suelta y no una credencial.
El feed de auditoría y la doble redacción
Cada petición autenticada deja una fila de uso. El registro ApiKeyUsage guarda apiKeyId, workspaceId, el método, la ruta y el canal — human, cli, llm o agent — de modo que se puede reconstruir quién tocó qué y desde dónde, sin depender de que la propia parte declare lo que hizo.
El feed de actividad aplica dos capas de redacción (services/activityRedaction.js): una por allowlist en el momento de escribir y otra profunda en el momento de leer. La primera decide qué se guarda; la segunda revisa lo guardado antes de devolverlo.
- contraseñas y API keys completas;
- cabeceras
Authorizationy cookies; - JWT y tokens OAuth o de sesión;
- códigos OTP y de reset;
- tokens de alta, vinculación y rotación;
- secretos de webhook;
- claves privadas;
- ciphertext de credenciales;
- firmas y payloads x402.
Lo que sobrevive a la redacción es deliberadamente lo no secreto: el identificador del evento, el apiKeyId, el actor (el userId o el canal), el correlationId, las fechas y las etiquetas de campo. Eso es lo que permite auditar el rastro sin reenviar el material sensible.
La redacción es fail-safe. Si falla (un getter que lanza, un ciclo, una estructura ilegible), el feed devuelve un esqueleto mínimo sin el payload crudo y con redactionFailed=true. El contenido nunca se escribe en logs: cuando la redacción no puede completarse, el sistema entrega menos información, no más.
Las cuotas, la última línea de defensa
Los límites se aplican por workspace. Se cuentan dos cosas distintas y conviene no confundirlas: el techo diario de requests autenticados y el cupo semántico mensual de operaciones.
| Límite | Valor | Qué cuenta |
|---|---|---|
dailyAgentOps | 200 al día | Requests autenticados con API key, por MCP y por HTTP directo |
| Operaciones de agente | 100 al mes | Lecturas y mutaciones de una colección (AGENT_READ, AGENT_MUTATION, 1 unidad cada una) |
| Operaciones de IA alojada | 100 al mes | Planificar sprint, generar tareas y desglosar (bucket hosted_ai) |
dailyHostedAiOps | 10 al día | Llamadas diarias a IA alojada |
| Webhooks | 3 por workspace | Endpoints de webhook registrados |
webhooksPerMinute | 2 por minuto | Entregas de webhook por minuto |
| Retención de actividad | 30 días | Actividad conservada del workspace |
La diferencia entre los dos techos es la clave para leer bien un error de cuota. dailyAgentOps cuenta requests: es el máximo diario de requests autenticados, y la nota oficial del producto es explícita en que no es el cupo semántico mensual. El cupo de 100 operaciones al mes cuenta operaciones semánticas. Y hay operaciones que consumen cero unidades: la entrega de webhook (WEBHOOK_DELIVERED), el reintento por 5xx o timeout (RETRY), la lectura humana en el dashboard (HUMAN_READ) y la llamada MCP pagada vía x402 (X402_MCP_PAID_TOOL). Un agente puede, por tanto, gastar requests y no gastar cuota semántica.
El orden de comprobación también es fijo: primero la cuota de agente (reserveAgentQuota, con su contador requests) y después el techo diario de requests del workspace. Por eso los dos límites se consultan siempre en ese orden, y por eso el catálogo de operaciones que publica la API, con el nombre de cada operación, es la forma fiable de saber qué se está cobrando.
Los límites se aplican por workspace, no por persona ni por API key. En el plan gratuito son 1 workspace, 1 humano y 2 API keys: dos credenciales de agente es el máximo por workspace en ese plan.
Webhooks: firma, sin reintento y secretos
Los webhooks son el canal de salida del sistema hacia terceros y, por eso mismo, el punto donde un dato puede escaparse a un tercero. El cuerpo se firma con HMAC-SHA256 usando el secreto del webhook y se entrega en la cabecera x-ai-tasker-signature: sha256=<firma>, junto a x-ai-tasker-event y x-ai-tasker-event-id, que es el UUID del evento; el campo id del cuerpo repite ese mismo UUID, de modo que el receptor puede correlacionar sin interpretar la cabecera.
- Timeout de 10 s por entrega y
attemptsfijado en 1: no hay reintento automático y el reintento lo decide quien recibe. - Historial:
GET /api/webhooks/:id/deliveriesdevuelve las 100 últimas entregas con su estado (pending,delivered,failed), suresponseCodey suerror. - Eventos:
task.created,task.updated,task.movedytask.archived; el endpoint de prueba disparawebhook.test. - El secreto se redacta: los secretos de webhook están en la lista de lo que el feed de auditoría elimina al escribir y al leer.
Control, qué protege y cómo falla
| Control | Qué protege | Cómo falla |
|---|---|---|
| Resolución por workspace | Que una key no alcance datos de otros workspaces | 403 API key workspace unavailable cuando el workspace no resuelve |
| Revocación de la key | Que una credencial robada deje de servir | 401 INVALID_API_KEY desde el momento de la revocación |
| Ciclo de vida del workspace | Que un workspace inactivo no siga accesible | 403 WORKSPACE_ARCHIVED, con la ruta de recuperación en el cuerpo |
| Cifrado en reposo | Que la credencial guardada no sea legible | Error AGENT_CREDENTIAL_ENCRYPTION_NOT_CONFIGURED si falta la clave |
| Rotación de claves | Que una credencial no viva indefinidamente | La key antigua recibe 401 INVALID_API_KEY tras el giro |
| Redacción del feed | Que el rastro no arrastre secretos | Esqueleto mínimo con redactionFailed=true si la redacción falla |
| Cuotas por workspace | Que un agente consuma sin límite | Se agota el contador de requests o el cupo de operaciones |
| Autorización humana | Que ningún proceso se amplíe a sí mismo | La operación exige sesión de Clerk y no se concede por redirección |
Checklist para endurecer un workspace de agente
- Una API key por agente, sin compartirla entre procesos ni entre entornos.
- Un workspace por agente, para que el aislamiento sea también el límite de cuota.
- Cuotas revisadas y ajustadas al trabajo real del agente, no dejadas en su valor por defecto.
- Rotación programada y hecha con la clave vigente, no solo cuando hay un incidente.
- Clave revocada en cuanto el agente termina su trabajo, y no "por si acaso".
- Workspace archivado tras la inactividad, dejando correr la ventana de recuperación antes de purgar.
- Feed de auditoría revisado: qué pidió cada key, con qué canal y desde qué ruta.
- Secretos de webhook rotados y guardados fuera del código que los usa.
Cómo verificar el modelo en tu propio entorno
Nada de esto hay que darlo por bueno: se comprueba con cuatro lecturas y una rotación de prueba. Enumerar las claves declaradas, leer el estado del ciclo de vida, revisar el feed de actividad y comprobar qué devuelve una llamada con una credencial revocada.
GET /api/apikeyscon una key válida: devuelve las claves declaradas del workspace, con sus scopes y su estado. Es el inventario de lo que hay que rotar.GET /agent/lifecycle/statuscon la API key del agente: devuelve los plazos del ciclo (aviso, archivo, recuperación) y el estado vigente.- Revisa el feed de actividad: cada fila debe traer
apiKeyId,workspaceId, método, ruta y canal, y ningún secreto. Si aparece una cabeceraAuthorizationo un token, la redacción no está haciendo su trabajo. - Rota una clave de prueba y usa la antigua: la respuesta debe ser 401
INVALID_API_KEYy no un error genérico. - Comprueba un workspace archivado: la respuesta debe ser 403
WORKSPACE_ARCHIVEDy el cuerpo debe indicar la ruta de recuperación.
Endurecer el workspace de un agente en cuatro pasos
El recorrido mínimo para dejar un workspace de agente con credencial propia, rotación programada, cuota revisada y rastro auditable. Cada paso es un endpoint real del contrato público del servicio.
- Crea una credencial propia para el agente
Da de alta el agente con
POST /agent/register(cabeceraIdempotency-Key) y quédate con la clave que devuelve, con prefijoatkr_. Esa es la credencial que viajará enAuthorization: Bearer atkr_…, y todo lo demás de esta guía se apoya en ella. - Comprueba el perímetro con dos lecturas
Con
GET /api/apikeysmira las claves declaradas del workspace y conGET /agent/lifecycle/statuslos plazos del ciclo de vida del agente. Si hay más de una credencial para un solo agente, este es el momento de revocarla. - Fija la rotación en el calendario
Pide el token con
POST /agent/key-rotation-token(900 s, un solo uso) y completa el giro conPOST /api/agent-key-rotations/confirmbajo sesión de Clerk, o conPOST /api/agent-key-rotations/{apiKeyId}/rotatey cabeceraIdempotency-Key. Guarda la clave nueva: se muestra una sola vez, y la antigua responde 401INVALID_API_KEY. - Revisa el rastro y las cuotas
Baja el feed de actividad y comprueba que cada fila trae
apiKeyId,workspaceId, método, ruta y canal, sin secretos. Contrasta el volumen con los contadores del workspace: 200 requests autenticados al día (dailyAgentOps), 100 operaciones de agente al mes y 100 de IA alojada al mes.
Preguntas frecuentes
¿Puede un agente ver los datos de otro workspace?
No. Una API key resuelve un solo perímetro: el workspace de apiKey.workspaceId más los workspaces compartidos declarados en apiKey.workspaceIds. Lo que no está en esa lista no es accesible, y si el workspace no resuelve la respuesta es 403 API key workspace unavailable en lugar de una lista vacía. Los scopes de la key son la intención declarada y hoy no se comprueban en ninguna ruta, así que un scope no retira ninguna tool: el límite técnico es el workspace más las cuotas.
¿Qué pasa si la clave de cifrado de credenciales no está configurada?
El servicio falla cerrado con el error AGENT_CREDENTIAL_ENCRYPTION_NOT_CONFIGURED. No hay modo degradado que guarde la credencial del agente sin cifrar: la ausencia de AGENT_CREDENTIAL_ENCRYPTION_KEY corta la operación en lugar de continuar con un almacén en claro.
¿Cómo sé si un agente ha rebasado un límite?
Hay dos contadores distintos y conviene saber cuál se ha agotado. dailyAgentOps es el máximo de requests autenticados al día por workspace (200), y el cupo semántico mensual es de 100 operaciones de agente y 100 de IA alojada. Cada petición autenticada deja además una fila de uso con su método, su ruta y su canal, de modo que el feed muestra el volumen real y a qué corresponde.
Fuentes
- AI Tasker — documentación OpenAPI de la API (102 paths)
https://api.ai-tasker.theboomer.dev/docs - AI Tasker — planes, cuotas y catálogo de operaciones en vivo
https://api.ai-tasker.theboomer.dev/api/plans - AI Tasker — health del servicio y transporte
https://api.ai-tasker.theboomer.dev/health - AI Tasker — manifiesto del servidor MCP
https://ai-tasker.theboomer.dev/server.json - AI Tasker — catálogo legible por máquina
https://ai-tasker.theboomer.dev/llms-full.txt
Cifras verificadas contra la API en vivo y las páginas oficiales de cada producto el 21 de octubre de 2026. Los precios de terceros pueden cambiar: contrasta con la página oficial antes de publicar.
Guías relacionadas
- Todas las guías — Cómo elegir gestor de tareas, MCP y ciclo de vida para agentes de IA.
- Permisos por workspace: cómo se acota un agente — Cómo se acota un agente en AI Tasker: workspace, cuotas, revocación y ciclo de vida. Qué limitan hoy los scopes y qué no.
- Ciclo de vida de un agente de IA — Cómo registrar un agente autónomo, vincularlo a un humano y qué pasa si deja de trabajar: aviso a 48 h, archivo a 7 días y purga a los 14.
- Webhooks para agentes: eventos y callbacks — Los webhooks de AI Tasker: eventos de tarea, firma HMAC, entregas y reintentos. Cómo montar un receptor que no pierde nada y no se duplica.
- Precios — Precios reales: plan gratuito y unidad facturable de 2,00 €/mes.
- Integración MCP —
https://mcp.ai-tasker.theboomer.dev/mcp - /llms.txt — Contrato legible por máquina.
Esta guía existe para ser indexada y citada. No está en el menú a propósito.