Saltar al contenido principal

Anti-Patrones

Errores comunes al desplegar billeteras de los agentes, diseñar la gobernanza u operar ULedger. Cada entrada indica qué no hacer, por qué es incorrecto y qué hacer en su lugar.


Anti-Patrones de Billeteras y Capabilities​

1. Compartir una Billetera entre Múltiples Agentes​

Qué: Dos o más procesos autónomos firman transactions usando el mismo archivo .ukey y la misma dirección de billetera.

Por qué es incorrecto: La pista de auditoría no puede distinguir entre los procesos. Cada transaction parece provenir del mismo actor. El registro on-chain carece de significado para fines de rendición de cuentas; se pierde el valor central de las billeteras de los agentes. Además, la firma concurrente desde múltiples procesos introduce condiciones de carrera de nonce y de secuenciación.

Qué hacer en su lugar: Se recomienda generar una billetera por cada proceso autónomo. Las billeteras son baratas. Un agente = una billetera = una dirección trazable.


2. Capabilities con Comodín ("action": "*", "resource": "*")​

Qué: Asignar una capability con acción y recurso ambos establecidos en "*", otorgando al agente acceso irrestricto al protocolo.

Por qué es incorrecto: Equivale a darle al agente una credencial de administrador completa. Anula el propósito del sistema de capabilities. Si el agente se ve comprometido o funciona mal, puede realizar cualquier acción en la chain: incluyendo transferir tokens, crear billeteras o invocar contracts no relacionados.

Qué hacer en su lugar: Se recomienda enumerar el conjunto mínimo de acciones y recursos que el agente necesita. Si el agente solo invoca un contract, se debe limitar el alcance a "action": "contract:invoke", "resource": "<specific-contract-address>". Si transfiere tokens, se debe limitar el alcance a la dirección específica del token y establecer un maxAmount.


3. Sin Expiración en las Capabilities del Agente (notAfter: 0)​

Qué: Crear capabilities con notAfter: 0 (sin expiración por altura de bloque).

Por qué es incorrecto: Una billetera de agente con capabilities sin expiración persiste indefinidamente. Si el agente es abandonado, olvidado o comprometido, conserva acceso al protocolo para siempre. Los auditores encontrarán billeteras obsoletas de los agentes con capabilities activas años después del último uso del agente.

Qué hacer en su lugar: Se debe establecer siempre notAfter en un horizonte de bloques razonable. Se recomienda implementar un proceso de renovación de capabilities (ver Integración de Agentes de IA Externos) que renueve antes de la expiración. Se recomienda tratar la renovación de capabilities como una verificación de liveness; si el proceso de renovación falla, las capabilities expiran y el agente queda silenciado automáticamente.


4. Omitir la Configuración de Recuperación en las Entities de Agentes​

Qué: Desplegar entities de agentes sin configurar billeteras de recuperación.

Por qué es incorrecto: Si se pierde la clave privada de la billetera padre (humana), no hay ruta de recuperación. La entity del agente queda huérfana de forma permanente; no puede transferirse, reasignarse de alcance ni deshabilitarse por los canales normales. Un agente huérfano con capabilities vigentes sigue operando sin control humano.

Qué hacer en su lugar: Se debe configurar CONFIGURE_ENTITY_RECOVERY para cada entity que contenga agentes. Se recomienda establecer un umbral de al menos 2 de 3 billeteras de recuperación. Las billeteras de recuperación deben estar en poder de personas distintas al propietario de la billetera: separación geográfica y organizacional.


5. Almacenar Claves Privadas de Agentes en Variables de Entorno o en Control de Versiones​

Qué: Incrustar el contenido de archivos .ukey en variables de entorno, Dockerfiles, archivos .env, o confirmar (commit) archivos de claves en git.

Por qué es incorrecto: Las variables de entorno son visibles para cualquier proceso del contenedor. El control de versiones es para siempre. Una clave de agente filtrada significa que un atacante puede enviar transactions atribuidas al agente; esas transactions son on-chain, permanentes e indistinguibles de las acciones legítimas del agente.

