Codex CLI: el cifrado de MultiAgentV2 borra el registro de tareas
DEV Community

Codex CLI: el cifrado de MultiAgentV2 borra el registro de tareas

Resumen

Un mensaje que un agente le envía a otro dentro de Codex CLI ya no queda legible en el historial local. Desde el PR #26210, fusionado el 5 de junio de 2026, el cifrado de MultiAgentV2 vacía el campo de texto plano de cada mensaje entre agentes y solo deja un blob cifrado en su lugar.

El issue #28058, abierto el 13 de junio de 2026 por el usuario ignatremizov en el repositorio openai/codex, documenta la consecuencia práctica: nadie puede leer después, sin descifrar nada, qué tarea le delegó un agente padre a un subagente.

  • TL;DR El issue #28058 del repositorio openai/codex (más de 98.000 estrellas y 14.600 forks) fue abierto el 13 de junio de 2026 por ignatremizov.
  • La causa es el PR #26210, "Encrypt multi-agent v2 message payloads", fusionado el 5 de junio de 2026.
  • Afecta a builds posteriores a la versión 0.137.0 con MultiAgentV2 habilitado.
  • El campo content de InterAgentCommunication queda vacío; el texto real solo vive en encrypted_content.
  • Impacta las llamadas spawn_agent, send_message y followup_task.
  • Es distinto del issue #26753, que reporta errores 400 al validar esquemas cifrados, no un problema de auditoría.
  • La solución propuesta agrega un campo de auditoría sin cifrar, separado del payload que recibe el modelo.
  • Al cierre de esta nota el issue seguía abierto, sin un pull request de fix vinculado.

Introducción

Codex CLI es la herramienta de línea de comandos de OpenAI para trabajar con agentes de código. Su función MultiAgentV2 permite que un agente padre reparta trabajo entre varios subagentes: uno revisa tests, otro refactoriza un módulo, otro investiga un bug.

Para que eso funcione, los agentes se mandan mensajes entre sí usando tres llamadas de herramienta: spawn_agent (crear un subagente con una tarea), send_message (mandarle contexto adicional) y followup_task (asignarle una tarea de seguimiento).

Hasta la versión 0.137.0, esos mensajes se guardaban en texto plano dentro del historial local (rollout), lo que permitía a cualquier desarrollador revisar después qué le había pedido un agente a otro. El PR #26210 cambió eso a propósito, como parte de un endurecimiento de privacidad para el transporte de mensajes entre agentes.

El problema, según documenta el issue #28058, es que ese cambio no distingue entre cifrado para el modelo y legible para el humano que audita. Ese historial no es un detalle cosmético. Equipos que usan Codex CLI en entornos de trabajo colaborativos dependen del rollout para responder preguntas después de que ocurrió el trabajo: qué le pidió un agente a otro, en qué orden, y si el resultado se desvió de la tarea original. Cuando esa fuente deja de ser legible, la auditoría pasa a depender de que alguien haya guardado el prompt original en otro lado, algo que no todos los flujos de trabajo hacen por defecto.

Qué pasó

El reporte es preciso sobre el mecanismo. La estructura InterAgentCommunication, definida en codex-rs/protocol/src/protocol.rs (líneas 735 a 791 del commit fde21ba), tiene dos campos relevantes: content, un String de texto plano, y encrypted_content, un Option<String> opcional.

  • El constructor original, new(), llena content con el texto real y deja encrypted_content en None.
  • El constructor nuevo, new_encrypted(), invierte esa lógica: inicializa content como cadena vacía y guarda el mensaje únicamente en encrypted_content.

Cuando MultiAgentV2 cifra la entrega a un subagente, usa new_encrypted(). El resultado es que el historial local, la reducción de traza y cualquier superficie de depuración del lado del agente padre pierden el texto legible de la tarea o el mensaje.

El autor del issue lo resume con tres preguntas concretas que, después del cambio, ya no se pueden responder inspeccionando el rollout: qué tarea recibió un subagente en un spawn_agent, qué mensaje se le mandó con send_message, y por qué existía un hilo hijo determinado al revisar el historial más tarde.

Contexto e historia del cifrado en MultiAgentV2

MultiAgentV2 es la segunda generación del sistema de subagentes de Codex CLI: la primera versión coordinaba agentes con mensajes en texto plano de punta a punta. El cifrado que introdujo el PR #26210 busca que el contenido de un mensaje entre agentes no quede expuesto en superficies donde no debería, algo razonable si Codex CLI corre en entornos compartidos o si el payload viaja por canales que un tercero podría inspeccionar.

