Cómo los archivos públicos llms.txt permiten a los investigadores ejecutar código dentro de grandes empresas
Los investigadores registraron nombres de paquetes no reclamados que los archivos oficiales llms.txt indicaban a los agentes de IA que instalaran, y el código se ejecutó dentro de grandes empresas en cuestión de minutos. Por qué ahora los datos son código.
Fuentes: Data Became Code: We Ran Code Inside Fortune 500s Using Files They Published for AI Agents
Cuando un archivo publicado se convierte en una orden
Un equipo de investigación en seguridad informó que una máquina dentro de una empresa de la lista Fortune 500 ejecutó código que ellos mismos habían publicado, y que esto ocurrió aproximadamente cuatro minutos después de que el código se pusiera en línea. Hubo dos llamadas adicionales dentro de la misma hora. Según ellos, nadie explotó una vulnerabilidad CVE, realizó phishing a ningún empleado ni tocó el perímetro de la red. Los investigadores registraron varios nombres de archivos oficiales, servidos mediante HTTPS y publicados por las propias empresas, que ya indicaban a los agentes de inteligencia artificial qué utilizar.
Dichos archivos eran públicos y los nombres asociados a ellos no estaban reclamados. Los agentes hicieron exactamente lo para lo que habían sido diseñados. El mismo equipo también afirma que, al escanear estos archivos a gran escala, se toparon con un ataque activo ya en curso: un archivo de instrucciones de un proveedor que dirigía a los agentes hacia código malicioso confirmado. Ese caso se describe a continuación.
Primero, los antecedentes.
Por qué llms.txt es importante aquí
Durante la mayor parte de la historia de Internet, una página en un sitio era simplemente una página. Alguien podía leerla, un rastreador podía indexarla, pero nadie la consideraba como una orden. Eso ya no es así.
Actualmente, las empresas colocan un nuevo tipo de archivo en la raíz de sus sitios, junto a robots.txt: llms.txt, y a veces uno más extenso llamado llms-full.txt. No se trata de un mapa del sitio ni de un aviso legal. Funciona como un conjunto cuidadosamente seleccionado de instrucciones para los agentes de IA que indican qué leer, qué APIs utilizar, qué paquetes instalar y en qué dominios confiar. Los laboratorios de modelos grandes publican los suyos propios, y la herramienta Lighthouse de Google en Chrome DevTools ahora incluye una auditoría bajo “navegación por agentes” que incentiva a los sitios a proporcionar uno. La cantidad de estos archivos va en aumento.
El equipo se propuso averiguar cuán ampliamente se había difundido esta capa de instrucciones. Su conteo: 8,565 archivos llms.txt en 6,214 dominios activos, de unas 15,000 empresas catalogadas. Entre los que los publicaron se encontraban grandes empresas, gigantes tecnológicos, empresas de fintech y contratistas de defensa.
Un archivo típico envía a un agente a la documentación, a un registro de cambios y a un foro comunitario, y luego a una línea de instalación, algo similar a pip install para el SDK de la empresa. Parece útil y oficial, y proviene del propio dominio de la empresa a través de HTTPS. Un agente de programación de IA que solicite integrarse con ese producto leerá esa línea y la ejecutará.
La pregunta posterior era casi vergonzosamente sencilla: ¿quién es realmente el dueño de ese nombre de paquete en PyPI? En todos los casos, la respuesta era nadie. El nombre figuraba en un archivo oficial de la propia plataforma, y el paquete al que apuntaba nunca había sido reclamado. Quien llega primero, sirve primero.
Los investigadores revisaron unos cuantos archivos más, luego cientos, y finalmente la mayoría de ellos, y vieron lo mismo en todas partes: instrucciones de instalación que mencionaban nombres de paquetes y dominios que nadie había registrado. Según ellos, estos no eran “potencialmente vulnerables”, sino simplemente disponibles. Tampoco se trataba de typosquatting, ya que los nombres en los archivos estaban escritos correctamente, por lo que no había errores ortográficos que detectar, dado que las registraciones nunca tuvieron lugar.
Cómo terminó ejecutándose código dentro de grandes empresas
El equipo eligió un pequeño conjunto de nombres de paquetes que aparecían en los archivos llms.txt de empresas reconocidas y los registró en PyPI y npm. Cada paquete incluía un mecanismo de retroalimentación inofensivo, una señal mínima que indicaba que se había realizado una instalación en la infraestructura controlada por los investigadores. Después de eso, esperaron.
La primera respuesta llegó en menos de cuatro minutos. Concretamente, dentro de alguna empresa valorada en varios cientos de miles de millones de dólares, un agente de IA leyó el archivo llms.txt en el sitio web de la empresa, encontró una línea de pip install y la ejecutó. El paquete provenía de PyPI, tal como indicaba el archivo, aunque en realidad era el paquete creado por los investigadores. La segunda respuesta provino de una empresa de la lista Fortune 500 y llegó en el transcurso de una hora; luego siguieron unas cuantas docenas más, tanto de startups como de empresas tradicionales, algunas de las cuales contaban con equipos de seguridad más grandes que toda la red profesional de los investigadores.
En resumen, no lograron superar la seguridad de nadie, sino que abusaron de una cadena de confianza.
Cómo los agentes encuentran estos archivos por sí solos
Luego el experimento analizó cuán poco estímulo se necesita. Los investigadores probaron cinco configuraciones diferentes en dos CLIs con capacidad de agencia, les dieron la misma oración 100 veces y no incluyeron nada más que el nombre de un proveedor. La oración pedía al agente que utilizara todos los documentos de ese proveedor para crear y ejecutar un proyecto Node.js con su SDK.
Ese era todo el prompt. No contenía ninguna URL, ningún enlace a documentación ni mención alguna a llms.txt. No hubo inyección de prompt, ningún atacante involucrado ni ingeniería social. El agente localizó por sí mismo el canal de instrucciones, ya que precisamente para eso fue diseñado: buscar la documentación oficial del proveedor. El equipo contó cuántas de las 100 ejecuciones por configuración accedieron a llms.txt, vio la orden y instaló un paquete que nadie había registrado.
Los paquetes estaban diseñados para ser inactivos, solo servían como señal. Todo hasta ese momento fue una investigación controlada. Lo que sigue es un incidente separado que surgió mientras se analizaba el corpus.
Un caso ya presente en la realidad
Un hallazgo detuvo al equipo de inmediato, porque ya estaba ocurriendo.
Clerk, un proveedor de autenticación cuyos SDKs se utilizan en una gran parte de las aplicaciones Next.js en producción, publica documentación escrita para agentes de IA. Un agente que sigue esa pista accede a la guía llms.txt de Clerk para solucionar problemas de protección de autenticación, la cual contiene este comando:
npx clerk-next-fix-auth-protection
El agente lee eso y lo ejecuta, lo cual no es sorprendente teniendo en cuenta que se trata de instrucciones directas del proveedor.
El problema no radica en un nombre de paquete escrito incorrectamente. La orden directa clerk-next-fix-auth-protection es el binario incluido dentro del paquete específico de Clerk @clerk/eslint-plugin. La documentación indica que los agentes deben instalar primero dicho paquete específico y luego ejecutar la orden directa. Pero si se ejecuta la orden antes de que el paquete esté instalado localmente, npx busca su nombre en el registro público de npm, donde Clerk nunca lo publicó como un paquete independiente.
Otra persona lo registró en su lugar. Según la descripción de los investigadores, el paquete no contiene código funcional, pero en cuanto se instala activa ganchos que envían el nombre de usuario del instalador, el nombre de la máquina, el directorio de trabajo y una marca de tiempo a un servidor externo en cada instalación. Está catalogado como MAL-2026-11069 bajo CWE-506, código malicioso incrustado, y fue detectado por OSV.dev de Google y Amazon Inspector. La documentación, la ranura abierta y la ejecución automática serían idénticas tanto si el payload obtiene un nombre de usuario como si instala una puerta trasera completa. El mecanismo de distribución es la vulnerabilidad, y el payload es solo una opción.
La investigación fue comunicada al equipo de seguridad de Clerk, quien respondió rápidamente y lo solucionó. En el informe se destaca que esto no constituye una crítica a Clerk. Un tercero registró el paquete, abusando de la confusión en los nombres de npx, y Clerk no tenía control sobre eso. El equipo lo presenta como un ejemplo confirmado en entornos reales de un problema estructural que afecta a cualquier proveedor que publique documentación legible por agentes.
Por qué los controles actuales podrían no detectarlo
Cada señal en la que se basa una configuración de seguridad apunta en la dirección equivocada en este caso. Un agente que encuentra un archivo llms.txt ve un archivo servido mediante HTTPS desde el dominio oficial, en un formato estándar destinado al consumo por IA, publicado por la empresa o por un socio en el que confía. El agente tiene pocas razones para dudar de nada de eso, ya que el archivo es, por diseño, la fuente autorizada.
Así que cuando el archivo indica instalar una herramienta de apariencia interna, el agente no se detiene a verificar si el nombre pertenece a la empresa. No examina el espacio de nombres de PyPI, ni se da cuenta de que un enlace a la documentación apunta a un dominio cuyo registro venció hace tres meses. Simplemente hace lo que indica el archivo.
La confianza también es transitiva. El archivo llms.txt no necesita estar en el sitio de la empresa objetivo. Los agentes obtienen contexto de terceros de confianza, como las documentaciones de un socio, la referencia al SDK de un proveedor o la página de configuración de un proyecto comunitario. Si el agente confía en ese tercero y el archivo de este apunta a un paquete no reclamado, la cadena funciona de la misma manera.
Tampoco se activó la detección de puntos finales. Para una herramienta EDR o un proxy, esto parece un desarrollador que utiliza un gestor de paquetes legítimo: una orden pip install dirigida a pypi.org, un dominio que todos los proxies corporativos permiten, con un agente de programación desplegado intencionadamente por la empresa como proceso padre. No hay anomalía ni alerta alguna. El fallo ocurre en la etapa anterior, en el intervalo entre la instrucción y su ejecución, y el punto final no puede detectarlo porque nunca se le hizo la pregunta adecuada.
Datos convertidos en código
Durante décadas, el contenido fue consumido por las personas. Ahora, los agentes de IA suelen ser los primeros en leerlo, interpretarlo y actuar sobre él. Ese es el error de categoría en el que cayó toda la industria: la frontera entre datos y código se ha derrumbado. Todo lo que aparece en su sitio web ya no es solo contenido; se trata de información operativa, es decir, código que se ejecuta en el entorno de otra persona con los privilegios que tenga ese agente.
Eso revierte una suposición antigua. Las páginas y documentos solían considerarse de bajo riesgo por definición, ya que nadie los trataba como ejecutables, por lo que nadie destinaba presupuesto para su integridad. Cuando los datos son código, la integridad de los datos se convierte en un elemento más del presupuesto de seguridad.
Más que un archivo
llms.txt no representa toda la superficie de ataque. Es la primera grieta que demuestra que algo ha cambiado. Cada superficie a la que se conecta un agente se convierte en un lugar donde pueden llegar instrucciones, y ninguno de esos lugares fue diseñado con controles de integridad.
Considere qué es lo que realmente recibe un agente: repositorios oficiales de GitHub, documentación, comunidades y foros, sus tickets y su correo electrónico. Durante veinte años este contenido estuvo dirigido a seres humanos, y nadie implementó controles de integridad alrededor de él porque el contenido no podía hacer nada. Ese mundo ya no existe. Todo el conjunto de datos al que están conectados los agentes se ha convertido silenciosamente en una superficie de ejecución.
El verdadero tema no es ni un archivo ni un registro. Los propios datos han cambiado de carácter, y la industria de la seguridad todavía está intentando ponerse al día.
Las cifras detrás de la investigación
- Tamaño del corpus: 8,565 archivos llms.txt provenientes de 6,214 dominios activos, seleccionados de una lista de unas 15,000 empresas.
- Más de 237 elementos no reclamados clasificados como instrucciones de instalación o configuración: nombres de paquetes, dominios y subdominios. Según los investigadores, cada uno de ellos podría haber sido reclamado, la mayoría de forma gratuita.
- Se afectaron seis ecosistemas: PyPI, npm, RubyGems, NuGet, crates.io y Packagist. En el ámbito de los dominios, hubo nombres .dev y .io vencidos, además de subdominios abandonados en Render, Vercel, Fly y Netlify, todos disponibles para ser reclamados.
Qué pueden aprovechar los defensores
Los investigadores describen llms.txt como solo el primer indicio que encontraron, y esperan que surjan más modos de fallo. A continuación se presentan algunos aspectos prácticos derivados de sus hallazgos:
- Haga una auditoría de los archivos destinados a sus agentes. Cada nombre de paquete, dominio y subdominio que mencionen debe estar registrado, ser propiedad de alguien y estar bajo supervisión.
- Ejecute los comandos de la documentación utilizando el nombre del paquete específico. Un nombre binario sin más detalles puede resolverse en un registro público si la instalación local aún no se ha realizado.
- Trate la documentación de terceros que consumen sus agentes como parte de la cadena de suministro, ya que la confianza proviene de ella.
- Tenga en cuenta que las herramientas estándar para puntos finales solo detectan una instalación normal de paquetes y no la marcarán como problemática, por lo que los controles deben aplicarse antes, en las instrucciones y en la búsqueda en el registro.
Según la declaración de divulgación, no se causó ningún daño en el experimento. No se implementó ninguna persistencia, no se extrajeron datos, los hallazgos se están comunicando de manera responsable a las organizaciones afectadas, y los nombres de las empresas se mantienen en secreto mientras continúa la corrección.
Lecturas relacionadas
- Creación de un agente asistente de conocimiento en Databricks con LangGraph — Construir un agente LangGraph en Databricks paso a paso: un agente mínimo, búsqueda vectorial RAG, puntos de control Lakebase para la memoria a corto plazo y un almacenamiento para la memoria a largo plazo.
- Una base de datos local para currículos RAG con Docling, PostgreSQL pgvector y Ollama — Convertir una carpeta de currículos en formato PDF y DOCX en una base de datos de candidatos buscable: fragmentación con Docling, PostgreSQL con pgvector, modelos locales Ollama y una interfaz frontal Streamlit.