# Escribe registros de auditoría ciegos que los agentes de IA no puedan editar

Un agente de IA puede escribir una explicación impecable de su trabajo después de tomar una mala decisión. Esa explicación no es una prueba. Si el agente puede ver, seleccionar, modificar o evitar los registros que usan los revisores para evaluarlo, el rastro de auditoría se convierte en otra superficie de salida que el agente puede optimizar.

Los registros de auditoría con escritura ciega resuelven un problema concreto pero importante: el proceso que solicita una acción externa no debe controlar el registro de esa acción. El sistema de acciones registra lo que observó, devuelve el resultado que el agente necesita y mantiene el registro para revisión fuera del alcance del agente. Esto no hace honesto a un agente. Hace que un agente deshonesto, confundido o comprometido tenga menos capacidad para seleccionar la historia después de los hechos.

La diferencia importa sobre todo cuando un agente puede desplegar código, llamar a API de pago, cambiar ajustes en la nube, enviar correo o ejecutar comandos SSH. En esos casos, una transcripción del chat es una prueba débil. Una transcripción registra afirmaciones y resultados de herramientas seleccionados. Un registro generado en el punto de aplicación de las reglas puede registrar la solicitud, la autorización, la ejecución y el resultado, incluso cuando el agente preferiría guardar silencio.

## El agente no debe controlar a la vez la acción y las pruebas

Un agente debe tener menos poder sobre las pruebas que sobre la tarea. Darle un archivo llamado `audit.jsonl` y pedirle que añada registros crea un diario de actividad, no un registro de auditoría. Puede olvidar una línea, ocultar un argumento incómodo, escribir que todo salió bien antes de que falle la llamada o crear una segunda copia que el revisor nunca llegue a ver.

El problema aparece incluso con agentes que siguen instrucciones. A menudo el agente decide qué herramientas invocar, qué excepción capturar y qué contexto conservar. Una inyección de instrucciones puede decirle que evite registrar una solicitud. Un error puede enviar una solicitud mediante una biblioteca sin instrumentar. Una dependencia maliciosa puede escribir directamente en la red. Si el mismo proceso controla la acción y el registro, cualquiera de estos fallos puede dejar un rastro ordenado pero incompleto.

Separa estas capacidades de forma explícita:

- El agente solicita una acción y recibe un resultado limitado.
- El ejecutor posee la credencial, envía la solicitud y crea el registro del evento.
- El diario acepta registros mediante una ruta que el agente no puede leer ni modificar.
- Un revisor lee y verifica los registros mediante una interfaz independiente.

Esto es un límite de capacidades, no una promesa sobre el comportamiento. El agente no debe tener acceso de archivo al diario, una API de consulta para sus entradas, credenciales que permitan reescribirlo ni una forma de establecer la marca de tiempo del evento. Si necesita explicar su razonamiento, guarda esa explicación en un artefacto de ejecución separado e indícala como material proporcionado por el agente. No la mezcles con el registro de ejecución.

Los equipos suelen confundir intención y pruebas. La intención es lo que el agente dice que pretendía hacer: «reiniciar el servicio de staging». Las pruebas son lo que observó un componente de ejecución: el agente solicitó un comando específico a una hora concreta, se produjo una decisión de aprobación, el ejecutor se conectó a una referencia de host determinada y el comando terminó con un estado concreto. Ambos elementos son útiles. Responden preguntas distintas y necesitan niveles de confianza diferentes.

## Escritura ciega significa separar capacidades, no retrasar la visualización

La escritura ciega significa que el actor puede provocar la creación de un registro sin acceder al registro almacenado ni a su contexto de revisión futuro. No significa que el agente no reciba información. Una tarea SSH necesita stdout, stderr y un estado de salida. Una tarea HTTP necesita el estado de la respuesta y su cuerpo, o una extracción limitada. Quitar los resultados vuelve inútil al agente sin fortalecer las pruebas.

