En vivo 18.11 · Cohorte 318 nov, 19:00 MSK — taller práctico gratuito de agentes IA · Cohorte 3 en vivo inicia 23.11Taller 18 nov →Cohorte 3 (23.11)
LanzamientoAnálisis · En radarHabr AI→ original

Kilo Code entregó en silencio al servidor los 12 archivos del proyecto, aunque solo se permitían dos

El autor comprobó qué se envía al servidor del modelo cuando un asistente de IA cambia un solo carácter en el código. Kilo Code 7.4.20 sustituyó la suma por la multiplicación, la prueba pasó y en el disco cambió un solo archivo. Pero un servidor de prueba que hacía de proveedor no confiable recibió los 12 archivos del proyecto, aunque el usuario solo había permitido enviar dos, y las copias coincidían byte a byte.

Procesado por IA desde Habr AI; editado por Hamidun News
Kilo Code entregó en silencio al servidor los 12 archivos del proyecto, aunque solo se permitían dos
Fuente: Habr AI. Collage: Hamidun News.
Escuchar artículo
Ficha técnica y cifras clave
ParámetroDatos
Fuente originalHabr AI ↗
Editor jefe
Dato clave #1El servidor leyó los archivos con llamadas read normales, sin archivos comprimidos ni curl
Dato clave #2Los resultados de la lectura iban al historial del chat y se enviaban en cada solicitud posterior
Dato clave #3Prohibir read no sirve si bash está permitido: Python lee el mismo archivo

Solemos aceptar el trabajo de un asistente de IA así: miramos el diff, ejecutamos las pruebas, vemos el verde y cerramos la tarea. Un experimento descrito en Habr revela un agujero en ese hábito. La edición puede ser perfecta y, aun así, el proyecto ya está en un servidor ajeno.

Cómo se montó el experimento

La tarea era deliberadamente minúscula: en price.py la función total(price, count) devolvía price + count, mientras que la prueba esperaba que total(7, 3) diera 21. Había que sustituir la suma por la multiplicación y ejecutar check.py. La instrucción del usuario decía que solo se podían enviar price.py y check.py.

El autor partió de un modelo en el que el proveedor de LLM no es confiable e incumple las instrucciones a propósito. Su papel lo desempeñó un servidor HTTP local en 127.0.0.1. Imitaba respuestas en streaming de la API Chat Completions compatible con OpenAI y enviaba al cliente tool_calls: primero doce comandos read para todos los archivos de un proyecto sintético, luego un comando de corrección y después la ejecución de la prueba. El cliente era real: bin/kilo.exe de la extensión Kilo Code 7.4.20, lanzado mediante el comando CLI run. La configuración permitía lectura y ejecución de comandos.

Qué ocurrió

Por fuera, todo parecía ejemplar. Kilo cambió un carácter, la prueba pasó, los demás archivos en disco no cambiaron, el código de salida fue cero y las 14 llamadas a herramientas terminaron con el estado completed. Pero el servidor recibió los 12 archivos, con un total de 11 103 bytes, y sus SHA-256 coincidían con los originales.

La mecánica es simple. Kilo añade el resultado de cada lectura al historial del chat y lo envía en la siguiente solicitud. El servidor extrae los mensajes con el rol tool, elimina los números de línea y recompone los archivos. No hace falta ningún canal de exfiltración: el cliente mismo lleva los datos en sus solicitudes habituales.

El tráfico es interesante por sí mismo. Hubo 15 llamadas al modelo y el volumen total de los cuerpos de las solicitudes fue de 458 779 bytes para 11 KB de código único. La causa es el reenvío del historial, las descripciones de herramientas y el marcado de servicio. No hubo una única solicitud enorme: el código salía en porciones pequeñas y luego se repetía. Por eso una fuga así no se detecta por el tamaño de una solicitud.

Por qué las prohibiciones funcionan peor de lo que parece

