Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
seclab-taskflows-fuzzing — Una pipeline de fuzzing impulsada por LLM y potenciada por el GitHub Security Lab Taskflow Agent | Kitploit
Herramientas/GitHubGitHub/githubsecuritylab/seclab-taskflows-fuzzing
Análisis EstáticoEscáneres de VulnerabilidadesAnálisis Dinámico (Sandboxing)Análisis de VulnerabilidadesAnálisis de CódigoScripting y AutomatizaciónFuzzingAnálisis de Malware
Utilidades y Frameworks
Seguridad de IA
GitHubgithubsecuritylab/seclab-taskflows-fuzzing

seclab-taskflows-fuzzing

Una pipeline de fuzzing impulsada por LLM y potenciada por el GitHub Security Lab Taskflow Agent

Ver Repositorio
122hace 4 díasAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

Seclab Taskflows Fuzzing

Una pipeline de fuzzing estilo OSS-Fuzz impulsada por LLM para proyectos nativos en C/C++. AFL++ para la ejecución, clang+lcov para la cobertura, un agente LLM para la escritura de harnesses, decisiones basadas en retroalimentación de cobertura, triaje y reportes.

  • Totalmente autónoma: le das un repositorio de GitHub y se encarga de todo, desde la identificación del objetivo hasta los informes de vulnerabilidades.
  • Técnicas estilo OSS-Fuzz: mutadores/diccionarios por formato, empalme de tokens consciente de la estructura, mejoras de harness guiadas por cobertura.
  • Genera informes de fallos legibles por máquina con veredictos de explotabilidad y parches sugeridos.
  • Panel HTML en vivo para el monitoreo de campañas en tiempo real.
  • Escrito en Python (taskflows/toolboxes/configs) con generación de harness en C para AFL++.
  • Estado: Desarrollo activo.

Antecedentes

Este repositorio contiene el taskflow de fuzzing para el GitHub Security Lab Taskflow Agent. Depende del repositorio complementario seclab-taskflows para algunos bloques de construcción compartidos (taskflow fetch_source_code, toolboxes local_file_viewer / gh_file_viewer, y el model_config predeterminado) — estos se instalan automáticamente como una dependencia de Python.

¡Las contribuciones son bienvenidas! Consulta CONTRIBUTING.md para obtener pautas.

Requisitos

  • Python 3.11+
  • Un entorno Linux (o Codespace) con acceso a apt
  • AFL++, clang, lcov, ctags, cscope, graphviz (instalados automáticamente por la pipeline si faltan)
  • Git y GitHub CLI (gh)

Instalación```bash

pip install git+https://github.com/GitHubSecurityLab/seclab-taskflows-fuzzing

root@kitploit:~
Esto incorpora `seclab-taskflow-agent` y `seclab-taskflows` (padre)
de forma transitiva, por lo que cada referencia con puntos de la forma
`seclab_taskflows.taskflows.audit.*`,
`seclab_taskflows.toolboxes.local_file_viewer`,
`seclab_taskflows.toolboxes.gh_file_viewer`, y
`seclab_taskflows.configs.model_config` se resuelve desde la distribución
padre en tiempo de ejecución.

---

## Tabla de contenidos

1. [Qué es esto](#what-this-is)
2. [Inicio rápido](#quick-start)
3. [Arquitectura](#architecture)
4. [El pipeline, etapa por etapa](#the-pipeline-stage-by-stage)
5. [El bucle de retroalimentación de cobertura](#the-coverage-feedback-loop)
6. [Fuzzing consciente de la estructura](#structure-aware-fuzzing)
7. [Corpus persistente entre iteraciones y campañas](#persistent-corpus-across-iterations-and-campaigns)
8. [Triaje e informes de vulnerabilidades](#triage-and-vulnerability-reports)
9. [Panel en vivo](#live-dashboard)
10. [Archivos de salida](#output-files)
11. [Esquema de la base de datos](#database-schema)
12. [Herramientas MCP (el vocabulario del agente)](#mcp-tools-the-agents-vocabulary)
13. [Parámetros ajustables (variables de entorno)](#tunable-knobs-environment-variables)
14. [Extender el pipeline](#extending-the-pipeline)
15. [Proyectos de referencia y resultados](#benchmark-projects-and-results)
16. [Limitaciones y trampas](#limitations-and-gotchas)
17. [Advertencia de seguridad](#security-warning)
18. [Desarrollo: pruebas, linting, contribución](#development-testing-linting-contributing)
19. [Glosario](#glossary)

---

## Qué es esto

Este taskflow es un pipeline de fuzzing totalmente autónomo. Dado un repositorio de GitHub
de un proyecto nativo en C/C++, hará lo siguiente:

1. instalar AFL++ + clang/llvm/lcov + ctags/cscope/graphviz si faltan,
2. obtener el código fuente,
3. identificar objetivos de fuzzing candidatos (parsers, decodificadores, validadores, …),
4. analizar el sistema de compilación,
5. escribir uno o más candidatos de harness por objetivo, compilar cada uno tanto como un
   binario `.afl` instrumentado con AFL como un binario `.cov` instrumentado para cobertura,
6. (opcionalmente) calificar candidatos mediante cobertura de 60 segundos y conservar el mejor,
7. ejecutar un bucle de fuzzing/cobertura/mejora con presupuestos de tiempo que se duplican,
8. triar cada fallo, confirmar que los fallos previamente conocidos aún se reproducen, y
   escribir informes de vulnerabilidad en markdown por cada fallo con veredictos, explotabilidad,
   parches sugeridos y bocetos de pruebas de regresión,
9. construir un grafo de llamadas al estilo Fuzz-Introspector + informe de API no tocada para la
   siguiente campaña,
10. publicar todo en un panel HTML en vivo.

El pipeline es **al estilo OSS-Fuzz** en esencia: utiliza muchas de las mismas
técnicas (mutadores y diccionarios por formato, empalme de tokens consciente de la estructura, mejoras de harness guiadas por cobertura, informes legibles por máquina,
fallos deduplicados con hash de pila) pero es mucho más pequeño y autocontenido.

---

## Inicio rápido```bash
# Inside the codespace (or a host with python + git available):
./scripts/fuzzing/run_fuzzing.sh tukaani-project/xz