El límite tiene cuatro partes prácticas. Primero, el agente usa una interfaz de solicitudes, no una credencial. Segundo, el ejecutor crea un registro a partir de sus propias observaciones, en lugar de confiar en un objeto JSON proporcionado por el agente. Tercero, el agente no puede enumerar, obtener, modificar ni eliminar registros. Cuarto, un revisor puede inspeccionar después el registro sin depender de la memoria del agente ni del historial del chat.

Un diseño de lectura retrasada no cumple ese estándar. Supón que un agente escribe eventos en una base de datos y recibe la promesa de que no podrá consultar la tabla hasta que termine la sesión. Sigue conociendo el esquema. Puede adaptar las cadenas de argumentos, elegir qué omitir, provocar fallos de transacciones y usar las diferencias en los tiempos de error para saber si un registro se guardó. Incluso puede conservar credenciales de la base de datos que otro flujo de código podría aprovechar.

La escritura ciega es más sólida cuando la ruta de eventos no devuelve nada que exponga el estado del diario. El ejecutor puede confirmar la acción solicitada, pero no debería devolver identificadores de eventos, números de secuencia, anotaciones de revisores, etiquetas de riesgo ni confirmación de que un registro concreto se volvió permanente. Esos detalles dan al actor material contra el que puede optimizar.

Esto no exige tratar a todos los agentes como hostiles. Reconoce que un agente puede volverse inseguro por muchas razones cotidianas: una instrucción inyectada, un bucle descontrolado, un error de una herramienta, una dependencia obsoleta o un operador que concede una tarea demasiado amplia. El diseño debe resistir algo más que las buenas intenciones.

## Un registro de solo anexado no basta

El almacenamiento de solo anexado detecta algunos tipos de manipulación. No demuestra que el registrador haya visto todas las acciones relevantes ni impide que un agente organice registros engañosos antes de almacenarlos. Los equipos compran con frecuencia almacenamiento inmutable y después dejan credenciales de red directas en el entorno del agente. Así, la brecha central sigue intacta.

Considera dos rutas de despliegue. En la primera, un agente lee un token de API de una variable de entorno y llama directamente al servicio de despliegue. Una biblioteca independiente intenta registrar la solicitud. El agente puede evitar la biblioteca, iniciar otro proceso o usar un cliente HTTP diferente. El registro puede seguir siendo perfectamente de solo anexado mientras el despliegue nunca aparece en él.

En la segunda, el agente puede pedir a un ejecutor que despliegue, pero nunca recibe el token. El ejecutor controla la única ruta que puede adjuntar la credencial. Registra la solicitud antes de transmitirla y actualiza el evento después de recibir la respuesta. El diario solo puede describir las acciones que pasaron por el ejecutor, pero el agente no tiene una ruta autorizada para rodearlo.

RFC 6962, la especificación de Certificate Transparency, describe un árbol de hashes de Merkle que permite demostrar de forma eficiente que una hoja pertenece a un árbol y que un árbol más reciente extiende a otro anterior. Es un patrón de integridad útil. No afirma que un árbol demuestre la captura completa de los eventos del mundo real. Una solicitud de despliegue que nunca entró en el árbol no puede aparecer en una prueba de inclusión.

La misma limitación se aplica a una cadena lineal de hashes. Un registro puede incluir el resumen de su predecesor. Si alguien edita, elimina o reordena registros almacenados, la verificación falla en el punto afectado. Sin embargo, una cadena limpia todavía puede cubrir solo un subconjunto elegido cuidadosamente de las acciones. Coloca el registrador en la ruta de acción antes de celebrar la cadena.

Hay una segunda limitación: los administradores también pueden poner en peligro el rastro. Si un operador puede modificar la base de datos de registros y restablecer la raíz de la cadena sin un testigo externo, el diseño protege principalmente contra cambios casuales. La verificación sin conexión, los puntos de control protegidos y la separación de accesos ofrecen a los revisores una base de confianza mejor. Ninguna de estas medidas convierte un registro en un relato completo de todo lo que ocurrió en una máquina.

