# Fijación de versiones para clientes de agentes antes del acceso sensible

Un cliente de agente local no debería obtener acceso a servicios sensibles solo porque su nombre aparece en una lista de herramientas aprobadas. El ejecutable, su runtime, sus extensiones y la forma en que se inicia determinan qué enviará la solicitud. Si cualquiera de esos elementos cambia, tienes un sujeto de seguridad diferente, aunque el título de la ventana y el nombre del comando parezcan conocidos.

La fijación de versiones para clientes de agentes es una práctica de control de versiones, no una solución para las instrucciones maliciosas ni para los permisos excesivos. Te proporciona una propiedad útil: puedes probar un artefacto conocido, registrar lo que probaste y rechazar el acceso sensible a un reemplazo que nadie haya revisado. Parece una medida poco llamativa. Evita muchas fallas que se pueden prevenir.

He visto equipos dedicar mucho esfuerzo a los almacenes de secretos y a los diálogos de aprobación, para después permitir que un actualizador de escritorio reemplace durante la noche el programa que realiza esas solicitudes. Seguían teniendo a una persona en el circuito, pero esa persona aprobaba el comportamiento de un código que nadie había evaluado. Eso no es un límite de seguridad real.

## Fija la identidad del ejecutable, no una etiqueta amigable de versión

Un número de versión exacto es necesario, pero por sí solo no identifica suficientemente a un cliente local. Una etiqueta como `2.4.1` indica lo que el proveedor pretendía publicar. No demuestra qué bytes instalaste, quién los firmó, qué runtime los inició ni si una extensión cambió su comportamiento después del arranque.

Un registro de aprobación útil identifica el artefacto en varias capas:

- El nombre del cliente y la cadena exacta de versión.
- El resumen SHA-256 del instalador o ejecutable descargado.
- La autoridad de firma y el identificador del paquete cuando el sistema operativo los muestra.
- La ruta de instalación, la versión del runtime y el inventario de extensiones.
- La fecha, el revisor y los servicios o permisos de credenciales aprobados para ese registro.

La diferencia entre una *fijación de versión* y una *fijación de artefacto* importa. La primera indica al instalador qué versión debe buscar. La segunda permite rechazar un archivo que difiere del archivo probado. Los equipos suelen mezclar ambos conceptos porque los gestores de paquetes usan la palabra «fijación» para los dos. El resultado puede ser grave: aprueban `1.4.3`, reciben una versión recompilada `1.4.3` desde un espejo comprometido o una caché alterada y no tienen ninguna prueba local que lo detecte.

La identidad de firma añade otra comprobación, pero no sustituye al resumen. Un proveedor legítimo puede firmar una versión defectuosa, y un resumen por sí solo no indica si el archivo procede del proveedor esperado. Cuando el cliente tiene acceso a sistemas de producción, registra ambos datos.

No conviertas esto en burocracia. El registro debe responder a una pregunta durante un incidente: «¿Qué código tenía permiso para enviar esa solicitud?». Si solo dice «el agente de programación», no puede responderla.

## Un árbol de dependencias bloqueado no equivale a un cliente revisado

Los archivos de bloqueo ayudan, pero resuelven un problema más limitado de lo que muchos equipos creen. Un bloqueo de paquetes selecciona versiones de dependencias para una instalación concreta. No inspecciona módulos nativos, no verifica todas las acciones posteriores a la instalación, no impide que un runtime cargue código desde un directorio del usuario ni demuestra que el ejecutable iniciado sea el artefacto que examinó el revisor.

Esto importa especialmente con clientes distribuidos mediante ecosistemas de lenguajes. Un comando que parece un solo programa puede ser en realidad un lanzador pequeño, un runtime, un árbol de paquetes y uno o más complementos descargados. Fijar solo el paquete de nivel superior puede dejar sin controlar la mayor parte de la decisión de confianza.

La especificación OpenSSF SLSA separa de forma útil la procedencia y la integridad. La procedencia describe dónde y cómo se creó un artefacto. Las comprobaciones de integridad establecen que el artefacto no ha cambiado. Ninguna de las dos afirmaciones significa que el programa sea seguro para concederle credenciales. Ambas siguen siendo importantes porque un equipo no puede revisar ni reproducir un objetivo que cambia.

Empieza por identificar qué se ejecuta cuando un desarrollador inicia el agente. En macOS, pregunta al shell en lugar de confiar en un icono del Dock:

```sh
command -v agent-client
file "$(command -v agent-client)"
head -n 1 "$(command -v agent-client)"
```