Esa es toda la interfaz. El script es autónomo; instalará AFL++ en la primera ejecución y luego dirigirá el resto del flujo de tareas. Los archivos de salida se escriben en ~/.local/share/seclab-taskflow-agent/seclab-taskflows/.

El panel de control se inicia automáticamente en segundo plano; en un Codespace, el puerto 8765 se redirige automáticamente — ábrelo en cualquier navegador para ver el progreso en vivo.

Para una prueba rápida, usa un objetivo pequeño:```bash ./scripts/fuzzing/run_fuzzing.sh DaveGamble/cJSON

root@kitploit:~
---

## Arquitectura

Tres capas, de arriba a abajo:```
┌────────────────────────────────────────────────────────────────────┐
│  scripts/fuzzing/run_fuzzing.sh                                    │
│      shell driver; chains the taskflow stages with `set +e`        │
└────────────────────┬───────────────────────────────────────────────┘
                     │
                     ▼
┌────────────────────────────────────────────────────────────────────┐
│  src/seclab_taskflows/taskflows/fuzzing/*.yaml                     │
│      LLM agent prompts; one YAML per pipeline stage                │
└────────────────────┬───────────────────────────────────────────────┘
                     │  (calls MCP tools)
                     ▼
┌────────────────────────────────────────────────────────────────────┐
│  src/seclab_taskflows/mcp_servers/                                 │
│   ├ fuzz_context.py    persistence (SQLite via SQLAlchemy)         │
│   └ fuzz_runner.py     subprocess wrappers (AFL, clang, lcov, ...) │
│                                                                    │
│  scripts/fuzzing/dashboard.py                                      │
│   read-only HTML view of fuzz_context.db                           │
└────────────────────────────────────────────────────────────────────┘

Reglas de diseño clave:

  • Sin estado global en las herramientas MCP. Cada función de herramienta toma argumentos explícitos; el estado persistente vive en fuzz_context.db.
  • Los agentes LLM son dueños de las decisiones, las herramientas MCP son dueñas de la ejecución. El agente decide qué fuzzear, qué harness escribir, qué brecha perseguir a continuación; las herramientas MCP solo exponen run_afl_for, compile_harness, store_crash, etc.
  • Idempotencia donde sea barato. Re-ejecutar el pipeline contra el mismo repositorio hace upsert de targets/harnesses/runs en lugar de duplicarlos. Esto es lo que hace que funcionen el corpus persistente y la transferencia entre campañas.
  • Dos binarios por harness. La instrumentación de bordes de AFL no es adecuada para informes de cobertura legibles por humanos, por lo que cada harness se compila dos veces: una con afl-clang-lto -fsanitize=address,undefined (el binario .afl) y otra con clang -fprofile-instr-generate -fcoverage-mapping (el binario .cov). El binario .afl hace fuzzing; el binario .cov reproduce la cola de AFL para producir cobertura real de líneas de código/funciones/ramas.

El pipeline, etapa por etapa

#EtapaTaskflow YAML
1Instalar AFL++ + herramientasscripts/fuzzing/install_afl.sh
2Obtener código fuenteseclab_taskflows.taskflows.audit.fetch_source_code
3Identificar objetivos de fuzzingseclab_taskflows_fuzzing.taskflows.fuzzing.identify_fuzz_targets
4Analizar el sistema de compilaciónseclab_taskflows_fuzzing.taskflows.fuzzing.analyze_build_system
5aEscribir harnesses iniciales (×N candidatos si se solicita)seclab_taskflows_fuzzing.taskflows.fuzzing.write_initial_harnesses
5bCompilar harnesses (AFL + cobertura)seclab_taskflows_fuzzing.taskflows.fuzzing.build_harnesses
5cCalificar candidatos (cuando HARNESS_CANDIDATES > 1)seclab_taskflows_fuzzing.taskflows.fuzzing.qualify_harnesses
6Bucle de fuzzing/cobertura/mejora (×N iteraciones)seclab_taskflows_fuzzing.taskflows.fuzzing.fuzz_iteration
7Triaje de crashesseclab_taskflows_fuzzing.taskflows.fuzzing.triage_crashes
8Confirmar que crashes previamente conocidos aún se reproducenseclab_taskflows_fuzzing.taskflows.fuzzing.confirm_fixed_crashes
9Construir grafo de llamadas + informe de API no tocadaseclab_taskflows_fuzzing.taskflows.fuzzing.analyze_call_graph
10Escribir informes de vulnerabilidades por crashseclab_taskflows_fuzzing.taskflows.fuzzing.write_vuln_reports
11Escribir informe de campañaseclab_taskflows_fuzzing.taskflows.fuzzing.write_report

Cada etapa es un taskflow YAML autocontenido que el agente ejecuta de principio a fin. Las etapas se comunican exclusivamente a través de la base de datos SQLite en fuzz_context.db — no hay transferencia en memoria.


El bucle de retroalimentación de cobertura

Este es el corazón del pipeline. Los presupuestos de tiempo se duplican en cada iteración:``` 30s → 60s → 120s → 240s → 480s → 960s (≈ 32 min/target)

root@kitploit:~
En cada iteración, para cada harness, el agente:

1. Solicita `get_persistent_corpus_dir(harness_id)` para obtener el
   directorio de corpus estable de este harness.
2. Llama a `run_afl_for(afl_binary_path, seed_dir=<persistent corpus>,
   output_dir=<run dir>, seconds=<budget>, dictionary=<auto.dict>)`.
3. Llama a `run_coverage(cov_binary_path, inputs_dir=<run>/default/queue,
   output_dir=<run>/coverage)` para producir un tracefile LCOV y un informe HTML.
4. Llama a `store_coverage_from_lcov(run_id, lcov_path, html_path)` para persistir
   una fila `coverage_report` + filas `coverage_gap` por cada elemento no cubierto.
5. Llama a `fold_queue_into_persistent_corpus(...)` para fusionar la cola de iteración
   de AFL en el corpus persistente y ejecutar `cmin` para mantener el tamaño acotado.
6. Lee `get_coverage_summary` + `get_coverage_gaps`, y luego:
   - añade una nueva semilla (etiquetada `coverage_feedback`) para alcanzar una
     rama no cubierta,
   - edita el código fuente del harness para llamar a una API adicional,
   - llama a `enrich_dictionary_from_uncovered(...)` para añadir automáticamente
     entradas al diccionario para las constantes mágicas que AFL necesita para
     satisfacer un guard, o
   - omite la brecha (ruta de error en frío / código de proveedor).
7. Llama a `store_iteration_note(repo, iteration_number, harness_id, note=<resumen
   de una línea>)` para que la línea temporal de iteraciones del panel de control
   registre lo que cambió.

**Detección de estancamiento.** El bucle termina anticipadamente una vez que dos iteraciones consecutivas
han ganado ambas < `FUZZ_PLATEAU_THRESHOLD_PCT` (por defecto `1.0`) puntos porcentuales absolutos
de cobertura de líneas.

---

## Fuzzing consciente de la estructura

Tres mecanismos complementarios producen entradas más sólidas que la mutación de bytes en bruto.

### 1. Diccionarios por formato + mutadores personalizados

Para objetivos cuyo `input_kind` coincide con un formato conocido, el taskflow incluye
diccionarios preconstruidos y archivos fuente C de `LLVMFuzzerCustomMutator`:

| Formato | Diccionario | Mutador | Notas |
|--------|------------|---------|-------|
| `json` | `json.dict` | `json_mutator.c` | Empalme de tokens, dup/drop de corchetes balanceados, cambio de tipo |
| `xml` | `xml.dict` | `xml_mutator.c` | Etiquetas, entidades, DTDs, tokens billion-laughs |
| `regex` | `regex.dict` | `regex_mutator.c` | Anclas, clases, cuantificadores, patrones ReDoS reales |
| `binary_tlv` | _(ninguno)_ | `binary_tlv_mutator.c` | Registros con prefijo de longitud: desbordamiento de longitud / dup / drop |
| `png` | `png.dict` | _(reutiliza binary_tlv)_ | Diccionario PNG + mutador binary_tlv |

Estos son recogidos automáticamente por `write_initial_harnesses` (diccionario
copiado junto a las semillas) y `build_harnesses` (mutador enlazado en el binario
de AFL). Cada mutador delega el 50% de las mutaciones al mutador de bytes por defecto
de AFL para no perder la aleatorización del motor.

Para añadir un nuevo formato: coloca un `<name>.dict` y/o un `<name>_mutator.c` en
`src/seclab_taskflows/dictionaries/`, luego regístralo en el
mapa `_FORMAT_ASSETS` al final de `fuzz_runner.py`.

### 2. Mutador inteligente consciente del código fuente (específico del proyecto)

Para formatos desconocidos, o cuando quieras tokens más sólidos específicos del proyecto,
`generate_smart_mutator` escanea los propios archivos `.c`/`.h` del repositorio objetivo
y emite un archivo C `LLVMFuzzerCustomMutator` cuyos diccionarios de empalme
se extraen de:

- literales de cadena con ≥3 caracteres alfabéticos (tras filtrar ruido de
  compilador/licencia, rutas, cabeceras, restricciones asm, especificadores de formato),
- constantes numéricas de 32 bits de `#define`, `case` y `enum` (tras
  filtrar ruido genérico de enteros pequeños como 0, 1, 256, 0xff…).

Hay tres enfoques disponibles:

| Enfoque | Qué empalma | Cuándo usarlo |
|-------|-----------------|-------------|
| `strings` | Solo literales de cadena del proyecto | Formatos de texto (JSON, XML, YAML, CSV) |
| `constants` | Solo valores mágicos numéricos de 32 bits | Protocolos binarios, cabeceras con números mágicos |
| `combined` | Ambos | Por defecto; normalmente el mejor |

Combina `generate_smart_mutators(...)` (plural) con `HARNESS_CANDIDATES >= 3`
para que cada enfoque se convierta en un harness candidato en la ronda de clasificación.

### 3. Diccionario AFL consciente del proyecto + enriquecimiento guiado por cobertura

Dos herramientas complementarias construyen y hacen crecer un diccionario `-x` de AFL
a medida que avanza la campaña:

- **`generate_project_dictionary(source_root, output_path)`** — se ejecuta una vez
  antes de la iteración 1, extrae estáticamente el mismo conjunto de tokens de código fuente
  usado por el mutador inteligente y lo escribe como un diccionario AFL. Las constantes
  numéricas se emiten en AMBAS endiannesses para que el fuzzer pueda satisfacer
  `memcmp(x, &magic, 4)` independientemente del orden de bytes del host.

- **`enrich_dictionary_from_uncovered(source_root, dictionary_path,
  uncovered_locations)`** — se ejecuta después del paso de cobertura de cada iteración,
  escanea el código fuente circundante en busca de guards condicionales
  (`strncmp/memcmp/strstr`, `case 0xN:`, `== 0xN`, `== 'X'`) cerca de las
  líneas no cubiertas, y AÑADE cualquier token nuevo al diccionario. Idempotente:
  nunca vuelve a añadir una entrada que ya está presente.

### 4. Operación de empalme de corpus

Cuando se pasa `corpus_dir` a `generate_smart_mutator`, el C generado
también obtiene un operador de empalme de corpus: en la primera llamada carga hasta 64 archivos
de ese directorio (limitados a 4 KiB cada uno), y a partir de entonces puede empalmar
subregiones aleatorias de esos archivos en la entrada mutada. Esto le da
al mutador un operador de estilo recombinación que el havoc estándar de AFL no hace
bien. Combínalo con `get_persistent_corpus_dir(...)` para que la biblioteca de empalme
sea "remezclar lo que AFL ya ha descubierto".

---

## Corpus persistente entre iteraciones y campañas

Cada harness tiene un directorio de corpus estable en:```
<workspace>/corpus/harness_<id>/

Así es como fuzz_iteration usa seed_dir para run_afl_for (en lugar de <harness>/seeds). Al final de cada iteración, fold_queue_into_persistent_corpus(...) fusiona la cola de iteración de AFL en este directorio y ejecuta afl-cmin para mantenerlo acotado.

El resultado: la cola de ayer se traslada a la ejecución de hoy Y a través de re-ejecuciones del mismo proyecto. Un parar-y-reiniciar de la campaña no pierde ningún progreso.


Triaje e informes de vulnerabilidades

Después de que el bucle de fuzz/cobertura/mejora finaliza, tres etapas se ejecutan automáticamente:

1. triage_crashes

Para cada archivo de crash en <run>/default/crashes/:

  • afl-tmin para minimizar la entrada,
  • replay_under_asan para capturar un stack trace y stack_top_hash (top-N frames normalizados; plantillas, espacios de nombres inline de libcxx, espacios de nombres anónimos y sufijos numéricos de LTO se eliminan para que crashes semánticamente idénticos tengan el mismo hash),
  • deduplicar por hash, persistir una fila crash con clasificación de bug-class + nota de confianza (alta / media / baja).

2. confirm_fixed_crashes

Reejecuta cada crash previamente clasificado (cuyo veredicto no sea ya fixed/duplicate/non_reproducible) a través del binario AFL+ASan actual. Si ya no provoca crash, marca verdict="fixed". Útil al re-ejecutar una campaña contra un proyecto que ha recibido correcciones upstream desde la última campaña.

3. write_vuln_reports

Para cada crash único, el agente lee el código fuente del harness + el código fuente de la función que provoca el crash, recorre la cadena de llamadas desde la API pública, luego asigna uno de diez veredictos al estilo OSS-Fuzz y escribe un informe de vulnerabilidad en markdown:

VeredictoSignificado
vulnerabilityReal, explotable a través de una API pública
library_hardeningBug real pero sin ruta realista por API pública; la biblioteca aún debería defenderse
harness_bugEl bug está en nuestro harness, no en la biblioteca
non_reproducibleLa reproducción no reproduce el crash con la entrada minimizada
oomOut-of-memory; vulnerabilidad solo si el tamaño controlable por el atacante es ilimitado
timeoutDoS mediante explosión algorítmica
assertion_failureSe alcanzó assert(); la relevancia de seguridad varía
fixedEstablecido por confirm_fixed_crashes: la entrada ya no reproduce
duplicateMisma causa raíz que otro crash con un hash de pila diferente
needs_investigationNo se pudo determinar; marcado para revisión humana

Cada informe de vulnerabilidad incluye:

  • Veredicto + bug class + CWE + severidad + confianza
  • Análisis de causa raíz con referencias archivo:línea
  • Alcanzabilidad desde la API pública (cadena de llamadas concreta)
  • Evaluación de explotabilidad (lectura vs. escritura, control del atacante, mitigaciones)
  • Corrección sugerida como diff unificado (marcada como "revisión requerida")
  • Esbozo de prueba de regresión

Panel en vivo

El panel se inicia automáticamente en segundo plano mediante run_fuzzing.sh. Desactívalo con FUZZ_NO_DASHBOARD=1; sobrescribe el puerto con FUZZ_DASHBOARD_PORT (por defecto 8765).

En un Codespace, el puerto 8765 se reenvía automáticamente — abre la URL reenviada en cualquier navegador. La página se actualiza automáticamente cada 5 s y muestra:

  • Chips de resumen de veredictos — recuentos por categoría de veredicto, ejecuciones totales, rutas, recuento total de ejecuciones, crashes
  • Indicador de pulso "en ejecución" en vivo — por repo y por harness con un fuzz_run en curso
  • Tabla de tendencia de cobertura con sparklines SVG en línea y una columna de delta por iteración
  • Grafo de llamadas y superficie de API no tocada — la instantánea de Fuzz-Introspector-lite
  • Tabla de crashes — ordenada por veredicto (vulnerability primero), enlazando a cada informe de vulnerabilidad y entrada minimizada
  • Mapa de calor de crashes — cuadrícula por-(harness × iteración) de recuentos de crashes, la opacidad escala con el recuento
  • Línea de tiempo de iteraciones — feed cronológico de notas de una línea escritas por el agente que describen qué cambió en cada iteración
  • Funciones principales no cubiertas — contraídas por defecto

API JSON

El panel también expone una pequeña API JSON de solo lectura para scripts:```bash

All known repos

curl http://127.0.0.1:8765/api/json

Per-repo: harnesses, per-iteration coverage, crashes with verdicts

curl 'http://127.0.0.1:8765/api/json?repo=kkos/oniguruma' | jq .

root@kitploit:~
---

## Archivos de salida

Todos bajo `~/.local/share/seclab-taskflow-agent/seclab-taskflows/`.

| Ruta | Contenido |
|------|----------|
| `fuzz_context/fuzz_context.db` | SQLite — objetivos, harnesses, ejecuciones, cobertura, crashes, veredictos, grafos de llamadas, sugerencias de harness, notas de iteración |
| `fuzz_runner/builds/` | Binarios `.afl` y `.cov` compilados |
| `fuzz_runner/runs/` | Directorios de salida de AFL + archivos LCOV + informes de cobertura HTML |
| `fuzz_runner/corpus/harness_<id>/` | Corpus persistente por harness (se mantiene entre iteraciones y campañas) |
| `fuzz_runner/repo/<owner>__<repo>/REPORT.md` | Resumen de campaña en Markdown, crashes agrupados por veredicto |
| `fuzz_runner/repo/<owner>__<repo>/vuln_<crash_id>.md` | Informe de vulnerabilidad en Markdown por crash |
| `fuzz_runner/repo/<owner>__<repo>/call_graph.{dot,svg,md}` | Grafo de llamadas estático + superposición de alcanzadas/no alcanzadas |

---

## Esquema de la base de datos

Tablas en `fuzz_context.db` (SQLite vía SQLAlchemy):

| Tabla | Columnas de interés |
|-------|--------------------|
| `fuzz_target` | `repo, file, function, signature, input_kind` |
| `harness` | `target_id, repo, harness_path, afl_binary_path, cov_binary_path, build_status, version, sanitizers` |
| `seed_corpus` | `target_id, source, path, bytes_count, added_in_iteration` |
| `fuzz_run` | `harness_id, iteration_number, exec_per_sec, paths_total, crashes_count, status, output_dir, started_at, ended_at` |
| `coverage_report` | `run_id, lines_total, lines_hit, line_pct, fns_*, branches_*, lcov_path, html_path` |
| `coverage_gap` | `report_id, file, function, line, kind, reason_hint` |
| `crash` | `run_id, input_blob_path, minimized_path, stack_top_hash, sanitizer_output, verdict, bug_class, cwe, severity, vuln_report_path, reproducer_path, classification, notes` |
| `call_graph` | `repo, target_id, dot_path, svg_path, functions_total, functions_in_graph, functions_reached, functions_unreached, untouched_surface_json` |
| `harness_suggestion` | `repo, function_name, file, rationale, input_kind, priority` |
| `iteration_note` | `repo, harness_id, iteration_number, note, created_at` |

Las migraciones del esquema residen en `_migrate()` en `fuzz_context.py`. Las nuevas TABLAS se crean automáticamente mediante `Base.metadata.create_all()`; solo las nuevas COLUMNAS necesitan `ALTER TABLE` basado en PRAGMA.

---

## Herramientas MCP (el vocabulario del agente)

El agente nunca llama directamente a AFL o clang — compone el pipeline llamando a herramientas MCP. El conjunto completo, agrupado por propósito:

### Persistencia (`fuzz_context.py`)

- `store_fuzz_target`, `get_fuzz_targets`
- `store_harness`, `update_harness_build`, `get_harnesses`
- `store_seed`, `start_fuzz_run`, `finish_fuzz_run`, `get_fuzz_runs`
- `store_coverage_from_lcov`, `get_coverage_summary`, `get_coverage_gaps`,
  `coverage_plateau_reached`
- `store_crash`, `update_crash_verdict`, `get_crashes`,
  `get_crashes_grouped`, `suggest_severity`
- `store_call_graph`, `get_call_graphs`, `get_repo_reached_functions`
- `store_harness_suggestion`, `get_harness_suggestions`
- `store_iteration_note`, `get_iteration_notes`

### Compilación / fuzzing / cobertura (`fuzz_runner.py`)

- `check_tooling`, `workspace_paths`
- `compile_harness` — compila los binarios `.afl` y `.cov`
- `run_afl_for`, `cmin`, `tmin`, `replay_under_asan`, `reproduce_crash`
- `run_coverage` — reproduce la cola de AFL contra el binario `.cov`, exporta LCOV
- `extract_dictionary` — extrae cadenas imprimibles de un binario
- `package_reproducer` — empaqueta un `.tgz` de un solo crash

### Corpus persistente (v8)

- `get_persistent_corpus_dir`, `fold_queue_into_persistent_corpus`

### Recursos de formato (C5)

- `list_format_assets`, `get_format_dictionary`, `write_format_mutator`

### Mutador inteligente + diccionario consciente del proyecto

- `generate_smart_mutator`, `generate_smart_mutators`
- `generate_project_dictionary`, `enrich_dictionary_from_uncovered`

Las funciones de las herramientas están decoradas con `@mcp.tool()` (FastMCP). Dentro de las pruebas, invócalas mediante el atributo `.fn`, p. ej.
`fr.run_afl_for.fn(afl_binary_path=..., ...)`.

---

## Parámetros ajustables (variables de entorno)

| Variable | Valor predeterminado | Propósito |
|----------|---------|---------|
| `HARNESS_CANDIDATES` | `1` | Número de harnesses candidatos escritos por objetivo. Establécelo en 2 o 3 para una competencia al estilo OSS-Fuzz-Gen. La etapa de calificación ejecuta cada uno durante `QUALIFIER_SECONDS` y conserva el mejor por % de líneas. |
| `QUALIFIER_SECONDS` | `60` | Presupuesto de tiempo real por candidato en la etapa de calificación. |
| `FUZZ_PLATEAU_THRESHOLD_PCT` | `1.0` | Ganancia de cobertura de líneas (en pp absolutos) por debajo de la cual dos iteraciones consecutivas se consideran una meseta y el bucle se detiene anticipadamente. |
| `FUZZ_DASHBOARD_PORT` | `8765` | Puerto para el panel en vivo. |
| `FUZZ_NO_DASHBOARD` | (sin establecer) | Establécelo en `1` para omitir el inicio del panel. |
| `FUZZ_RUNNER_TIMEOUT` | `1200` | Tiempo de espera del subproceso por herramienta en `fuzz_runner` (segundos). |
| `LOCAL_SHELL_TIMEOUT` | `180` | Tiempo de espera por comando en `local_shell` (segundos). |

Además de las variables estándar del agente (`COPILOT_TOKEN`, `LOG_DIR`,
`FUZZ_CONTEXT_DIR`, …). Consulta el README raíz del proyecto para la lista completa.

---

## Extender el pipeline

### Añadir un nuevo formato (mutador + diccionario)

1. Coloca `dictionaries/<name>.dict` (formato `-x` de AFL) y/o
   `dictionaries/<name>_mutator.c` (mutador personalizado de libFuzzer).
2. Regístralo en `_FORMAT_ASSETS` al final de `fuzz_runner.py`:   ```python
   "<name>": {
       "dictionary": "<name>.dict",
       "mutator": "<name>_mutator.c",
       "description": "Short one-liner about the format",
   },
  1. El agente lo recogerá automáticamente a través de list_format_assets().

Añadir una nueva herramienta MCP

  1. Añade una función decorada con @mcp.tool() en fuzz_context.py (para persistencia) o fuzz_runner.py (para trabajo en subprocesos).
  2. Usa Annotated[type, Field(description=...)] para cada argumento — la descripción es lo que ve el LLM.
  3. Añade una prueba unitaria en tests/test_fuzz_context.py / tests/test_fuzz_runner.py. Invoca la herramienta a través de su atributo .fn (convención de FastMCP).
  4. Referencia la nueva herramienta en el user_prompt del YAML del taskflow correspondiente.

Añadir una nueva etapa del pipeline

  1. Crea un nuevo YAML en src/seclab_taskflows/taskflows/fuzzing/. Usa uno de los archivos existentes (p. ej. triage_crashes.yaml) como plantilla.
  2. Conéctalo en scripts/fuzzing/run_fuzzing.sh entre las dos etapas existentes correctas.
  3. (Opcional) añade una sección de dashboard específica de la etapa en scripts/fuzzing/dashboard.py.

Migración de esquema

Al añadir una nueva tabla SQL:

  • Añade el modelo SQLAlchemy en fuzz_context_models.py.
  • No se necesita nada más — Base.metadata.create_all() se llama en la inicialización del motor y crea las nuevas tablas automáticamente.

Al añadir una nueva COLUMNA a una tabla existente:

  • Actualiza el modelo SQLAlchemy.
  • Añade un bloque PRAGMA table_info + ALTER TABLE ADD COLUMN en _migrate() en fuzz_context.py para que las bases de datos antiguas se actualicen de forma transparente.
  • Si el dashboard lee la columna, actualiza también _migrate_if_writable() en scripts/fuzzing/dashboard.py.

Proyectos de referencia y resultados

benchmark/projects.yaml enumera los proyectos de referencia. Se eligen para que el pipeline completo v4+ pueda ejecutarse de principio a fin en una imagen de desarrollo de codespace sin intervención humana.

#RepoPor qué es interesanteNotas
1tukaani-project/xzBiblioteca del mundo real con mucho análisis sintáctico (liblzma); rica cadena de filtros + superficie de análisis de enteros/VLILínea base
2DaveGamble/cJSONPequeño analizador JSON en C de un solo archivo; CMake trivialPrueba rápida para el pipeline
3akheron/janssonBiblioteca JSON en C compacta con punto de entrada documentado json_loadb() para búfer de bytesCMake; ejecuciones/seg muy rápidas
4libexpat/libexpatAnalizador XML en streaming maduro; muchos CVE históricosCMake o autotools
5kkos/onigurumaMotor de regex; recibe patrón del atacante + sujetoAutotools; la compilación del patrón es la ruta crítica

Números de referencia de una ejecución completa del pipeline v4 en la imagen de desarrollo de codespace (≈32 min/objetivo):

RepoObjetivosArnesesEjecuciones de AFLCrashesVeredictos
tukaani-project/xz88480—
DaveGamble/cJSON66360—
akheron/jansson773510harness_bug, library_hardening, duplicate, needs_investigation
libexpat/libexpat33180—
kkos/oniguruma10106013vulnerability (×2 lectura fuera de límites en regerror.c), library_hardening, harness_bug, non_reproducible

Los resultados de cero crashes de xz / cJSON / libexpat son esperados: esos proyectos reciben mucho fuzzing upstream. Los dos hallazgos clasificados como vulnerability en oniguruma son lecturas fuera de límites reales en la ruta de código de formateo de advertencias de onig_snprintf_with_pattern (lectura de un byte más allá de pat_end cuando el patrón termina con una barra invertida); los informes markdown por crash incluyen parches sugeridos.

Para añadir un nuevo proyecto de referencia, añade una entrada en benchmark/projects.yaml y (opcionalmente) documenta el motivo en benchmark/README.md. Cualquier cosa que la etapa existente analyze_build_system pueda compilar con clang + flags de AFL++ es un candidato razonable. Los analizadores, decodificadores y serializadores en C puro suelen funcionar mejor.


Limitaciones y advertencias

  • Solo C / C++. AFL++ es un fuzzer de instrumentación nativa.
  • Dependiente del sistema de compilación. Los proyectos con sistemas de compilación no triviales (reglas Bazel personalizadas, libc vendorizada, herramientas de compilación propietarias) pueden fallar al compilar con flags de clang/AFL. El agente marca esos objetivos como BUILD_FAILED: y los omite.
  • Advertencias de AFL en Codespace. AFL++ requiere kernel.core_pattern=core y un ajuste del gobernador de CPU. En un Codespace no están disponibles, por lo que el taskflow exporta AFL_SKIP_CPUFREQ=1 y AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 por defecto. AFL imprime advertencias pero sigue encontrando crashes mediante el manejo de abortos al estilo libFuzzer.
  • Limitado por el modelo. La calidad de escritura de arneses del agente está limitada por la comprensión del código objetivo por parte del modelo subyacente.
  • Empalme de corpus del mutador inteligente solo en POSIX. La operación de empalme de corpus usa <dirent.h>. Bien para Linux/macOS; no compilaría en Windows.
  • Advertencia sobre el modo stdin. Los binarios de AFL compilados mediante compile_harness usan libAFLDriver en modo argv. Por lo tanto, replay_under_asan y tmin usan stdin_input=False por defecto porque libAFLDriver entra en bucle infinito cuando se controla mediante stdin.
  • generate_smart_mutator + generate_smart_mutators usan .format() de Python — cada { / } literal en la plantilla de C debe duplicarse ({{ / }}). Si editas la plantilla y empiezas a ver KeyError, ese es el motivo.

Advertencia de seguridad

Este taskflow ejecuta afl-fuzz, clang, llvm-cov, y comandos de compilación arbitrarios elegidos por el LLM, directamente en el host (sin contenedor). Un agente con inyección de prompt podría en principio hacer cualquier cosa que tu usuario pueda. Ejecuta solo:

  • dentro de entornos desechables (GitHub Codespaces, VMs temporales, etc.),
  • sin privilegios elevados,
  • con acceso de red limitado a lo que necesiten git, apt y el sistema de compilación.

La caja de herramientas local_shell NO está detrás de un prompt de confirmación — el taskflow es autónomo y se ejecuta sin un humano en el bucle, por lo que una confirmación interactiva simplemente se bloquearía para siempre. Cada comando de shell se registra en $LOG_DIR/mcp_local_shell.log para su revisión a posteriori.


Desarrollo: pruebas, linting, contribución```bash

Run the test suite (Python 3.11+ required by hatch-test envs)

hatch test

Run the linter

hatch fmt --linter --check

Auto-fix lint issues

hatch fmt --linter

Lint a single file

hatch fmt --linter --check -- src/seclab_taskflows/mcp_servers/fuzz_runner.py

root@kitploit:~
Convenciones del código base (véase también `benchmark/improvements.md` para la versión de estas según el historial de la campaña):

- Use `os.environ.get(NAME) or "default"` en lugar de
  `os.environ.get(NAME, "default")`. De lo contrario, se devolverían cadenas vacías
  procedentes de la sustitución de plantillas YAML.
- Use `X | None` (PEP 604) en las nuevas anotaciones, no `Optional[X]`.
- Las pruebas invocan las herramientas MCP mediante `.fn(...)`, no directamente el nombre decorado.
- Evite los literales `/tmp/...` en las pruebas — use el fixture `tmp_path` de pytest
  (regla de lint `S108`).
- Todas las importaciones en línea dentro de los métodos de prueba necesitan `# noqa: PLC0415` si
  no puede moverlas al principio del archivo (por ejemplo, cuando se importan condicionalmente
  después de un `pytest.skip`).
- Una sola aserción por línea para pruebas de verdad compuestas (regla de lint `PT018`).

El registro de mejoras (`benchmark/improvements.md`) es el log persistente
de lo que se ha añadido al pipeline a lo largo de las versiones. Cuando añada una
característica sustancial, agregue una sección allí describiendo qué cambió, dónde
reside y qué pruebas la protegen.

---

## Glosario

- **AFL++** — Fuzzer greybox guiado por cobertura; el motor de ejecución aquí.
- **libAFLDriver** — Biblioteca estática que permite a los arneses de AFL++ usar
  la convención de punto de entrada de libFuzzer (`LLVMFuzzerTestOneInput`).
- **LCOV** — Formato estándar de la industria para archivos de traza de cobertura. Exportamos a él
  mediante `llvm-cov export -format=lcov` y lo analizamos nosotros mismos.
- **`stack_top_hash`** — Un hash de 16 caracteres de los N marcos superiores normalizados de
  una traza de pila de ASan/UBSan. Se usa para la deduplicación de fallos.
- **Corpus persistente** — Directorio por arnés en
  `<workspace>/corpus/harness_<id>/` que conserva las entradas interesantes de AFL
  a través de iteraciones y re-ejecuciones de la misma campaña.
- **Mutador inteligente** — Un `LLVMFuzzerCustomMutator` cuyos tokens de empalme se
  extraen del propio código fuente del objetivo (`generate_smart_mutator`).
- **Mutador personalizado (libFuzzer)** — Una función C proporcionada por el usuario invocada por
  el motor con total libertad sobre cómo mutar un búfer; AFL++ admite
  la misma ABI.
- **Herramienta MCP** — Una función decorada con FastMCP que el agente LLM puede invocar.
- **OSS-Fuzz / Fuzz-Introspector** — La infraestructura de fuzzing de código abierto de Google
  y su herramienta complementaria de análisis de grafo de llamadas/cobertura.
  Varias de las características de este taskflow (mutadores por formato, deduplicación por pila,
  informe de grafo de llamadas + API no tocada, arneses multi-candidato) están
  inspiradas en ellas.

---

## Licencia

Este proyecto está licenciado bajo los términos de la licencia de código abierto MIT. Consulte el archivo [LICENSE](https://github.com/githubsecuritylab/seclab-taskflows-fuzzing/blob/main/LICENSE.txt) para conocer los términos completos.

## Mantenedores

Consulte [CODEOWNERS](https://github.com/githubsecuritylab/seclab-taskflows-fuzzing/blob/main/CODEOWNERS) o póngase en contacto con el equipo de GitHub Security Lab.

## Soporte

Consulte [SUPPORT.md](https://github.com/githubsecuritylab/seclab-taskflows-fuzzing/blob/main/SUPPORT.md) para obtener detalles sobre cómo obtener ayuda con este proyecto.

## Agradecimientos

Este proyecto se basa en los conceptos y técnicas de [AFL++](https://github.com/AFLplusplus/AFLplusplus), [OSS-Fuzz](https://github.com/google/oss-fuzz) y [Fuzz-Introspector](https://github.com/ossf/fuzz-introspector).
Descargar herramienta