Qué hacer en su lugar: Se debe usar un gestor de secretos (HashiCorp Vault, AWS Secrets Manager, Kubernetes Secrets). Se deben montar los archivos de claves en tiempo de ejecución en una ruta no legible por todos. Nunca se deben imprimir los bytes de la clave en los logs. Se recomienda tratar los archivos .ukey como claves SSH privadas.


6. Verificar la Expiración de la Capability Antes del Envío, No Después​

Qué: La aplicación verifica notAfter > currentBlock antes de enviar una transaction y asume que la aprobación está garantizada.

Por qué es incorrecto: La expiración de la capability se verifica en el momento de ejecución (procesamiento del bloque), no en el momento del envío. Una transaction enviada antes de que la capability expire puede no incluirse en un bloque hasta después de la expiración. Cuando se procesa el bloque, la capability está expirada y la transaction falla; se consume gas y se registra un rechazo on-chain.

Qué hacer en su lugar: Se recomienda incorporar un margen de expiración en los valores notAfter de las capabilities. Se debe diseñar notAfter para que esté bien más allá del último uso esperado. Es recomendable monitorear el estado de las capabilities regularmente y renovar de forma proactiva, no reactiva.


Anti-Patrones de la Jerarquía de Entities​

7. Otorgar Permisos de Entity de Nivel Administrador a las Billeteras de los Agentes​

Qué: Vincular una billetera de agente a su entity con ManageChildren: true, ManageWallets: true, ManageAccessList: true o TransferOwnership: true.

Por qué es incorrecto: Estos permisos permiten al agente reestructurar su propia gobernanza: crear sub-entities, modificar quién puede interactuar con él o transferirse a sí mismo a un nuevo propietario. Un agente comprometido podría usar estos permisos para atrincherarse o cortar la supervisión humana.

Qué hacer en su lugar: Las billeteras de los agentes deben tener ManageMetadata: true (para que puedan actualizar su propia metadata operativa) y nada más, salvo que exista una necesidad específica y justificada.


8. No Aprovechar el Cascade Disable​

Qué: Deshabilitar la billetera de un agente individual sin deshabilitar a su padre cuando se pretende deshabilitar a todos los agentes de un subárbol.

Por qué es incorrecto: Las demás billeteras hijas del mismo padre no se ven afectadas. Si una billetera padre tiene 10 agentes hijos y uno está comprometido, deshabilitar solo la billetera comprometida deja 9 más en ejecución. En un escenario de respuesta a incidentes, la palanca correcta es deshabilitar al padre; esto se propaga mediante BFS a todos los satélites de forma atómica.

Qué hacer en su lugar: Se recomienda comprender la jerarquía de billeteras antes de un incidente. Es necesario saber cuál es la billetera padre de cada subárbol de agentes. En la respuesta a incidentes, se debe deshabilitar al padre para propagar en cascada. Para una remoción dirigida, se debe deshabilitar la billetera hija específica.


9. Usar Entities PERSONAL para Agentes​

Qué: Crear un agente de IA como una entity PERSONAL en lugar de una entity AGENT.

Por qué es incorrecto: Las entities PERSONAL pueden tener hijos (SERVICE, DEVICE, AGENT). Un agente modelado como PERSONAL puede crear sub-entities, otorgándose un poder de gobernanza organizacional que no debería tener. También induce a error a los auditores que interpretan el tipo de entity como indicativo de un sujeto humano.

Qué hacer en su lugar: Se deben modelar los procesos autónomos como entities AGENT (tipo hoja, sin hijos). Se deben modelar los servicios automatizados persistentes como entities SERVICE. Se debe usar PERSONAL únicamente para usuarios humanos.


Anti-Patrones de Diseño de Contracts​

10. Sin Funciones de Emergencia Exclusivas del Propietario​

Qué: Desplegar un contract sin funciones que solo el propietario pueda llamar.

Por qué es incorrecto: Si la lógica del contract tiene un error, o si el sistema entra en un estado inesperado, no existe una palanca administrativa para pausar, reiniciar o corregir el contract sin desplegar una actualización. Una actualización requiere la billetera propietaria; si no hay una pausa de emergencia on-chain, el contract defectuoso sigue ejecutándose durante el proceso de actualización.