El comando `head` importa cuando el primer resultado es un script. Una primera línea como `#!/usr/bin/env node` indica que el runtime de Node y el árbol de paquetes forman parte de la ruta de ejecución. Si la primera línea delega en otro lanzador, debes seguir el rastro. No apruebes un alias del shell, un enlace simbólico o un script de arranque como si fuera el cliente.

Para un paquete de aplicación, inspecciona el ejecutable real y los metadatos de firma:

```sh
APP="/Applications/Agent Client.app"
BIN="$APP/Contents/MacOS/Agent Client"
shasum -a 256 "$BIN"
codesign -dv --verbose=4 "$APP" 2>&1 | grep -E 'Identifier=|TeamIdentifier=|Authority='
spctl --assess --type execute --verbose=4 "$APP"
```

La salida del hash tiene la forma `digest  path`. La salida de `codesign` suele incluir un identificador, un identificador de equipo y una o más líneas de autoridad. Guarda esa salida junto al registro de aprobación. `spctl` pide a macOS que evalúe la aplicación según su política de seguridad actual. Es una evidencia útil, pero no significa que la aplicación merezca acceso a una credencial de despliegue.

Una revisión que dice «el archivo de bloqueo está en el repositorio» deja demasiadas preguntas sin respuesta. Conserva el archivo de bloqueo. Después identifica el artefacto que inicia realmente las acciones sensibles.

## La compatibilidad del protocolo no establece la confianza del cliente

Un cliente puede hablar correctamente un protocolo de agentes y seguir sin ser adecuado para el acceso sensible. La compatibilidad del protocolo responde si dos programas pueden intercambiar mensajes. La confianza del cliente responde si ese programa concreto, iniciado en ese estado concreto, puede solicitar una acción respaldada por una credencial.

La documentación de Model Context Protocol describe el intercambio de capacidades declaradas entre un cliente y un servidor durante la inicialización. Esa negociación es útil para la interoperabilidad. No atestigua el binario del cliente, no describe las extensiones cargadas ni promete que el cliente conservará la intención del usuario. No trates un handshake correcto como una comprobación de identidad.

La confusión aparece cuando los equipos permiten que cualquier cliente local compatible con MCP invoque una herramienta sensible porque la herramienta tiene un nombre de servidor conocido. El servidor MCP ve una solicitud a través de un canal de protocolo. Puede saber muy poco sobre el programa que creó la solicitud. Un cliente malicioso o simplemente desconocido puede usar los mismos nombres de métodos que uno probado.

Mantén separados tres registros:

1. La versión del protocolo y las capacidades que probaste.
2. El artefacto del cliente, la identidad de firma, el runtime y las extensiones que aprobaste.
3. Los permisos de servicio que ese cliente puede solicitar.

Un cambio en cualquiera de esos registros merece revisión. Una actualización del protocolo puede modificar los valores predeterminados o el tratamiento de mensajes. Una actualización del cliente puede cambiar las herramientas que invoca o cuándo reintenta. Un cambio de permisos puede hacer destructivo un reintento que antes era inofensivo.

Hay otra diferencia que suele pasarse por alto: fijar un cliente no fija las instrucciones de un agente. El prompt del usuario, los archivos del repositorio, las descripciones de herramientas, el contenido remoto y la salida del modelo pueden influir en un cliente fijado. La fijación limita las sorpresas causadas por el reemplazo del software. No vuelve segura cualquier llamada a una herramienta. Coloca un punto de aprobación humana delante de las acciones cuyas consecuencias sean difíciles de deshacer.

## Prueba la ruta de permisos, no solo la ventana de chat

Un cliente candidato solo supera la revisión después de comportarse correctamente en toda la ruta de acceso que piensas permitir. Pedirle que resuma un repositorio o cree un archivo temporal demuestra que la interfaz funciona. No prueba la inyección de credenciales, el comportamiento de las aprobaciones, los reintentos, las redirecciones, las comprobaciones de hosts SSH ni lo que hace el cliente después de que una herramienta devuelva un error.

Usa un servicio de staging o una credencial de prueba diseñada para ese fin y con permisos limitados. La credencial debe poder demostrar la acción, pero no modificar datos de producción, rotar secretos compartidos ni acceder a cuentas no relacionadas. Si no puedes crear una credencial así, el servicio es demasiado amplio para un cliente autónomo y necesita su propio diseño de acceso.

Prueba deliberadamente estos casos:

- Una solicitud permitida normal con la respuesta esperada.
- Una solicitud que supera el alcance de la credencial y recibe una denegación.
- Un retraso de respuesta o un fallo de conexión que active reintentos.
- Una redirección o un endpoint modificado, si el cliente usa HTTP.
- Una conexión SSH con una clave de host modificada, si el cliente usa SSH.

Los dos últimos casos suelen descubrir comportamientos sorprendentes. Los clientes HTTP pueden seguir redirecciones, y una redirección puede enviar una solicitud a otro host. Que las credenciales sigan la redirección depende del cliente y de la implementación de autenticación. Debes observarlo, no deducirlo de una nota de versión. Los clientes SSH deben tratar una discrepancia de clave de host como una condición de parada hasta que una persona resuelva el cambio. Un agente no debería decidir que una clave desconocida es aceptable solo porque la tarea le pide continuar.

Captura metadatos de las solicitudes sin registrar secretos. En HTTP, un endpoint de prueba puede guardar el método, el host, la ruta, el estado y algunos encabezados no secretos. Confirma qué encabezado de autorización añade la puerta de enlace y después confirma que el cliente nunca recibe ese valor en el resultado de una herramienta, un mensaje de error o una transcripción local.

Para un endpoint destructivo, haz que la operación de staging deje una marca reconocible. Una prueba que solo devuelve HTTP 200 demuestra muy poco. Necesitas evidencias de que ocurrió exactamente una acción prevista, de que no ocurrió la acción equivocada después de un reintento y de que el registro de auditoría identifica la sesión correcta.

## Mantén el candidato aislado del cliente aprobado

Una versión candidata necesita su propia instalación, configuración, cachés y directorios de extensiones. Compartirlos da a la compilación de prueba acceso a un estado que puede diferir de una instalación limpia y hace menos creíble la reversión. Muchos de los fallos más molestos que he investigado procedían de un cliente «nuevo» que cargaba silenciosamente un complemento antiguo o reutilizaba una sesión autenticada del navegador.

En macOS, las cuentas de usuario separadas ofrecen el límite más limpio para una prueba seria. Una cuenta distinta cambia el directorio personal, los directorios de soporte de aplicaciones, las cachés, los elementos de inicio de sesión y muchos almacenes de credenciales. Para una prueba rápida de desarrollo, pueden bastar directorios separados si el cliente documenta cómo seleccionar cada ruta y verificas que las respeta.

No dirijas ambas versiones al mismo archivo de configuración escribible. Los clientes suelen actualizar el formato de configuración al iniciarse. La versión nueva puede escribir campos que la antigua ignore o gestione mal. Eso convierte la reversión en una migración parcial, justo cuando necesitas que sea sencilla.

Trata las extensiones con la misma cautela que el cliente. Registra sus versiones exactas, ubicaciones de origen, hashes cuando sea práctico y si el cliente puede descargar actualizaciones automáticamente. Si el cliente descubre extensiones en un directorio amplio, como una carpeta de plugins del usuario, la prueba del candidato debe comenzar con esa carpeta vacía. Añade solo las extensiones necesarias.

Una prueba limpia también revela un problema menos vistoso: las dependencias no documentadas. Si el candidato solo funciona después de heredar variables de entorno, cookies del navegador, funciones del shell o una caché global de paquetes de la instalación aprobada, documenta esas entradas. Cada dependencia oculta dificulta reproducir el comportamiento posterior.

## Convierte la promoción en un cambio de versión pequeño y repetible

La promoción debe sustituir un registro revisado por otro, no depender de que alguien recuerde en qué botón de descarga hizo clic. Escribe la misma secuencia cada vez. La secuencia proporciona un vocabulario común a los revisores y una ruta de reversión razonable al equipo de guardia.

1. Descarga el candidato desde el canal de versiones habitual del proveedor y registra su origen, versión exacta, hash y firmante.
2. Instálalo en la ubicación de prueba aislada y registra el runtime y las extensiones que carga.
3. Ejecuta las pruebas de la ruta de permisos con credenciales de staging, incluidos los casos denegados y de error.
4. Compara las solicitudes, los avisos y los registros observados con el comportamiento aprobado. Investiga cada solicitud de privilegios nueva.
5. Instala el candidato aprobado en la ubicación privilegiada, conserva el artefacto anterior y cambia el acceso solo después de que las comprobaciones de instalación coincidan con el registro.

