Lección 5: Los límites y la seguridad de la memoria
Objetivos de aprendizaje:
- Explicar por qué la «memoria» como funcionalidad es también una nueva superficie de ataque
- Recontar cómo, en el caso MemoryTrap, una operación rutinaria se convirtió en un ataque entre sesiones
- Decidir qué contenido nunca debería escribirse en la memoria persistente, y qué información se vuelve peligrosa una vez que queda obsoleta
- Nombrar al menos dos medidas concretas que defiendan específicamente contra el envenenamiento de memoria
Requisitos: terminar la Lección 4 y entender el estado estructurado y los puntos de control | Anterior: Lección 4 << | Siguiente: Lección 6 >>
Una operación rutinaria de «clonar el repo, aprobar la instalación»
Le pides a un agente conectado a memoria persistente que ayude con un proyecto nuevo: clonar el repo, comprobar que las dependencias se instalan sin problemas. El agente lee package.json, encuentra una dependencia que hay que instalar y pregunta si la aprueba. Le dices «adelante», el agente ejecuta la instalación, la tarea se cierra y te pones con otra cosa.
Nada en esa secuencia parece sospechoso. Nadie le dijo al agente que «ignorara las instrucciones anteriores», nadie le pasó una URL que no reconozcas. Simplemente hizo lo que se suponía que tenía que hacer: clonar, comprobar, instalar, listo.
Una vulnerabilidad real divulgada por el equipo de investigación de Cisco y publicada en el blog del OWASP Gen AI Security Project — los investigadores la llamaron MemoryTrap — describe exactamente este tipo de camino. Como lo expone el artículo: "In the vulnerability we called MemoryTrap, we found that a routine developer workflow could turn into persistent prompt injection. The path was surprisingly ordinary: clone a repository, let the agent help, approve a dependency installation, and move on."1 (En la vulnerabilidad que llamamos MemoryTrap, descubrimos que un flujo de trabajo rutinario de desarrollo podía convertirse en una inyección de prompt persistente. El camino era sorprendentemente ordinario: clonar un repositorio, dejar que el agente ayude, aprobar la instalación de una dependencia y seguir adelante.) En apariencia no pasó nada, pero dentro de esa instalación aprobada, contenido malicioso oculto en el paquete de la dependencia o en algún lugar del repo aprovechó su oportunidad para hacer algo más problemático. No se quedó confinado a este proyecto: "Instead, it reached persistent memory, the global hooks configuration, and even influenced a highly trusted instruction layer through the system prompt."1 (En su lugar, llegó a la memoria persistente, a la configuración global de hooks e incluso influyó en una capa de instrucciones de alta confianza a través del system prompt.) Dicho de otro modo, "a one-time action could shape the model's future behavior across sessions, projects, and even reboots."1 (una acción puntual podía moldear el comportamiento futuro del modelo entre sesiones, proyectos e incluso reinicios.)
Por qué la memoria es una nueva superficie de ataque: ASI06
Este caso cae bajo ASI06 — Memory & Context Poisoning — en la taxonomía de riesgos de OWASP para la seguridad de agentes. El razonamiento tras esa categoría se enuncia con claridad en el blog oficial: "Agentic systems do not just respond in the moment. They retain context, reuse memory, and rely on persistent state to guide future reasoning and actions. That is what makes them useful. It is also what makes them vulnerable."1 (Los sistemas agénticos no se limitan a responder en el momento. Retienen contexto, reutilizan memoria y se apoyan en estado persistente para guiar el razonamiento y las acciones futuras. Eso es lo que los hace útiles. Es también lo que los hace vulnerables.)
Descompón esa frase y en realidad es la lista de capacidades que las primeras cuatro lecciones fueron construyendo una a una: la gestión del historial de la Lección 2 permite que una conversación continúe, la memoria externa de la Lección 3 permite que la información persista entre sesiones, el estado estructurado y los puntos de control de la Lección 4 permiten que una tarea se reanude desde donde se detuvo. Cada una de esas capacidades hace al agente más útil, y cada una significa también esto: una vez que el contenido malicioso se cuela en estos lugares de confianza, leídos y ejecutados automáticamente, su impacto ya no se limita a una respuesta equivocada esta vez. Se lee una y otra vez, surte efecto una y otra vez, hasta que alguien lo nota y lo limpia.
Esa es la raíz de por qué la «aprobación de la instalación de la dependencia» en MemoryTrap era peligrosa. Lo que se aprobó no fue una operación aislada y puntual, sino un camino que podía escribir en la memoria persistente y en la configuración de hooks — el tipo de almacenamiento en el que se confía y que se carga una y otra vez.
Qué guardar y qué no guardar
La pregunta central que plantea MemoryTrap es esta: qué contenido nunca debería permitirse que entre en la memoria persistente o en la configuración de hooks — el tipo de almacenamiento que se carga automática y repetidamente.
El curso anterior «Llamada a herramientas en agentes: conseguir que los agentes hagan cosas de verdad», en su Lección 5 «Permisos y seguridad: los límites de lo que un agente puede hacer», expuso una regla básica: el contenido que devuelve una herramienta es siempre datos, nunca instrucciones. En la capa de memoria esa regla hay que llevarla un paso más allá: el contenido que se lee no debe promoverse automáticamente a memoria sin revisión. Los archivos del repo, los logs de instalación de dependencias y el contenido web que un agente lee mientras hace una tarea son solo datos de entrada para esta única tarea. Copiar una de esas líneas literalmente en CLAUDE.md o en Auto memory promueve «texto no confiable leído durante esta tarea» a «contenido cargado como regla de confianza en todas las sesiones futuras». Eso es exactamente lo que pasó dentro de la «aprobación de la instalación de la dependencia» de MemoryTrap.
Para la pregunta concreta de «qué guardar», unos cuantos límites que puedes aplicar directamente:
- Las credenciales no deberían guardarse: claves, contraseñas, tokens de acceso — una vez escritos en un archivo de memoria que se carga automáticamente, quedan reexpuestos en la ventana en cada sesión, ampliando la superficie de fuga sin ningún beneficio a cambio.
- El texto crudo no confiable no debería guardarse tal cual: contenidos de archivos, texto web, salida de dependencias leídos durante una tarea. Si hace falta recordar algo de eso, debería ser una conclusión que una persona haya confirmado y reescrito como una afirmación clara (por ejemplo, «esta dependencia necesita Node 18 o superior»), no todo el bloque de texto leído trasladado literalmente a un archivo de memoria.
- Las reglas y los hechos estables y confirmados sí vale la pena guardarlos: por ejemplo las convenciones de estilo de código del proyecto de la Lección 3, o una causa raíz confirmada tras una investigación real. La fuente de confianza de este contenido es clara, y escribirlo en memoria aporta valor genuino.
La prueba es la misma línea de razonamiento que la comprobación de límites de ruta de la Lección 3: no «se puede escribir esto técnicamente», sino «el contenido que estoy a punto de escribir proviene de una fuente de confianza, y merece que cada sesión futura confíe en él automáticamente».
El peligro de la memoria obsoleta: una regla que fue correcta y ahora es errónea
Más allá de «qué no guardar» hay una segunda clase de riesgo fácil de pasar por alto: el contenido que ya está en memoria puede, con el tiempo, convertirse en memoria obsoleta — antes correcta, ya no aplicable, pero ejecutada aún como una regla vigente porque sigue en la memoria persistente.
Imagina una nota de Auto memory escrita hace unos meses: «Desplegar este proyecto es sencillo — basta con hacer push a la rama main y sale a producción automáticamente, sin revisión adicional». Puede que fuera verdad en su momento. Pero pasan los meses, el proyecto introduce revisión de código obligatoria y nadie actualiza la nota. Si el agente lee esa memoria obsoleta y aún la trata como guía operativa vigente y de confianza — haciendo push directo a main, saltándose la revisión —, el resultado es la misma clase de problema que el envenenamiento de memoria: contenido en el que no se debería confiar se trata como hecho autoritativo simplemente porque ocupa la ranura de «memoria».
La diferencia entre la memoria obsoleta y el envenenamiento de memoria es el origen: el envenenamiento es contenido malicioso escrito activamente, mientras que la memoria obsoleta es contenido que era bienintencionado y correcto pero se volvió poco fiable porque nadie lo actualizó ni lo limpió a tiempo. Pero ambos comparten la misma postura defensiva — no se debería confiar sin condiciones en el contenido en memoria, y especialmente cuando toca permisos o procesos que cambian con el tiempo, hay que reverificarlo periódicamente para confirmar que sigue siendo válido.
La corrección de Anthropic, y otras superficies de confianza más allá de la memoria
Tras divulgarse MemoryTrap, la respuesta de Anthropic merece registrarse: como dice el artículo, "To Anthropic's credit, after we at Cisco disclosed the issue, Claude Code v2.1.50 removed user memories from the system prompt, reducing the specific high-trust override path we identified. That was the right fix for the path we found."1 (Hay que reconocerle a Anthropic que, después de que en Cisco divulgáramos el problema, Claude Code v2.1.50 eliminó las memorias de usuario del system prompt, reduciendo el camino específico de anulación de alta confianza que identificamos. Esa fue la corrección adecuada para el camino que encontramos.) Esa valoración lleva su propio recordatorio: lo que se corrigió fue «el camino que encontramos», no «toda la clase de riesgo de envenenamiento de memoria». La memoria, los hooks, los archivos de configuración — cualquier lugar que el sistema cargue repetidamente como fuente de confianza podría en principio ser el punto de aterrizaje del próximo ataque.
Un principio más general del blog de OWASP: "Once malicious content reaches trusted surfaces like memory, hooks, or configuration, the attacker is no longer just influencing one response. They are influencing future reasoning."1 (Una vez que el contenido malicioso llega a superficies de confianza como la memoria, los hooks o la configuración, el atacante ya no está influyendo solo en una respuesta. Está influyendo en el razonamiento futuro.) Esa frase cierra todo lo que ha discutido esta lección: los archivos de memoria de la Lección 3 y los puntos de control de la Lección 4 son, en el fondo, almacenamiento en el que «las sesiones futuras confiarán y que cargarán». Cuanto más útiles son, más merecen una puerta de escritura seriamente vigilada.
Resumen
- La memoria es útil porque deja que el contenido persista entre sesiones y se cargue con confianza repetidamente — que es exactamente lo que la convierte también en una superficie de ataque. La categoría de riesgo ASI06 describe esta clase de envenenamiento de memoria y de contexto.
- El caso MemoryTrap muestra que un flujo de trabajo rutinario de apariencia normal (clonar un repo, aprobar la instalación de una dependencia) puede dejar que el contenido malicioso llegue a la memoria persistente y a la configuración global de hooks, e incluso influya en una capa de instrucciones de alta confianza a través del system prompt. Una sola acción puntual basta para moldear el comportamiento futuro del modelo entre sesiones, proyectos y reinicios.
- Qué guardar tiene límites claros: las credenciales no deberían guardarse, el texto crudo no confiable no debería guardarse directamente, y solo las reglas y los hechos estables y confirmados vale la pena guardarlos.
- La memoria obsoleta también es peligrosa: contenido que antes era correcto pero ya no aplica, si se ejecuta aún como una regla vigente, es la misma clase de problema que el envenenamiento de memoria.
- Anthropic corrigió el camino divulgado (v2.1.50 eliminó las memorias de usuario del system prompt), pero el principio más general es este: una vez que el contenido malicioso llega a cualquier superficie de confianza (memoria, hooks, configuración), el atacante ya no está influyendo en una respuesta sino en el razonamiento futuro.
Lección 6 >>