El propio reporte aclara que no está pidiendo revertir esa entrega cifrada. La objeción es más específica: cifrar la entrega al modelo no debería implicar borrar, también, la copia legible que un humano necesita para auditar qué se delegó. Son dos preocupaciones distintas que el PR #26210 resolvió con un solo mecanismo.

Vale la pena distinguir este issue del issue #26753, abierto antes y relacionado con el mismo cambio. Ese reporte describe un error 400 al validar el esquema de spawn_agent cuando el modelo no está configurado para aceptar herramientas cifradas: es un fallo de que la llamada ni siquiera se acepta. El #28058, en cambio, ocurre después de que el mensaje cifrado ya fue aceptado y entregado con éxito: el problema es que, una vez aceptado, no queda rastro legible de qué decía. El campo content queda vacío; solo persiste el payload cifrado.

Detalles técnicos y rendimiento del cifrado en MultiAgentV2

Para entender el alcance conviene ver la diferencia entre un mensaje antes y después del PR #26210.

Antes, un mensaje entre agentes se veía, de forma simplificada, así:

{
  "author": "orchestrator",
  "recipient": "agent-refactor-1",
  "content": "Refactor the auth module and run the test suite",
  "encrypted_content": null,
  "trigger_turn": true
}

Después del cambio, cuando MultiAgentV2 entrega el mensaje cifrado, el mismo tipo de entrada queda así en el historial:

{
  "author": "orchestrator",
  "recipient": "agent-refactor-1",
  "content": "",
  "encrypted_content": "eyJhbGciOiJBMjU2R0NNIiwi...",
  "trigger_turn": true
}

El campo content queda como cadena vacía y todo el texto útil vive dentro de encrypted_content, un blob que solo el destinatario puede descifrar.

La definición real de la estructura, tal como aparece en el código fuente citado en el issue, es esta:

pub struct InterAgentCommunication {
    pub id: Option<String>,
    pub author: AgentPath,
    pub recipient: AgentPath,
    pub other_recipients: Vec<AgentPath>,
    pub content: String,
    pub encrypted_content: Option<String>,
    pub internal_chat_message_metadata_passthrough: Option<InternalChatMessageMetadataPassthrough>,
    pub trigger_turn: bool,
}

impl InterAgentCommunication {
    pub fn new_encrypted(
        author: AgentPath,
        recipient: AgentPath,
        other_recipients: Vec<AgentPath>,
        encrypted_content: String,
        trigger_turn: bool,
    ) -> Self {
        Self {
            id: None,
            author,
            recipient,
            other_recipients,
            content: String::new(),
            encrypted_content: Some(encrypted_content),
            internal_chat_message_metadata_passthrough: None,
            trigger_turn,
        }
    }
}

La tabla siguiente resume el cambio de comportamiento entre las dos rutas de construcción del mensaje:

Estado Campo content Campo encrypted_content Auditable en el rollout local
Antes del PR #26210 (new()) Texto legible del mensaje None
Después del PR #26210 con MultiAgentV2 (new_encrypted()) Cadena vacía Payload cifrado No ⚠️

Ojo: esto no es una vulnerabilidad de cifrado. El problema no es que el mensaje esté mal protegido, sino que, una vez cifrado, ya no queda ninguna copia legible para quien audita el historial localmente.

Cómo empezar a inspeccionar tu propio historial

Si usás Codex CLI con MultiAgentV2 habilitado en una build posterior a la 0.137.0, podés confirmar el comportamiento revisando directamente los archivos de rollout donde se guarda el historial de la sesión.