El orden final importa. No concedas acceso primero para inspeccionar después el archivo instalado. Si la comprobación de instalación falla, el candidato debe seguir sin poder llamar a servicios sensibles. Rechazar una versión es un resultado normal, no un proceso fallido.

Usa un registro sencillo que pueda guardarse junto a las notas operativas. YAML funciona porque se puede leer durante un incidente:

```yaml
client:
  name: agent-client
  version: "2.4.1"
  executable_sha256: "replace-with-verified-digest"
  signer_team_id: "record-the-observed-team-id"
  install_path: "/Applications/Agent Client.app"
  runtime: "native bundle"
review:
  tested_on: "2025-03-08"
  reviewer: "initials"
  extensions: []
access:
  environments: ["staging", "production-read"]
  forbidden_actions: ["secret-rotation", "deployment-write"]
rollback:
  previous_version: "2.4.0"
```

Los valores anteriores son marcadores de posición, no una plantilla que puedas presentar como evidencia. Complétalos a partir de tu inspección real. En particular, nunca pegues un resumen tomado de un anuncio de versión sin calcular el hash del archivo descargado.

Evita reglas generales como «se permiten todas las versiones de este proveedor». Son populares porque reducen el trabajo de revisión, pero eliminan precisamente el control que ofrece la fijación. La identidad del proveedor puede ser una entrada de la revisión, pero no es una autorización permanente para que código desconocido use tus credenciales de producción.

## Las actualizaciones automáticas y el acceso sensible no deben compartir un límite

Las actualizaciones automáticas tienen sentido para muchas aplicaciones de escritorio. El riesgo cambia cuando la aplicación puede causar acciones externas mediante credenciales almacenadas, claves SSH o cuentas de servicio privilegiadas. En ese caso, un actualizador puede cambiar el programa que solicita autorización entre un día de trabajo y el siguiente.

Hay tres patrones viables. El más seguro es desactivar el reemplazo automático de la instalación privilegiada y promover las versiones manualmente. Otra opción es permitir que los desarrolladores usen copias actualizadas automáticamente sin acceso sensible, mientras una copia fijada se encarga del trabajo privilegiado. La tercera consiste en colocar el límite de acción fuera del cliente, de modo que cada proceso nuevo deba recibir autorización nueva antes de hacer algo importante.

El tercer patrón limita el daño de una actualización inesperada, pero no lo sobrevalores. Una tarjeta de aprobación nueva solo sirve si identifica el proceso de forma significativa. Ver un nombre genérico de cliente y aprobarlo cada mañana acostumbra a las personas a aceptar cualquier cosa. Muestra la autoridad de firma, la ruta del proceso u otra evidencia que el revisor pueda comparar con el registro aprobado.

No permitas silenciosamente un cliente actualizado solo porque procede de la tienda de aplicaciones del sistema operativo o porque macOS considera que está firmado. Esos mecanismos reducen algunos riesgos de la cadena de suministro, pero no indican si el comportamiento nuevo coincide con tus reglas de acceso. Tu organización sigue siendo responsable de decidir si concede sus credenciales.

La fijación de versiones también necesita una fecha de caducidad o revisión. Una fijación permanente se convierte en una fijación sin parches. Establece una periodicidad según el cliente, los servicios que puede tocar y los avisos de seguridad del proveedor. La revisión no necesita dramatismo cuando el comportamiento no ha cambiado, pero sí una decisión deliberada.

## La autorización por acción detecta lo que una fijación no puede

Un cliente fijado todavía puede recibir instrucciones maliciosas mediante un repositorio, una descripción de incidencia, una página web o el resultado de una herramienta. También puede tomar una mala decisión dentro de los permisos concedidos para un trabajo legítimo. La autorización humana debe concentrarse en acciones con efectos importantes, como escribir datos de producción, cambiar infraestructura, transferir datos a un destino nuevo o abrir una sesión SSH con un host sensible.

Las solicitudes de aprobación fallan cuando piden a las personas que aprueben ruido técnico. Una solicitud que aparece para cada lectura inofensiva enseña a hacer clic. Una que aparece después de ocultar su destino tampoco ayuda demasiado. Muestra la acción, el destino, el método y la identidad de la credencial antes de que la puerta de enlace envíe la solicitud. Mantén pocas opciones, para que una persona pueda evaluarlas de verdad.

Una división práctica es permitir lecturas de bajo riesgo mediante la aprobación de una sesión y exigir aprobación explícita para acciones que puedan cambiar el estado o exponer datos. El límite depende del servicio. Una lectura de un repositorio de código puede ser normal; una lectura de una base de datos de clientes puede revelar datos. No clasifiques solo por el verbo HTTP.