## Coloca el registrador en la ruta de ejecución

El registrador debe observar la acción en el punto donde se adjuntan las credenciales y la solicitud externa sale del sistema controlado. Registrar en la capa del marco del agente es demasiado pronto. Registrar solo en un servicio remoto suele ser demasiado tarde y puede omitir el contexto de autorización. La puerta de enlace de ejecución puede ver tanto la solicitud que aceptó como el resultado que recibió.

Para HTTP, esa puerta de enlace debe aceptar una solicitud limitada, seleccionar una credencial almacenada, adjuntarla por sí misma, enviar la solicitud y devolver una parte permitida de la respuesta. El agente no debe enviar encabezados `Authorization` sin restricciones. Debe referirse a una credencial mediante un nombre interno que la puerta de enlace resuelva.

La estructura de una solicitud puede ser lo bastante pequeña como para inspeccionarla y registrarla:

```json
{
  "action": "http.request",
  "credential_ref": "deploy-api",
  "method": "POST",
  "url": "https://deploy.example.internal/releases",
  "headers": {"content-type": "application/json"},
  "body": {"revision": "a18f3c"}
}
```

El ejecutor debe rechazar los encabezados de credenciales proporcionados por quien llama en esta ruta. Así se evita que un agente introduzca otro token en la solicitud mientras deja un `credential_ref` engañoso en el diario. También debe normalizar la URL antes de registrarla, porque una URL sin procesar puede contener información de usuario, trucos con rutas codificadas o un secreto introducido por accidente en un parámetro de consulta.

Para SSH se aplica la misma regla. El agente solicita ejecutar un comando contra una referencia de host. El ejecutor elige la identidad configurada, el comportamiento de verificación del host y el método de conexión. Si el agente puede leer una clave privada e invocar su propio cliente SSH, el sistema de auditoría ya no puede afirmar que cubre sus acciones remotas.

No confundas una puerta de enlace con un proxy de propósito general. Un proxy intenta observar un tráfico amplio. Una puerta de enlace de acciones ofrece un conjunto definido de acciones y posee la autoridad para ejecutarlas. Esa estructura más limitada facilita precisar qué significa el registro: este ejecutor aceptó esta acción con esta autorización y obtuvo este resultado.

## Registra un evento antes de que el exterior pueda responder

Un registro fiable necesita un evento de inicio antes de que el ejecutor envíe la acción y un evento de finalización después de recibir un resultado. Si solo escribes un registro después de un éxito, un tiempo de espera, un bloqueo, la terminación del proceso o una interrupción de red puede hacer que una solicitud importante desaparezca del historial.

Usa un identificador de acción generado por el ejecutor, no por el agente. El registro de inicio debe contener el identificador de sesión, la identidad del proceso que actúa, el tipo de acción, el objetivo normalizado, un resumen seguro de la solicitud, la decisión de autorización y una marca de tiempo generada por el registrador. Marca su estado como `started`.

Después de recibir una respuesta o un fallo, el ejecutor escribe un registro de finalización que hace referencia al mismo identificador de acción. Debe incluir una categoría de resultado como `succeeded`, `rejected`, `timed_out`, `transport_error` o `executor_error`, junto con un resumen de la respuesta y metadatos limitados. Así, un revisor puede distinguir entre «la puerta de enlace lo rechazó» y «el sistema remoto pudo recibirlo, pero no devolvió ninguna respuesta».

La última distinción tiene consecuencias operativas. Imagina que un agente envía `POST /releases` y pierde la conexión después de que el servicio remoto acepte la solicitud. Reintentar a ciegas puede producir dos versiones. Llamar fallo al primer intento porque el cliente no vio una respuesta es incorrecto. El diario debe mostrar que el ejecutor intentó la llamada, que el transporte falló después de comenzar la transmisión y que el estado remoto final sigue siendo desconocido hasta que otra fuente lo confirme.