# macOS / Linux
grep -o '"encrypted_content":"[^"]*"' ~/.codex/sessions/*/rollout.jsonl | head -5
# Windows (PowerShell)
Select-String -Path "$env:USERPROFILE\.codex\sessions\*\rollout.jsonl" -Pattern '"encrypted_content":"'

Si el comando anterior devuelve resultados y, al mismo tiempo, el campo content de esas mismas entradas aparece vacío, tu instalación está mostrando el comportamiento reportado en el issue #28058. Podés comparar contra una sesión sin MultiAgentV2, o previa al 5 de junio de 2026, para ver la diferencia con el content legible.

El propio reporte no ofrece un flag de configuración para desactivar el cifrado y recuperar el campo legible: por ahora, la única forma de ver el texto es no depender del rollout y capturar la tarea del lado del orquestador antes de que se cifre, algo que la mayoría de los flujos de trabajo no hacen por defecto. El PR #26210 se fusionó el 5 de junio de 2026.

Impacto y análisis

El impacto recae sobre todo en dos grupos: equipos que auditan qué hicieron sus agentes en producción, y desarrolladores que depuran por qué un subagente terminó ejecutando una tarea inesperada. En ambos casos, la respuesta históricamente vivía en el rollout local, y con MultiAgentV2 cifrado esa respuesta desaparece salvo que se descifre el payload, algo que el issue no describe como parte del flujo normal de un humano revisando su propio historial.

El patrón no es exclusivo de Codex CLI: cualquier sistema que cifra un payload de punta a punta enfrenta la misma tensión entre confidencialidad y auditabilidad. La diferencia es que, en un pipeline de agentes que toman decisiones y ejecutan cambios de código, la trazabilidad de quién le pidió qué a quién no es un lujo opcional: es la única forma de reconstruir por qué el repositorio terminó en un estado determinado.

El siguiente diagrama resume dónde se pierde la información dentro del flujo de spawn_agent:

Agente padre -> Codex CLI: spawn_agent con la tarea T
Codex CLI -> Codex CLI: cifra el mensaje internamente
Codex CLI -> Subagente: entrega el mensaje cifrado
Nota: el rollout local ya no guarda el texto legible de la tarea T

La propuesta de arreglo que plantea el propio issue es puntual: mantener el campo message cifrado para la entrega al modelo, pero agregar un campo de auditoría separado, sin cifrar, que se persista en los metadatos de rollout, historial y traza. Esa separación, un canal para el modelo y otro para el humano que audita, es en esencia el mismo principio detrás de sistemas de registro que cifran el payload de negocio pero mantienen metadatos de auditoría en claro.

Clave: el issue no pide revertir el cifrado; pide que cifrar la entrega al modelo deje de significar, automáticamente, que nadie pueda auditar la tarea después.

Qué sigue

Al momento de escribir esta nota, el issue #28058 seguía abierto en el tracker de openai/codex, con las etiquetas CLI, bug y subagent, sin un pull request de corrección vinculado todavía. El reporte deja explícita la forma que debería tener el fix: un campo de auditoría no cifrado, independiente del message que ve el modelo, guardado en los metadatos de rollout, historial y traza.

Para equipos que ya corren MultiAgentV2 en flujos donde la auditoría importa (revisión de cumplimiento, depuración de incidentes, control de qué le delegan sus agentes a otros agentes), la recomendación práctica hasta que exista un fix es no depender del rollout cifrado como única fuente de verdad: registrar la tarea del lado del orquestador antes de que MultiAgentV2 la cifre.

Probalo vos: corré grep -o "encrypted_content" ~/.codex/sessions/*/rollout.jsonl sobre tu propia sesión de MultiAgentV2 y confirmá si tu historial local ya perdió el texto legible de las tareas delegadas.

Preguntas frecuentes

¿Qué es MultiAgentV2 en Codex CLI?
Es el sistema de Codex CLI que permite que un agente coordine subagentes usando las llamadas spawn_agent, send_message y followup_task para repartir tareas de código entre varios agentes.

¿Qué cambió exactamente el PR #26210?
Cifró el payload del mensaje que ve el modelo destinatario y, como efecto colateral, dejó vacío el campo content que antes guardaba el texto legible en el historial local.

¿Cómo sé si mi instalación está afectada?
Si corrés una build posterior a la 0.137.0 con MultiAgentV2 habilitado, revisá tus archivos de rollout: si ves encrypted_content lleno y content vacío en los mensajes entre agentes, estás viendo el comportamiento del issue #28058.

¿El cifrado en sí tiene alguna falla de seguridad?
No según lo que documenta el issue. El reclamo no es sobre la fortaleza del cifrado, sino sobre la pérdida de una copia legible para auditoría humana local.

¿En qué se diferencia del issue #26753?
El #26753 describe errores 400 al validar el esquema de herramientas cifradas cuando el modelo no está configurado para aceptarlas: la llamada falla antes de completarse. El #28058 ocurre después, cuando el mensaje ya se entregó con éxito pero no queda registro legible de su contenido.

¿Ya existe una corrección disponible?
No al momento de esta nota. El issue seguía abierto, sin pull request de fix vinculado, aunque el reporte propone una solución concreta: un campo de auditoría sin cifrar, separado del payload cifrado.

Referencias

  • GitHub: issue #28058: reporte original de la regresión de auditoría en MultiAgentV2.
  • GitHub: PR #26210: cambio que introduce el cifrado de mensajes en MultiAgentV2.
  • GitHub: issue #26753: reporte relacionado sobre errores 400 en esquemas cifrados.
  • GitHub: openai/codex: repositorio principal de Codex CLI.

Comments

No comments yet. Start the discussion.