Sallyport usa una escala fija de decisiones: el almacén deniega toda acción mientras está bloqueado, un proceso de agente nuevo requiere autorización de sesión de forma predeterminada y determinadas entradas de credenciales pueden exigir aprobación en cada uso. Ese modelo limitado es intencional. Un lenguaje de políticas general ofrecería más opciones, pero también más formas de escribir accidentalmente una excepción que nadie entiende.

Haz que la revocación sea inmediata. Cuando un cliente candidato actúa de forma inesperada, debes poder detener su sesión de acceso actual antes de iniciar una investigación larga. Revocar la credencial del servicio puede ser necesario después, pero es una respuesta brusca que puede interrumpir trabajos no relacionados. La revocación de sesión contiene primero al proceso en ejecución.

## Los registros de auditoría deben relacionar una acción con la ejecución aprobada

Un registro que dice «la llamada API tuvo éxito» no basta para el trabajo de agentes. Debes relacionar la llamada con el proceso local, la decisión de aprobación, la credencial utilizada y el registro del cliente vigente en ese momento. De lo contrario, la investigación de un incidente se reduce a comparar horas entre terminales, historial del navegador y registros del servicio.

Conserva un registro de sesión para cada proceso de agente. Debe incluir cuándo comenzó el proceso, cómo lo autorizó el usuario, su identidad observada y cuándo terminó o fue revocado. Mantén un registro de actividad separado para cada acción. Ese registro debe identificar el destino, la operación, el resultado y la sesión relacionada, sin incluir secretos.

La evidencia de manipulación importa porque un agente puede generar mucho trabajo en poco tiempo y los registros locales son fáciles de editar después de un error. Una cadena de hashes permite detectar eliminaciones o modificaciones cuando alguien verifica la secuencia. No impide que una máquina comprometida realice acciones, pero ofrece a los investigadores una base mejor para detectar un historial reescrito.

Sallyport proyecta sus registros de sesiones y actividad desde un único registro de auditoría cifrado y encadenado mediante hashes, y `sp audit verify` puede comprobar la cadena sin conexión sobre el texto cifrado y sin una clave del almacén. Este diseño resulta útil cuando la persona que revisa el historial no debe recibir acceso a los secretos utilizados en las acciones.

Prueba la ruta de auditoría durante la promoción. Aprueba una sesión de staging, realiza una solicitud permitida y otra denegada, revoca la sesión y comprueba después que los registros identifican los cuatro eventos. Si no pueden mostrar la solicitud denegada o la revocación, falta información que se vuelve especialmente importante cuando el comportamiento falla.

## La fijación falla si el sistema que la rodea sigue siendo mutable

Un cliente cuyo hash se ha comprobado sigue ejecutándose en una máquina que puede cambiar por debajo. El sistema operativo, el runtime, el entorno del shell, la configuración DNS, los proxies, los almacenes de certificados, los binarios auxiliares locales y las extensiones instaladas por desarrolladores afectan a la forma en que las solicitudes salen de la máquina. La fijación es un control de una cadena, no una etiqueta que se añade a una configuración arriesgada.

Empieza por los elementos que pueden alterar acciones privilegiadas sin cambiar el resumen del cliente. Inspecciona las variables de entorno usadas para seleccionar endpoints, el comportamiento del proxy y las ubicaciones de credenciales. Comprueba qué binario SSH o ayudante invoca el cliente. Registra la ubicación prevista de known-hosts y confirma que la prueba rechaza una identidad de servidor desconocida. Revisa si la configuración permite ejecutar comandos locales arbitrarios como herramientas.

No intentes resolver cada incertidumbre construyendo un motor de políticas. La mayoría de los equipos necesitan menos piezas móviles, no un conjunto enorme de reglas que nadie pueda explicar a las dos de la madrugada. Una lista corta de destinos permitidos, credenciales limitadas, aprobaciones explícitas para llamadas sensibles y un artefacto de cliente conocido cubren más casos que una colección compleja de condiciones sin probar.

El hábito operativo es sencillo: cuando cambia un cliente, el acceso se pausa hasta que el artefacto nuevo lo merece. Conserva la copia antigua aprobada, prueba el reemplazo en la ruta de permisos real y registra las evidencias. Es menos emocionante que las demostraciones autónomas, pero así evitas que una actualización en segundo plano se convierta en un cambio de producción no revisado.