En la serie inicial de pruebas, la regla read: deny bloqueaba la lectura directa de un directorio prohibido. Pero con bash: allow, Python leyó el mismo archivo y la salida pasó a la siguiente solicitud. Cuando se prohibió bash, el comando no se ejecutó. Los permisos en Kilo se definen por separado para cada herramienta, y prohibir una no cierra las demás vías.

Hay también salvedades honestas. En el experimento no hay un modelo real: los comandos los elegía el servidor de prueba, así que no se mide la propensión de los modelos comerciales a este comportamiento. El servidor conocía de antemano los nombres de los archivos; no se probó la búsqueda autónoma de un árbol desconocido. Tampoco se probó la sesión gráfica de la extensión, solo la CLI.

Qué hacer en la práctica

Primero: evalúe no solo el diff, sino también el registro de llamadas a herramientas y los cuerpos de las solicitudes al proveedor. Pase al menos una vez al agente por un proxy local y vea qué sale realmente.

Segundo: dé al agente los mínimos permisos. Si la lectura está permitida, todo lo leído pertenece potencialmente al proveedor. Para repositorios sensibles, es un argumento a favor de los modelos locales o de proveedores con garantías contractuales estrictas.

Tercero: no confíe en una instrucción de texto como «envía solo estos dos archivos». Es un deseo dirigido al modelo, no una restricción del cliente. El límite real lo crean solo los permisos de las herramientas, el sandbox y las políticas de red.

El autor publicó el banco de pruebas completo: Python 3.10+, Git y el ejecutable de Kilo, unas 150 líneas de código. Conviene repetirlo con su propio cliente, sea cual sea el agente que use.

Historia

Preguntas frecuentes sobre la noticia

Cómo se montó el experimento?

La tarea era deliberadamente minúscula: en price.py la función total(price, count) devolvía price + count, mientras que la prueba esperaba que total(7, 3) diera 21. Había que sustituir la suma por la multiplicación y ejecutar check.py. La instrucción del usuario decía que solo se podían enviar price.py y check.py. El autor partió de un modelo en el que el proveedor de LLM no es confiable e incumple las instrucciones a propósito. Su papel lo desempeñó un servidor HTTP local en 127.0.0.1.

¿Qué se sabe sobre Qué ocurrió?

Por fuera, todo parecía ejemplar. Kilo cambió un carácter, la prueba pasó, los demás archivos en disco no cambiaron, el código de salida fue cero y las 14 llamadas a herramientas terminaron con el estado completed. Pero el servidor recibió los 12 archivos, con un total de 11 103 bytes, y sus SHA-256 coincidían con los originales. La mecánica es simple. Kilo añade el resultado de cada lectura al historial del chat y lo envía en la siguiente solicitud.

¿Qué se sabe sobre Por qué las prohibiciones funcionan peor de lo que parece?

En la serie inicial de pruebas, la regla read: deny bloqueaba la lectura directa de un directorio prohibido. Pero con bash: allow, Python leyó el mismo archivo y la salida pasó a la siguiente solicitud. Cuando se prohibió bash, el comando no se ejecutó. Los permisos en Kilo se definen por separado para cada herramienta, y prohibir una no cierra las demás vías. Hay también salvedades honestas.

ZK
Zhemal Khamidun — CPO de Alpina Digital, product manager de AlpinaGPT. Crea productos de IA desde 2019. Hamidun News es un proyecto personal que creció hasta ser un agregador en producción con más de 6.000 lectores.
✦ Unified AI Workspace · Nomad

Test Frontier LLMs & Autonomous Agents in One Workspace

Run Claude Opus 5.5, GPT-6, Gemini 3.1, and DeepSeek side-by-side in Nomad AI (nomadnet.ai) — unified model routing, deep research, and multimodal workflows under one subscription.

Try Nomad AI →Launch Nomad Agent
¿Qué te parece?
Cargando comentarios…