Automatización del ciclo de vida del fuzzing
Antonio Morales, miembro de GitHub Security Lab, ha desarrollado el Fuzzing Taskflow basándose en el Taskflow Agent para transformar el proceso de fuzzing en un flujo de trabajo autónomo. El fuzzing es una técnica de pruebas de software que consiste en introducir datos aleatorios o malformados en un programa para provocar fallos y descubrir errores de seguridad. Hasta ahora, este proceso requería que un experto supervisara la cobertura del código, escribiera harnesses —funciones específicas que actúan como puntos de entrada para el fuzzer— y analizara manualmente cada cierre inesperado del programa.
El nuevo sistema permite que un usuario simplemente indique un repositorio de GitHub para que la IA asuma todo el flujo de trabajo. El agente identifica los puntos de entrada más adecuados, analiza el sistema de construcción del proyecto, redacta los harnesses necesarios y ejecuta AFL++, una herramienta de fuzzing basada en instrumentación. Posteriormente, el agente lee los informes de cobertura, ajusta los harnesses para alcanzar zonas del código no exploradas y redacta un informe de vulnerabilidad detallado por cada error único detectado, operando sin supervisión constante.
Arquitectura técnica y gestión de herramientas
El funcionamiento del Fuzzing Taskflow se organiza en tres capas diferenciadas para garantizar que haya una separación clara entre la toma de decisiones y la ejecución técnica. La primera capa es un controlador de shell, el archivo run_fuzzing.sh, que encadena las diversas etapas del flujo. La segunda capa consiste en una serie de archivos YAML que contienen los prompts específicos que guían al modelo de lenguaje extenso en cada fase del proceso. Finalmente, la tercera capa está compuesta por herramientas MCP (Model Context Protocol), que son las primitivas que el agente invoca para realizar tareas concretas, como compilar un harness o ejecutar AFL.
Para evitar que el agente interactúe directamente con el sistema operativo de forma descontrolada, el diseño establece que el LLM solo tome decisiones sobre qué fuzzear o qué brecha de cobertura cerrar, mientras que las herramientas MCP ejecutan las acciones. Todo el estado del proceso se almacena en una base de datos SQLite denominada fuzz_context.db, lo que impide que los datos se transmitan en memoria entre etapas y asegura la persistencia de la información.
Implementación de binarios duales para la cobertura
Un aspecto técnico relevante es la construcción doble de cada harness. El sistema genera un binario .afl, compilado con afl-clang-lto y sanitizadores de direcciones y valores indefinidos, destinado exclusivamente a la ejecución del fuzzer. Simultáneamente, crea un binario .cov mediante clang con mapeo de cobertura y generación de instrumentos de perfil. Mientras el primero guía la búsqueda de errores, el segundo se utiliza para reproducir la cola de entradas de AFL y generar informes de cobertura de líneas y ramas que sean legibles para el agente de IA.
Optimización de la cobertura y detección de mesetas
El núcleo del sistema es un bucle de retroalimentación de cobertura que automatiza la tarea manual de analizar informes LCOV para encontrar ramas no cubiertas. El agente ejecuta AFL durante un presupuesto de tiempo determinado, analiza el informe de cobertura y decide la acción más eficiente para avanzar. Las opciones incluyen la creación de una nueva semilla diseñada para alcanzar una rama específica, la edición del código fuente del harness para llamar a una API adicional o el enriquecimiento del diccionario de AFL con constantes mágicas que el programa esté comparando.
Para optimizar el uso de los recursos computacionales, el presupuesto de tiempo se duplica en cada iteración, comenzando en 30 segundos y llegando hasta los 960 segundos por objetivo. Esta estrategia permite capturar rápidamente los errores más evidentes y dedicar más tiempo a las protecciones más complejas. El proceso se detiene mediante un mecanismo de detección de mesetas: si dos iteraciones consecutivas aportan menos del 1 % de cobertura absoluta de líneas, el agente considera que ha llegado al límite de rentabilidad y finaliza la tarea.
Fuzzing consciente de la estructura y mutaciones
El Fuzzing Taskflow aborda la limitación de los mutadores de bytes tradicionales, que suelen fallar ante entradas de texto estructurado. Para solventar esto, el marco implementa cuatro mecanismos de generación de entradas conscientes de la estructura. Primero, utiliza diccionarios y mutadores personalizados para formatos conocidos como JSON, XML, PNG y regex. El mutador de JSON, por ejemplo, realiza la duplicación de corchetes equilibrados y el empalme de tokens, mientras que el de XML gestiona etiquetas y entidades.
En segundo lugar, el sistema puede generar un diccionario a nivel de fuente escaneando los archivos .c y .h del proyecto. El agente extrae literales de cadena y constantes numéricas de 32 bits provenientes de definiciones o enumeraciones, bajo la premisa de que los valores más críticos que un analizador verifica suelen estar escritos en su propio código fuente. Tercero, el diccionario de AFL crece dinámicamente; el flujo de trabajo analiza las instrucciones de comparación cerca de las líneas no cubiertas, como strncmp o memcmp, y añade esos nuevos tokens al diccionario.
Finalmente, el agente emplea un operador de empalme de corpus que carga archivos de un directorio y combina regiones aleatorias de estos en la entrada, una capacidad de recombinación que supera las funciones estándar de la herramienta havoc de AFL. Para evitar la pérdida de progreso, cada harness mantiene un directorio de corpus estable que sobrevive a las iteraciones y a las campañas completas, asegurando que el fuzzer no tenga que redescubrir las mismas rutas en cada ejecución.
Seguridad en la ejecución y selección de modelos
Debido a que el Taskflow Agent ejecuta comandos de construcción arbitrarios y utiliza clang y afl-fuzz directamente en el host sin un contenedor intermedio, existe un riesgo de seguridad. Un agente que sufra una inyección de prompts podría, teóricamente, ejecutar cualquier acción que el usuario tenga permitida en el sistema. Por ello, GitHub Security Lab recomienda ejecutar la herramienta exclusivamente en entornos desechables, como Codespaces o máquinas virtuales efímeras, y sin privilegios elevados.
En cuanto al modelo de lenguaje, el sistema utiliza Claude Sonnet 5 por defecto, ya que ha superado las pruebas internas sin activar las barreras de seguridad que algunos modelos frontera imponen a las tareas de ciberseguridad. No obstante, la configuración es flexible y permite cambiar el modelo a través de un archivo de configuración YAML en el directorio de origen del proyecto.
Impacto en la seguridad de proyectos de código abierto
La introducción de esta herramienta cambia la dinámica del mantenimiento de proyectos de código abierto. Anteriormente, incluso los proyectos inscritos en OSS-Fuzz podían albergar errores críticos porque la creación de nuevos harnesses y el triaje de fallos dependían totalmente de la disponibilidad de expertos humanos. Al delegar estas tareas a un agente de IA, se reduce la barrera de entrada para implementar un fuzzing continuo y exhaustivo.
La capacidad de generar mutadores sobre la marcha y de ajustar la estrategia de cobertura basándose en el análisis del código fuente permite que el proceso de descubrimiento de vulnerabilidades sea mucho más agresivo y preciso. Para los desarrolladores, esto significa que la detección de errores de memoria o desbordamientos de búfer ocurre de forma automática y sistemática, transformando la seguridad de una tarea reactiva en un proceso autónomo integrado en el ciclo de desarrollo.