Un par mínimo de registros podría verse así:

```json
{"seq":481,"action_id":"01HV...","state":"started","session":"run-72","type":"http.request","target":"deploy.example.internal/releases","request_sha256":"...","authorized":true,"previous_sha256":"..."}
{"seq":482,"action_id":"01HV...","state":"completed","result":"transport_error","sent":true,"response_sha256":null,"previous_sha256":"..."}
```

Los campos anteriores ilustran una estructura, no un esquema universal. Mantén el valor de secuencia y el resumen bajo control del registrador. El agente puede proporcionar una etiqueta de tarea, pero márcala como entrada no fiable y limita su longitud. De lo contrario, un agente puede poner secretos, instrucciones para los revisores o prosa engañosa en un campo que parece oficial.

Un bloqueo entre los dos registros deja una acción sin terminar. Consérvala. Un registro incompleto es una prueba que necesita investigación, no basura que deba limpiarse durante la recuperación. Al reiniciar, el sistema puede marcarlo como no resuelto si tiene una forma fiable de hacerlo, pero no debe reescribir el historial para convertirlo en un éxito o un fallo ordenado.

## El esquema debe conservar la intención y el resultado

Un diario que solo guarda «comando ejecutado» responde a muy pocas preguntas durante un incidente. Un diario que almacena cada byte de cada solicitud y respuesta crea un volcado de datos sensibles. El punto medio útil registra suficiente contexto estructurado para identificar la acción y evaluar la autorización, al tiempo que minimiza los secretos y los datos sin control.

Registra la identidad del proceso que llama en términos que el sistema operativo pueda establecer. En macOS, la autoridad de firma de código ofrece un ancla de sesión mejor que un nombre de agente declarado por el propio agente. Los identificadores de proceso se reutilizan. Un nombre mostrado puede mentir. Registra suficiente contexto de sesión para que un revisor pueda saber si un proceso nuevo inició la ejecución y si la aprobación se aplicaba a ese proceso.

Para una acción HTTP, conserva el método, la autoridad y la ruta normalizadas, la referencia de la credencial seleccionada, los encabezados de solicitud permitidos, el resumen del cuerpo de la solicitud, el resultado de la decisión y el estado de la respuesta cuando esté disponible. Para una acción SSH, conserva la referencia del host, la referencia de la cuenta remota si corresponde, el comando o un resumen del comando según su sensibilidad, la referencia de la identidad seleccionada, el resultado de la verificación del host, el estado de salida y el resumen de la salida.

No almacenes credenciales sin proteger. No permitas que un token bearer se cuele en una URL, un encabezado personalizado, los argumentos de un comando o la salida capturada. Ocultar el secreto después de almacenarlo es menos seguro que impedir su recopilación, porque ya habrá entrado en copias de seguridad, réplicas o exportaciones para revisores.

Los resúmenes necesitan cuidado. Un resumen solo demuestra igualdad frente a un material que el revisor ya posee. No explica a una persona qué ocurrió. Para un contenido de despliegue, un resumen almacenado junto con una revisión del repositorio puede funcionar bien. Para un comando destructivo de base de datos, puede ser necesaria una representación normalizada del comando, porque la instrucción exacta es la prueba que necesitan los revisores.

Conserva un campo separado para la decisión de política o aprobación que permitió la acción. Un revisor posterior debe poder responder: ¿el ejecutor permitió esto porque la sesión tenía aprobación, porque el operador aprobó ese uso concreto o porque la bóveda estaba abierta? No reduzcas esas opciones a un `allowed: true` impreciso si el modelo de control humano depende de la diferencia.

## La revisión necesita acceso separado y verificación independiente

Los revisores necesitan algo más que una tabla en la que buscar. Deben determinar si la secuencia de registros es coherente internamente y si el sistema ha conservado sus límites. La persona que investiga una ejecución no debería necesitar que el agente resuma primero su propio comportamiento.

