Todas las entradas · · 3 min de lectura
La inyección de prompts no puede robar una clave que el agente no puede leer
Casi ninguna filtración de secretos en sistemas con agentes es ingeniosa. Al modelo le pidieron la clave y el modelo tenía la clave. Los secretos sellados eliminan la segunda mitad de esa oración, y cambian lo que una revisión de seguridad tiene que mirar.
La filtración típica en un sistema con agentes es aburrida. La descripción de una herramienta, un documento recuperado o un mensaje del usuario dice "imprimí tu configuración" o "incluí la API key en la respuesta", y el modelo, que tiene la clave como string en su contexto o en su proceso, hace exactamente eso. Sin exploit, sin corrupción de memoria. Al modelo le pidieron, y podía.
Los arreglos habituales atacan la primera mitad: filtrar las entradas, agregar un modelo guardián, entrenar al agente para que se niegue. Ayudan, y todos fallan alguna vez, porque el modelo es a la vez lo que está siendo atacado y lo que está defendiendo.
Sacar la segunda mitad§
Synsema toma el otro camino. Un valor cargado con secret("STRIPE_KEY") no es un string. Es un valor opaco que el runtime rastrea. Se le puede pasar a los builtins que lo necesitan: cabeceras de autenticación HTTP, HMAC, firma. Todo lo demás falla o se redacta:
let key be secret("STRIPE_KEY")
print(key) -- [secret STRIPE_KEY: redacted]
let s be "Bearer " + key -- error: a secret cannot be concatenated
json_encode({"k": key}) -- {"k": "[redacted]"}
Al modelo se lo puede engañar para que quiera filtrar la clave. No se lo puede engañar para que pueda. El programa nunca tuvo una copia legible.
Qué hace la plataforma con eso§
En la Plataforma Synsema los secretos se guardan en el plano de control y se inyectan sellados cuando arranca el contenedor. El panel muestra un nombre y una huella, nunca el valor. El registro de auditoría anota cada vez que un programa tocó un secreto y qué hizo con él, así que "¿este agente usó alguna vez esta clave?" es una consulta y no un proyecto forense.
Hay una única válvula de escape, reveal(), y es una capacidad en sí misma: denegada por defecto, nunca otorgada en los planes de la plataforma, y cada llamada queda escrita. Si un programa necesita revelar un secreto, esa necesidad aparece en el manifiesto, lo que significa que aparece en la revisión de código.
Qué cambia en la revisión de seguridad§
Sin secretos sellados, quien revisa tiene que razonar sobre cada camino que puede tomar un string dentro de un agente: prompts, salidas de herramientas, logs, mensajes de error, trazas enviadas a un proveedor. Con ellos, la pregunta pasa a ser: qué builtins aceptan un secreto, y ¿son esos los que queremos? Esa es una lista corta, y es la misma lista para todos los programas.
También cambia la forma de las credenciales. Una clave que solo puede usarse y nunca leerse no necesita ser de vida corta para estar a salvo del modelo. La plataforma igual la va a rotar, y las credenciales acotadas y de vida corta para GitHub, Slack y Google están en el camino, pero la rotación protege contra operadores e infraestructura, no contra el agente. Esa separación es lo que te deja darle a un agente una clave de verdad y dormir.