Qué hacer en su lugar: Se debe incluir como mínimo una función pause() que solo pueda llamar el propietario del contract. Cuando está en pausa, todas las funciones no propietarias revierten de inmediato. Esto da al propietario una forma de detener el sistema mientras se prepara una actualización.


11. Almacenar Datos Sensibles en el Storage del Contract​

Qué: Escribir PII, credenciales, claves privadas u otros datos sensibles en el storage del contract mediante set_storage().

Por qué es incorrecto: El storage del contract es on-chain. Es visible para todos los operadores de nodes, auditores y cualquiera con acceso a los datos de la chain. La capa de pruebas STARK hace que estos datos sean demostrables de forma permanente y pública, lo opuesto a lo que se desea para datos sensibles.

Qué hacer en su lugar: Se deben almacenar únicamente hashes, compromisos (commitments) o referencias a los datos sensibles. Se recomienda mantener los datos reales off-chain en un almacén privado. Se debe registrar el hash on-chain para que la referencia sea demostrable, pero los datos en sí no queden expuestos.


12. Confundir el Control de Acceso del Contract con las Capabilities del Protocolo​

Qué: Depender únicamente de verificaciones get_caller() internas del contract para restringir el acceso de los agentes, sin establecer capabilities en la billetera.

Por qué es incorrecto: Si el contract se actualiza, se revierte o tiene un error en su control de acceso, la billetera puede enviar transactions que eludan las barreras previstas. Las capabilities a nivel de protocolo son aplicadas por el node; no pueden ser eludidas por la lógica del contract.

Qué hacer en su lugar: Se recomienda usar ambas: las capabilities de la billetera controlan si la billetera puede invocar el contract a nivel de protocolo; la lógica del contract controla qué funciones puede ejecutar quien llama a nivel de aplicación. Esto es defensa en profundidad.


Anti-Patrones Operativos​

13. Una sola Billetera de Recuperación con Umbral 1​

Qué: Configurar recoveryWallets: [one-wallet] con threshold: 1.

Por qué es incorrecto: Una recuperación con una sola aprobación requiere únicamente que una parte ejecute una toma de control. Si esa billetera de recuperación se ve comprometida, o si un ataque de ingeniería social convence a esa única persona de aprobar una recuperación maliciosa, la entity es tomada. No hay una segunda verificación.

Qué hacer en su lugar: Se debe usar un umbral mínimo de 2 de 3 billeteras de recuperación. Las billeteras de recuperación deben estar en poder de personas distintas, organizaciones distintas o ubicaciones físicas distintas. Para entities de alto valor, se recomienda considerar 3 de 5.


14. No Monitorear la Liveness de los Checkpoints​

Qué: Desplegar un clúster Helix y no ejecutar el auditor independiente.

Por qué es incorrecto: La cadena de pruebas STARK vale tanto como el monitoreo que se hace de ella. Si el sidecar de Helix falla, la generación de checkpoints se detiene y la garantía de evidencia de manipulación (tamper-evidence) de la pista de auditoría se degrada silenciosamente; nadie sabe que las pruebas se han detenido hasta que un auditor las necesita.

Qué hacer en su lugar: Se debe ejecutar el sidecar del auditor independiente de forma continua. Se deben configurar alertas por retraso en la altura del checkpoint (ningún checkpoint nuevo dentro de N epochs esperados). Se recomienda tratar la liveness de los checkpoints como una métrica operativa de primer nivel, no como algo secundario.


15. Reconstruir el Estado Histórico a partir de Logs​

Qué: Tratar los logs de aplicación del node como la pista de auditoría e ignorar el historial de transactions on-chain.

Por qué es incorrecto: Los logs de aplicación son mutables (cualquier operador de node puede alterarlos), están aislados (cada node tiene su propio log) y no están vinculados criptográficamente a la salida del consensus. Son diagnósticos operativos, no un registro de auditoría.

Qué hacer en su lugar: El historial de transactions on-chain (verificado por checkpoints STARK) es la pista de auditoría. Se deben construir las herramientas de cumplimiento y auditoría sobre la API de la chain y la verificación de checkpoints, no sobre archivos de log.