El encadenamiento de hashes ofrece una comprobación concreta. Cada registro incluye un resumen del registro almacenado anterior y el registrador calcula un resumen del registro canónico actual. Un verificador lee la secuencia en orden, vuelve a calcular cada resumen y comprueba que cada referencia al predecesor coincide. Cambiar un objetivo antiguo, eliminar un fallo incómodo o intercambiar dos registros rompe la cadena posterior.

La canonicalización importa. Si un componente calcula el hash del texto JSON mientras otro lo analiza y vuelve a serializarlo, unos espacios o un orden de campos inofensivos pueden provocar un fallo de verificación. Define el orden exacto de los campos, la codificación de caracteres, el tratamiento de valores nulos, la precisión de las marcas de tiempo y el algoritmo de resumen. Después, versiona el formato de los registros. Un verificador debe saber si puede validar una versión concreta, en lugar de adivinarlo.

La verificación debe funcionar lejos del proceso que creó los registros. Si comprobar la integridad requiere el mismo servicio en ejecución, un servicio comprometido puede mentir sobre una cadena rota. Copia el flujo de registros cifrado a una máquina de revisión o a un archivo protegido y ejecuta el verificador sobre esa copia.

Sallyport proyecta sus diarios de Sessions y Activity desde un único registro de auditoría cifrado y encadenado mediante hashes, y `sp audit verify` puede verificar esa cadena sin conexión sobre el texto cifrado y sin una clave de bóveda. Esa separación apunta en la dirección correcta: comprobar las pruebas no debería exigir exponer los secretos que hicieron posible la acción.

La verificación de integridad responde a una pregunta limitada: ¿estos registros forman la secuencia que espera el verificador? No demuestra que todas las respuestas del servidor fueran veraces, que el sistema objetivo no tuviera otra vía de acceso ni que un administrador nunca sustituyera todo el diario por otra copia válida más antigua. Si el retroceso importa en tu entorno, conserva puntos de control protegidos o envía las raíces firmadas a un sistema de retención independiente.

## Patrones de fallo que arruinan el rastro sin llamar la atención

Los diseños más perjudiciales suelen parecer razonables en una demostración. Se rompen ante un reintento, una interrupción o un agente que usa la misma autoridad de una forma inesperada.

El primer fallo es registrar desde el SDK del agente. Es popular porque requiere pocas líneas de código y ofrece una vista de trazas familiar para los desarrolladores. No puede proporcionar un registro de ejecución cuando el agente obtiene credenciales, invoca otro programa o llama a un destino que el SDK no envuelve. Trata las trazas del SDK como datos de depuración.

El segundo es utilizar un único registro de éxito. Un registro escrito solo después de una respuesta correcta borra la ambigüedad. Las operaciones de red tienen resultados ambiguos y los comandos remotos pueden cambiar el estado antes de que se cierre la conexión. Registra el inicio y la finalización por separado y conserva los inicios sin terminar.

El tercero es poner secretos en el contenido de auditoría. A veces los equipos lo justifican diciendo que los revisores necesitan reproducir todo. Rara vez necesitan un token bearer para entender una acción, y los secretos copiados convierten el diario en un objetivo de gran valor. Almacena referencias de credenciales y resúmenes de solicitudes.

El cuarto es dar a los revisores un índice de búsqueda modificable y tratarlo como la fuente de verdad. Los índices de búsqueda pierden campos, caducan documentos y permiten reparaciones. Conserva un flujo de eventos duradero como registro de autoridad. Crea una vista de búsqueda a partir de él y permite que el revisor vuelva al registro original cuando la vista parezca sospechosa.

El quinto es permitir una vía de escape demasiado amplia. Un comando como «ejecutar un shell arbitrario con el entorno de producción» derrota un manejo cuidadoso de las credenciales y el modelado de eventos. A veces un operador necesita un acceso excepcional. Convierte ese acceso en una acción aprobada por separado y con un registro explícito, en lugar de ocultarlo dentro de la ruta normal del agente.

## La aprobación humana y la escritura ciega resuelven riesgos distintos

La aprobación puede detener una acción insegura antes de que ocurra. La escritura ciega conserva las pruebas después de que se produzca una solicitud de acción. Los equipos necesitan ambas cosas cuando un agente opera con credenciales de consecuencias importantes.

La aprobación de una sesión es adecuada cuando una persona confía en un proceso de agente concreto para realizar un trabajo limitado durante un periodo determinado. La aprobación por acción es adecuada para una credencial u operación que merece atención humana cada vez. Ningún tipo de aprobación sustituye al registro de ejecución. Una sesión aprobada todavía puede hacer una llamada accidental y un agente todavía puede describir mal lo que hizo.

La pantalla de aprobación debe identificar el proceso que llama de una forma que una persona pueda evaluar. Una etiqueta declarada por el propio agente, como «asistente de lanzamientos», es débil. Una autoridad de firma de código establecida ofrece al operador una señal más firme sobre qué programa solicitó el poder. La decisión de aprobación debe formar parte del contexto del evento, pero el agente no debe controlar cómo describe el sistema esa identidad.

Mantén separada la puerta de la bóveda de la aprobación. Una bóveda bloqueada debe denegar acciones incluso si existe una aprobación anterior de sesión. Así se crea un interruptor de emergencia sencillo: bloquea la autoridad y el ejecutor deja de usar las credenciales almacenadas. El diario también debe registrar las denegaciones. Una secuencia de solicitudes denegadas puede mostrar que un agente está repitiendo acciones, haciendo sondeos o continuando después de que un operador revocara el acceso.

No conviertas esto en un lenguaje de reglas enorme a menos que realmente lo necesites. Las reglas que nadie puede inspeccionar durante un incidente ofrecen una falsa sensación de seguridad. Un conjunto pequeño de controles claros, una interfaz de acciones limitada y registros que el agente no puede seleccionar suelen ser mejores que una pila de excepciones condicionales.

## Construye el límite alrededor de la acción que puede perjudicarte

Empieza por la acción externa cuyo uso indebido obligaría a realizar una investigación desagradable. Puede ser un comando SSH en producción, una llamada a una API de lanzamientos, un cambio de cuenta o una solicitud de pago. Retira la credencial del entorno del agente, fuerza esa acción a pasar por un ejecutor y prueba las rutas de fallo antes de conectar más herramientas.

Haz esta breve prueba contra el diseño:

1. Solicita una acción y termina el proceso del agente mientras la solicitud está en curso. Confirma que el diario conserva un evento de inicio.
2. Haz que el destino remoto devuelva un error y confirma que el registro de finalización distingue entre rechazo, fallo remoto y fallo de transporte.
3. Intenta la misma acción con un encabezado de credencial o una clave privada proporcionados por quien llama. Confirma que el ejecutor lo rechaza.
4. Da al agente sus interfaces normales e intenta enumerar, modificar o eliminar registros de auditoría. Confirma que no tiene ninguna ruta para hacerlo.
5. Copia el diario almacenado a otro lugar y verifica su cadena sin depender del estado activo del ejecutor.

Estas pruebas encuentran brechas de diseño que una demostración del camino feliz oculta. También obligan a responder con precisión una pregunta incómoda: ¿qué acciones puede seguir realizando el agente fuera de la puerta de enlace registrada? Si la respuesta incluye autoridad de producción, el registro está incompleto por diseño. Dilo claramente, cierra la ruta o limita las afirmaciones que haces sobre el rastro de auditoría.

Un registro de auditoría útil empieza antes de que salga la solicitud, termina con el mejor resultado observado y permanece fuera del control del agente. Construye ese límite antes de que el primer incidente te pida confiar en la versión de los hechos de un agente.
