خط أنابيب اختبار تشويش مدفوع بنموذج لغوي كبير (LLM) يعمل بواسطة وكيل Taskflow من GitHub Security Lab
خط أنابيب fuzzing مدفوع بنماذج اللغة الكبيرة (LLM) بأسلوب OSS-Fuzz لمشاريع C/C++ الأصلية. AFL++ للتنفيذ، وclang+lcov للتغطية، ووكيل LLM لكتابة الـ harness، وقرارات التغذية الراجعة للتغطية، والفرز، وإعداد التقارير.
يحتوي هذا المستودع على fuzzing taskflow الخاص بـ
GitHub Security Lab Taskflow Agent.
يعتمد على المستودع المرافق
seclab-taskflows
لبعض اللبنات المشتركة
(taskflow الخاص بـ fetch_source_code، وصناديق أدوات local_file_viewer / gh_file_viewer،
وmodel_config الافتراضي) — ويتم تثبيت تلك تلقائيًا
كاعتمادية Python.
المساهمات مرحّب بها! يُرجى الاطلاع على للإرشادات.
aptgh)pip install git+https://github.com/GitHubSecurityLab/seclab-taskflows-fuzzing
يستدعي هذا الحزمتين `seclab-taskflow-agent` و `seclab-taskflows` (الحزمة الأم)
بشكل تتابعي، لذا فإن كل إشارة نقطية بالصيغة
`seclab_taskflows.taskflows.audit.*`،
`seclab_taskflows.toolboxes.local_file_viewer`،
`seclab_taskflows.toolboxes.gh_file_viewer`، و
`seclab_taskflows.configs.model_config` تُحلّ من توزيعة الحزمة الأم
عند التشغيل.
---
## جدول المحتويات
1. [ما هذا](#what-this-is)
2. [البدء السريع](#quick-start)
3. [البنية](#architecture)
4. [خط الأنابيب، مرحلة بمرحلة](#the-pipeline-stage-by-stage)
5. [حلقة تغذية راجعة للتغطية](#the-coverage-feedback-loop)
6. [التهيئة الواعية بالبنية](#structure-aware-fuzzing)
7. [مجموعة مدخلات دائمة عبر التكرارات والحملات](#persistent-corpus-across-iterations-and-campaigns)
8. [الفرز وتقارير الثغرات](#triage-and-vulnerability-reports)
9. [لوحة المعلومات الحية](#live-dashboard)
10. [ملفات المخرجات](#output-files)
11. [مخطط قاعدة البيانات](#database-schema)
12. [أدوات MCP (مفردات الوكيل)](#mcp-tools-the-agents-vocabulary)
13. [المقابض القابلة للضبط (متغيرات البيئة)](#tunable-knobs-environment-variables)
14. [توسيع خط الأنابيب](#extending-the-pipeline)
15. [مشاريع القياس والنتائج](#benchmark-projects-and-results)
16. [القيود والمزالق](#limitations-and-gotchas)
17. [تحذير أمني](#security-warning)
18. [التطوير: الاختبار، التدقيق، المساهمة](#development-testing-linting-contributing)
19. [المصطلحات](#glossary)
---
## ما هذا
هذا الـ taskflow هو خط أنابيب تهيئة (fuzzing) مستقل بالكامل. عند إعطائه مستودع GitHub
لمشروع أصلي بلغة C/C++، فإنه سيقوم بما يلي:
1. تثبيت AFL++ + clang/llvm/lcov + ctags/cscope/graphviz إذا كانت مفقودة،
2. جلب المصدر،
3. تحديد أهداف التهيئة المرشحة (المحللات، المفككات، المدققات، …)،
4. تحليل نظام البناء،
5. كتابة مرشح واحد أو أكثر من الـ harness لكل هدف، وبناء كل منها كملف ثنائي `.afl`
مُجهّز بـ AFL وملف ثنائي `.cov` مُجهّز بالتغطية،
6. (اختياريًا) تأهيل المرشحين عبر تغطية مدتها 60 ثانية والاحتفاظ بالأفضل،
7. تشغيل حلقة تهيئة/تغطية/تحسين مع مضاعفة ميزانيات الوقت،
8. فرز كل انهيار، والتأكد من أن الانهيارات المعروفة سابقًا لا تزال قابلة لإعادة الإنتاج، و
كتابة تقارير ثغرات markdown لكل انهيار مع الأحكام، وقابلية الاستغلال،
والتصحيحات المقترحة، ومخططات اختبارات الانحدار،
9. بناء رسم بياني للاستدعاءات بأسلوب Fuzz-Introspector + تقرير واجهات API غير الملموسة
للحملة التالية،
10. نشر كل شيء على لوحة معلومات HTML حية.
خط الأنابيب هذا **بأسلوب OSS-Fuzz** من حيث الروح: فهو يستخدم العديد من
التقنيات نفسها (مُحوّلات ومفردات خاصة بكل صيغة، ولصق رموز واعٍ بالبنية،
وتحسينات harness مدفوعة بالتغطية، وتقارير قابلة للقراءة آليًا،
وانهيارات مُزالة التكرار ومُجزّأة حسب المكدس) لكنه أصغر بكثير ومكتفٍ ذاتيًا.
---
## البدء السريع```bash
# Inside the codespace (or a host with python + git available):
./scripts/fuzzing/run_fuzzing.sh tukaani-project/xz
هذه هي الواجهة بأكملها. السكربت مستقل؛ سيقوم بتثبيت AFL++
عند التشغيل الأول، ثم يدير بقية سير المهام. تُكتب ملفات الإخراج
إلى ~/.local/share/seclab-taskflow-agent/seclab-taskflows/.
تبدأ لوحة المعلومات تلقائيًا في الخلفية؛ في Codespace، يتم
تمرير المنفذ 8765 تلقائيًا — افتحه في أي متصفح لمشاهدة التقدم مباشرة.
لإجراء اختبار سريع، استخدم هدفًا صغيرًا:```bash ./scripts/fuzzing/run_fuzzing.sh DaveGamble/cJSON
## البنية المعمارية
ثلاث طبقات، من الأعلى إلى الأسفل:```
┌────────────────────────────────────────────────────────────────────┐
│ 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 │
└────────────────────────────────────────────────────────────────────┘
قواعد التصميم الأساسية:
fuzz_context.db.run_afl_for، compile_harness، store_crash، إلخ.afl-clang-lto -fsanitize=address,undefined (ثنائية .afl) ومرة
بـ clang -fprofile-instr-generate -fcoverage-mapping (ثنائية .cov).
ثنائية .afl تُجرى الاختبار العشوائي؛ وثنائية .cov تُعيد تشغيل قائمة انتظار AFL
لإنتاج تغطية حقيقية لأسطر المصدر/الدوال/الفروع.| # | المرحلة | Taskflow YAML |
|---|---|---|
| 1 | تثبيت AFL++ + الأدوات | scripts/fuzzing/install_afl.sh |
| 2 | جلب المصدر | seclab_taskflows.taskflows.audit.fetch_source_code |
| 3 | تحديد أهداف الاختبار العشوائي | seclab_taskflows_fuzzing.taskflows.fuzzing.identify_fuzz_targets |
| 4 | تحليل نظام البناء | seclab_taskflows_fuzzing.taskflows.fuzzing.analyze_build_system |
| 5a | كتابة الـ harnesses الأولية (×N مرشحاً إذا طُلب) | seclab_taskflows_fuzzing.taskflows.fuzzing.write_initial_harnesses |
| 5b | بناء الـ harnesses (AFL + التغطية) | seclab_taskflows_fuzzing.taskflows.fuzzing.build_harnesses |
| 5c | تأهيل المرشحين (عندما HARNESS_CANDIDATES > 1) | seclab_taskflows_fuzzing.taskflows.fuzzing.qualify_harnesses |
| 6 | حلقة الاختبار العشوائي/التغطية/التحسين (×N تكراراً) | seclab_taskflows_fuzzing.taskflows.fuzzing.fuzz_iteration |
| 7 | فرز الأعطال | seclab_taskflows_fuzzing.taskflows.fuzzing.triage_crashes |
| 8 | تأكيد أن الأعطال المعروفة سابقاً لا تزال قابلة لإعادة الإنتاج | seclab_taskflows_fuzzing.taskflows.fuzzing.confirm_fixed_crashes |
| 9 | بناء مخطط الاستدعاء + تقرير واجهات API غير الملموسة | seclab_taskflows_fuzzing.taskflows.fuzzing.analyze_call_graph |
| 10 | كتابة تقارير الثغرات لكل عطل | seclab_taskflows_fuzzing.taskflows.fuzzing.write_vuln_reports |
| 11 | كتابة تقرير الحملة | seclab_taskflows_fuzzing.taskflows.fuzzing.write_report |
كل مرحلة هي Taskflow YAML قائمة بذاتها يشغّلها الوكيل
من البداية إلى النهاية. تتواصل المراحل حصرياً عبر قاعدة بيانات SQLite
في fuzz_context.db — لا يوجد تسليم في الذاكرة.
هذا هو قلب خط الأنابيب. ميزانيات الوقت تتضاعف كل تكرار:``` 30s → 60s → 120s → 240s → 480s → 960s (≈ 32 min/target)
في كل تكرار، ولكل أداة تشغيل، يقوم الوكيل بما يلي:
1. يطلب `get_persistent_corpus_dir(harness_id)` للحصول على دليل المجموعة
المستقر الخاص بهذه الأداة.
2. يستدعي `run_afl_for(afl_binary_path, seed_dir=<persistent corpus>,
output_dir=<run dir>, seconds=<budget>, dictionary=<auto.dict>)`.
3. يستدعي `run_coverage(cov_binary_path, inputs_dir=<run>/default/queue,
output_dir=<run>/coverage)` لإنتاج ملف تتبع LCOV وتقرير HTML.
4. يستدعي `store_coverage_from_lcov(run_id, lcov_path, html_path)` لحفظ
صف `coverage_report` + صفوف `coverage_gap` لكل عنصر غير مغطى.
5. يستدعي `fold_queue_into_persistent_corpus(...)` لدمج قائمة انتظار تكرار
AFL في المجموعة المستمرة وتشغيل `cmin` للحفاظ على حجم محدود.
6. يقرأ `get_coverage_summary` + `get_coverage_gaps`، ثم إما:
- يضيف بذرة جديدة (موسومة بـ `coverage_feedback`) للوصول إلى فرع
غير مغطى،
- يعدّل مصدر الأداة لاستدعاء واجهة برمجية إضافية،
- يستدعي `enrich_dictionary_from_uncovered(...)` لإضافة إدخالات قاموس
تلقائيًا للثوابت السحرية التي يحتاجها AFL لتلبية شرط حارس، أو
- يتخطى الفجوة (مسار خطأ بارد / كود المورّد).
7. يستدعي `store_iteration_note(repo, iteration_number, harness_id, note=<one
line summary>)` بحيث يتتبع الجدول الزمني للتكرارات في لوحة المعلومات ما
تغيّر.
**كشف الهضبة.** تخرج الحلقة مبكرًا بمجرد أن يحقق تكراران متتاليان معًا < `FUZZ_PLATEAU_THRESHOLD_PCT` (الافتراضي `1.0`) نقطة مئوية مطلقة من تغطية الأسطر.
---
## التشويش المدرك للبنية
ثلاث آليات متكاملة تنتج مدخلات أقوى من تحوير البايتات الخام.
### 1. قواميس لكل صيغة + محوّرات مخصصة
للأهداف التي تطابق `input_kind` الخاصة بها صيغة معروفة، يوفّر taskflow
قواميس جاهزة وملفات مصدر C لـ `LLVMFuzzerCustomMutator`:
| الصيغة | القاموس | المحوّر | ملاحظات |
|--------|------------|---------|-------|
| `json` | `json.dict` | `json_mutator.c` | لصق الرموز، تكرار/إسقاط الأقواس المتوازنة، قلب النوع |
| `xml` | `xml.dict` | `xml_mutator.c` | الوسوم، الكيانات، DTDs، رموز billion-laughs |
| `regex` | `regex.dict` | `regex_mutator.c` | المراسي، الفئات، المكمّمات، أنماط ReDoS الحقيقية |
| `binary_tlv` | _(لا شيء)_ | `binary_tlv_mutator.c` | سجلات مسبوقة بالطول: تجاوز الطول / تكرار / إسقاط |
| `png` | `png.dict` | _(يعيد استخدام binary_tlv)_ | قاموس PNG + محوّر binary_tlv |
يتم التقاطها تلقائيًا بواسطة `write_initial_harnesses` (يُنسخ القاموس بجوار
البذور) و`build_harnesses` (يُربط المحوّر في ثنائي AFL). يفوّض كل محوّر 50%
من التحويرات إلى محوّر البايتات الافتراضي في AFL حتى لا نفقد عشوائية المحرك.
لإضافة صيغة جديدة: أضف `<name>.dict` و/أو `<name>_mutator.c` إلى
`src/seclab_taskflows/dictionaries/`، ثم سجّلها في خريطة
`_FORMAT_ASSETS` في أسفل `fuzz_runner.py`.
### 2. محوّر ذكي مدرك للمصدر (خاص بالمشروع)
للصيغ غير المألوفة، أو عندما تريد رموزًا أقوى خاصة بالمشروع، يفحص
`generate_smart_mutator` ملفات `.c`/`.h` الخاصة بالمستودع الهدف ويصدر ملف
C لـ `LLVMFuzzerCustomMutator` تُستخرج قواميس اللصق الخاصة به من:
- السلاسل النصية الحرفية التي تحتوي على ≥3 أحرف أبجدية (بعد تصفية ضوضاء
المترجم/الترخيص، والمسارات، والترويسات، وقيود asm، ومحددات التنسيق)،
- الثوابت الرقمية 32-بت من `#define` و`case` و`enum` (بعد تصفية ضوضاء
الأعداد الصحيحة الصغيرة العامة مثل 0، 1، 256، 0xff…).
تتوفر ثلاثة تركيزات:
| التركيز | ما يلصقه | متى تستخدمه |
|-------|-----------------|-------------|
| `strings` | السلاسل النصية الحرفية للمشروع فقط | الصيغ النصية (JSON، XML، YAML، CSV) |
| `constants` | قيم سحرية رقمية 32-بت فقط | البروتوكولات الثنائية، الترويسات ذات الأرقام السحرية |
| `combined` | كليهما | الافتراضي؛ عادةً الأفضل |
اقرن `generate_smart_mutators(...)` (بصيغة الجمع) مع `HARNESS_CANDIDATES >= 3`
بحيث يصبح كل تركيز أداة تشغيل مرشحة في جولة التأهيل.
### 3. قاموس AFL مدرك للمشروع + إثراء مدفوع بالتغطية
أداتان متكاملتان تبنيان وتنمّيان قاموس AFL `-x` مع تقدم الحملة:
- **`generate_project_dictionary(source_root, output_path)`** — يعمل مرة واحدة
قبل التكرار 1، ويستخرج بشكل ثابت نفس مجموعة رموز المصدر المستخدمة بواسطة
المحوّر الذكي ويكتبها كقاموس AFL. تُصدر الثوابت الرقمية بكلا ترتيبي
البايتين (endianness) حتى يتمكن المشوّش من تلبية
`memcmp(x, &magic, 4)` بغض النظر عن ترتيب بايتات المضيف.
- **`enrich_dictionary_from_uncovered(source_root, dictionary_path,
uncovered_locations)`** — يعمل بعد خطوة التغطية في كل تكرار، ويفحص
المصدر المحيط بحثًا عن حراس شرطية
(`strncmp/memcmp/strstr`، `case 0xN:`، `== 0xN`، `== 'X'`) بالقرب من
الأسطر غير المغطاة، ويُلحق أي رموز جديدة بالقاموس. عديم الأثر الجانبي:
لا يعيد إضافة إدخال موجود بالفعل.
### 4. عملية لصق المجموعة
عند تمرير `corpus_dir` إلى `generate_smart_mutator`، يحصل الكود C المولّد
أيضًا على عامل لصق المجموعة: عند الاستدعاء الأول يحمّل حتى 64 ملفًا من ذلك
الدليل (بحد أقصى 4 KiB لكل ملف)، ومنذ ذلك الحين يمكنه لصق مناطق فرعية
عشوائية من تلك الملفات في المدخل المحوّر. يمنح هذا المحوّر عاملًا بأسلوب
إعادة التركيب لا تؤديه آلية havoc الأساسية في AFL جيدًا. اقرنه مع
`get_persistent_corpus_dir(...)` بحيث تكون مكتبة اللصق "إعادة مزج ما اكتشفه
AFL بالفعل".
---
## المجموعة المستمرة عبر التكرارات والحملات
لكل أداة تشغيل دليل مجموعة مستقر في:```
<workspace>/corpus/harness_<id>/
هذا ما يستخدمه fuzz_iteration كـ seed_dir لـ run_afl_for (بدلاً
من <harness>/seeds). في نهاية كل تكرار،
fold_queue_into_persistent_corpus(...) يدمج قائمة انتظار التكرار الخاصة بـ AFL في
هذا الدليل ويشغّل afl-cmin لإبقائه محدوداً.
النتيجة: قائمة انتظار الأمس تنتقل إلى تشغيل اليوم وإلى إعادة التشغيل لنفس المشروع. إيقاف وإعادة تشغيل الحملة لا يفقد أي تقدم.
بعد انتهاء حلقة fuzz/coverage/improve، تعمل ثلاث مراحل تلقائياً:
triage_crashesلكل ملف انهيار في <run>/default/crashes/:
afl-tmin لتصغير المدخل،replay_under_asan لالتقاط تتبع المكدس و stack_top_hash
(أعلى N إطارات مُطبَّعة؛ تُزال القوالب، ومساحات الأسماء المضمنة في libcxx، ومساحات
الأسماء المجهولة، واللواحق الرقمية لـ LTO بحيث تُجزَّأ الانهيارات
المتطابقة دلالياً بشكل متطابق)،crash مع تصنيف فئة الخطأ +
ملاحظة الثقة (عالية / متوسطة / منخفضة).confirm_fixed_crashesيعيد تشغيل كل انهيار مصنَّف سابقاً (الذي لم يكن حكمه بالفعل
fixed/duplicate/non_reproducible) عبر ثنائي AFL+ASan الحالي.
إذا لم يعد ينهار، يضع علامة verdict="fixed". مفيد عند إعادة تشغيل
حملة ضد مشروع طُبِّقت عليه إصلاحات من المنبع منذ
الحملة الأخيرة.
write_vuln_reportsلكل انهيار فريد، يقرأ الوكيل مصدر الـ harness + مصدر الدالة المنهارة، ويتتبع سلسلة الاستدعاء من واجهة API العامة، ثم يعيّن أحد عشرة أحكام بأسلوب OSS-Fuzz ويكتب تقرير ثغرة بصيغة markdown:
| الحكم | المعنى |
|---|---|
vulnerability | حقيقي، قابل للاستغلال عبر واجهة API عامة |
library_hardening | خطأ حقيقي لكن لا يوجد مسار واقعي عبر واجهة API العامة؛ يجب أن تدافع المكتبة عن نفسها |
harness_bug | الخطأ في الـ harness الخاص بنا، وليس في المكتبة |
non_reproducible | إعادة التشغيل لا تعيد إنتاج الانهيار على المدخل المُصغَّر |
oom | نفاد الذاكرة؛ ثغرة فقط إذا كان الحجم القابل للتحكم من المهاجم غير محدود |
timeout | DoS عبر تضخم خوارزمي |
assertion_failure | تحقق assert()؛ تتفاوت الصلة الأمنية |
fixed | يُضبط بواسطة confirm_fixed_crashes: المدخل لم يعد يعيد الإنتاج |
duplicate | نفس السبب الجذري لانهيار آخر بتجزئة مكدس مختلفة |
needs_investigation | تعذّر التحديد؛ مُعلَّم للمراجعة البشرية |
يتضمن كل تقرير ثغرة:
تُشغَّل لوحة المعلومات تلقائياً في الخلفية بواسطة
run_fuzzing.sh. عطّلها بـ FUZZ_NO_DASHBOARD=1؛ تجاوز المنفذ
بـ FUZZ_DASHBOARD_PORT (الافتراضي 8765).
في Codespace، يُعاد توجيه المنفذ 8765 تلقائياً — افتح عنوان URL المُعاد توجيهه في
أي متصفح. تُحدَّث الصفحة تلقائياً كل 5 ثوانٍ وتعرض:
fuzz_run قيد التنفيذvulnerability أولاً)، مع روابط
لكل تقرير ثغرة ومدخل مُصغَّرتكشف لوحة المعلومات أيضاً عن JSON API صغير للقراءة فقط للسكربتات:```bash
curl 'http://127.0.0.1:8765/api/json?repo=kkos/oniguruma' | jq .
---
## ملفات الإخراج
جميعها تحت `~/.local/share/seclab-taskflow-agent/seclab-taskflows/`.
| المسار | المحتويات |
|------|----------|
| `fuzz_context/fuzz_context.db` | SQLite — الأهداف، أدوات التغليف، التشغيلات، التغطية، الأعطال، الأحكام، الرسوم البيانية للاستدعاءات، اقتراحات أدوات التغليف، ملاحظات التكرار |
| `fuzz_runner/builds/` | ملفات `.afl` و `.cov` الثنائية المبنية |
| `fuzz_runner/runs/` | مجلدات إخراج AFL + ملفات LCOV + تقارير التغطية HTML |
| `fuzz_runner/corpus/harness_<id>/` | مجموعة مدخلات دائمة لكل أداة تغليف (تنتقل عبر التكرارات والحملات) |
| `fuzz_runner/repo/<owner>__<repo>/REPORT.md` | ملخص الحملة بصيغة Markdown، الأعطال مجمّعة حسب الحكم |
| `fuzz_runner/repo/<owner>__<repo>/vuln_<crash_id>.md` | تقرير ثغرة بصيغة Markdown لكل عطل |
| `fuzz_runner/repo/<owner>__<repo>/call_graph.{dot,svg,md}` | رسم بياني ثابت للاستدعاءات + طبقة تراكب للدوال التي تم الوصول إليها/لم يتم الوصول إليها |
---
## مخطط قاعدة البيانات
الجداول في `fuzz_context.db` (SQLite عبر SQLAlchemy):
| الجدول | الأعمدة ذات الأهمية |
|-------|--------------------|
| `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` |
توجد ترحيلات المخطط في `_migrate()` داخل `fuzz_context.py`. يتم إنشاء الجداول الجديدة تلقائيًا بواسطة `Base.metadata.create_all()`؛ فقط الأعمدة الجديدة تحتاج إلى `ALTER TABLE` القائم على PRAGMA.
---
## أدوات MCP (مفردات الوكيل)
لا يستدعي الوكيل AFL أو clang مباشرة أبدًا — بل يركّب خط الأنابيب من خلال استدعاء أدوات MCP. المجموعة الكاملة، مجمّعة حسب الغرض:
### الاستمرارية (`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`
### البناء / الفَزّ / التغطية (`fuzz_runner.py`)
- `check_tooling`, `workspace_paths`
- `compile_harness` — يبني ملفات `.afl` و `.cov` الثنائية
- `run_afl_for`, `cmin`, `tmin`, `replay_under_asan`, `reproduce_crash`
- `run_coverage` — يعيد تشغيل قائمة انتظار AFL مقابل الملف الثنائي `.cov`، ويصدّر LCOV
- `extract_dictionary` — يستخرج السلاسل النصية القابلة للطباعة من ملف ثنائي
- `package_reproducer` — يحزم عطلًا واحدًا في ملف `.tgz`
### مجموعة المدخلات الدائمة (v8)
- `get_persistent_corpus_dir`, `fold_queue_into_persistent_corpus`
### أصول التنسيقات (C5)
- `list_format_assets`, `get_format_dictionary`, `write_format_mutator`
### المُحوِّل الذكي + قاموس مدرك للمشروع
- `generate_smart_mutator`, `generate_smart_mutators`
- `generate_project_dictionary`, `enrich_dictionary_from_uncovered`
دوال الأدوات مزخرفة بـ `@mcp.tool()` (FastMCP). داخل الاختبارات، استدعها عبر السمة `.fn`، مثل
`fr.run_afl_for.fn(afl_binary_path=..., ...)`.
---
## المقابض القابلة للضبط (متغيرات البيئة)
| المتغير | الافتراضي | الغرض |
|----------|---------|---------|
| `HARNESS_CANDIDATES` | `1` | عدد أدوات التغليف المرشحة المكتوبة لكل هدف. اضبطه على 2 أو 3 لمنافسة على نمط OSS-Fuzz-Gen. تشغّل مرحلة التأهيل كل واحدة لمدة `QUALIFIER_SECONDS` وتحتفظ بالأفضل حسب نسبة الأسطر %. |
| `QUALIFIER_SECONDS` | `60` | الميزانية الزمنية لكل مرشح في مرحلة التأهيل. |
| `FUZZ_PLATEAU_THRESHOLD_PCT` | `1.0` | مكسب تغطية الأسطر (بالنقاط المئوية المطلقة) الذي إذا نزل تحته تكراران متتاليان يُعتبران هضبة ويتوقف الحلقة مبكرًا. |
| `FUZZ_DASHBOARD_PORT` | `8765` | المنفذ للوحة المعلومات المباشرة. |
| `FUZZ_NO_DASHBOARD` | (غير مضبوط) | اضبطه على `1` لتخطي بدء لوحة المعلومات. |
| `FUZZ_RUNNER_TIMEOUT` | `1200` | المهلة الزمنية لكل عملية فرعية لكل أداة في `fuzz_runner` (بالثواني). |
| `LOCAL_SHELL_TIMEOUT` | `180` | المهلة الزمنية لكل أمر في `local_shell` (بالثواني). |
بالإضافة إلى متغيرات الوكيل القياسية (`COPILOT_TOKEN`, `LOG_DIR`,
`FUZZ_CONTEXT_DIR`, …). راجع README في جذر المشروع للقائمة الكاملة.
---
## توسيع خط الأنابيب
### إضافة تنسيق جديد (مُحوِّل + قاموس)
1. أضف `dictionaries/<name>.dict` (بصيغة AFL `-x`) و/أو
`dictionaries/<name>_mutator.c` (مُحوِّل مخصص لـ libFuzzer).
2. سجّله في `_FORMAT_ASSETS` في أسفل `fuzz_runner.py`: ```python
"<name>": {
"dictionary": "<name>.dict",
"mutator": "<name>_mutator.c",
"description": "Short one-liner about the format",
},
list_format_assets().@mcp.tool() في fuzz_context.py (للاستمرارية) أو fuzz_runner.py (لعمل العمليات الفرعية).Annotated[type, Field(description=...)] لكل وسيط — الوصف هو ما يراه LLM.tests/test_fuzz_context.py / tests/test_fuzz_runner.py. استدعِ الأداة عبر سمة .fn الخاصة بها (اصطلاح FastMCP).user_prompt الخاص بملف YAML لتدفق المهام ذي الصلة.src/seclab_taskflows/taskflows/fuzzing/. استخدم أحد الملفات الموجودة (مثل triage_crashes.yaml) كقالب.scripts/fuzzing/run_fuzzing.sh بين المرحلتين المناسبتين من المراحل الموجودة.scripts/fuzzing/dashboard.py.عند إضافة جدول SQL جديد:
fuzz_context_models.py.Base.metadata.create_all() عند تهيئة المحرك وينشئ الجداول الجديدة تلقائيًا.عند إضافة عمود جديد إلى جدول موجود:
PRAGMA table_info + ALTER TABLE ADD COLUMN في _migrate() في fuzz_context.py حتى يتم ترقية قواعد البيانات القديمة بشفافية._migrate_if_writable() في scripts/fuzzing/dashboard.py.يسرد benchmark/projects.yaml المشاريع المرجعية. تم اختيارها بحيث يمكن تشغيل خط الأنابيب الكامل v4+ من البداية إلى النهاية على صورة تطوير codespace دون تدخل بشري.
| # | المستودع | لماذا هو مثير للاهتمام | ملاحظات |
|---|---|---|---|
| 1 | tukaani-project/xz | مكتبة كثيفة المحللات في العالم الحقيقي (liblzma)؛ سلسلة مرشحات غنية + سطح تحليل عدد صحيح/VLI | خط الأساس |
| 2 | DaveGamble/cJSON | محلل JSON بلغة C صغير أحادي الملف؛ CMake بسيط | فحص سريع لخط الأنابيب |
| 3 | akheron/jansson | مكتبة JSON بلغة C مدمجة مع نقطة دخول موثقة json_loadb() لمخزن البايتات | CMake؛ سرعة تنفيذ عالية جدًا |
| 4 | libexpat/libexpat | محلل XML تدفقي ناضج؛ العديد من ثغرات CVE التاريخية | CMake أو autotools |
| 5 | kkos/oniguruma | محرك تعبيرات نمطية؛ يستقبل نمط المهاجم والموضوع | Autotools؛ تجميع الأنماط هو المسار الساخن |
أرقام مرجعية من تشغيل كامل لخط أنابيب v4 على صورة تطوير codespace (≈32 دقيقة/هدف):
| المستودع | الأهداف | أدوات الاختبار | تشغيلات AFL | الأعطال | الأحكام |
|---|---|---|---|---|---|
tukaani-project/xz | 8 | 8 | 48 | 0 | — |
DaveGamble/cJSON | 6 | 6 | 36 | 0 | — |
akheron/jansson | 7 | 7 | 35 | 10 | harness_bug، library_hardening، duplicate، needs_investigation |
libexpat/libexpat | 3 | 3 | 18 | 0 | — |
kkos/oniguruma | 10 | 10 | 60 | 13 | vulnerability (×2 قراءة خارج الحدود في regerror.c)، library_hardening، harness_bug، non_reproducible |
نتائج xz / cJSON / libexpat الخالية من الأعطال متوقعة: تلك المشاريع تخضع للاختبار المكثف في المنبع. النتائج المصنفة كـ vulnerability في oniguruma هي قراءات حقيقية خارج الحدود في مسار كود تنسيق التحذيرات في onig_snprintf_with_pattern (قراءة بايت واحد بعد pat_end عندما ينتهي النمط بشرطة مائلة عكسية)؛ تتضمن تقارير markdown لكل عطل تصحيحات مقترحة.
لإضافة مشروع معايير جديد، أضف مدخلًا إلى benchmark/projects.yaml و(اختياريًا) وثّق السبب في benchmark/README.md. أي شيء يمكن لمرحلة analyze_build_system الحالية بناؤه باستخدام clang + أعلام AFL++ هو مرشح معقول. تميل محللات C الصرفة، وفك الترميز، والمُسلسِلات إلى العمل بشكل أفضل.
BUILD_FAILED: على تلك الأهداف ويتخطاها.kernel.core_pattern=core وضبط حاكم المعالج. في Codespace هذه غير متاحة، لذا يُصدّر تدفق المهام AFL_SKIP_CPUFREQ=1 و AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 افتراضيًا. يطبع AFL تحذيرات لكنه لا يزال يجد الأعطال عبر معالجة الإجهاض بنمط libFuzzer.<dirent.h>. مناسب لـ Linux/macOS؛ لن يُترجم على Windows.compile_harness برنامج libAFLDriver في وضع argv. لذلك يعتمد replay_under_asan و tmin افتراضيًا على stdin_input=False لأن libAFLDriver يتكرر إلى ما لا نهاية عند تشغيله عبر stdin.generate_smart_mutator + generate_smart_mutators يستخدمان Python .format() — يجب مضاعفة كل { / } حرفي في قالب C ({{ / }}). إذا عدّلت القالب وبدأت ترى KeyError، فهذا هو السبب.يشغّل تدفق المهام هذا afl-fuzz و clang و llvm-cov، وأوامر بناء عشوائية يختارها LLM، مباشرة على المضيف (بدون حاوية). يمكن لوكيل مُحقَن بالتعليمات أن يفعل من حيث المبدأ أي شيء يستطيع مستخدمك فعله. شغّله فقط:
git و apt ونظام البناء.صندوق أدوات local_shell ليس خلف مطالبة تأكيد — تدفق المهام مستقل ويعمل دون وجود إنسان في الحلقة، لذا فإن التأكيد التفاعلي سيتوقف إلى الأبد. يتم تسجيل كل أمر shell في $LOG_DIR/mcp_local_shell.log للمراجعة اللاحقة.
hatch test
hatch fmt --linter --check
hatch fmt --linter
hatch fmt --linter --check -- src/seclab_taskflows/mcp_servers/fuzz_runner.py
اصطلاحات قاعدة الشيفرة (انظر أيضًا `benchmark/improvements.md` للحصول على نسخة سجل الحملة من هذه):
- استخدم `os.environ.get(NAME) or "default"` بدلًا من
`os.environ.get(NAME, "default")`. وإلا فسيتم إرجاع السلاسل الفارغة من
استبدال قالب YAML.
- استخدم `X | None` (PEP 604) في التعليقات التوضيحية الجديدة، وليس `Optional[X]`.
- تستدعي الاختبارات أدوات MCP عبر `.fn(...)`، وليس الاسم المزخرف مباشرةً.
- تجنّب استخدام القيم الحرفية `/tmp/...` في الاختبارات — استخدم fixture
`tmp_path` الخاص بـ pytest (قاعدة lint `S108`).
- جميع الاستيرادات المضمّنة داخل دوال الاختبار تحتاج إلى `# noqa: PLC0415` إذا
لم تتمكن من نقلها إلى أعلى الملف (مثلًا عند الاستيراد الشرطي
بعد `pytest.skip`).
- تأكيد واحد لكل سطر لاختبارات الصحة المركّبة (قاعدة lint `PT018`).
متتبّع التحسينات (`benchmark/improvements.md`) هو السجل الدائم
لما أُضيف إلى خط الأنابيب عبر الإصدارات. عند إضافة ميزة
جوهرية، أضف قسمًا هناك يصف ما تغيّر، وأين يقع،
وما الاختبارات التي تحميه.
---
## المصطلحات
- **AFL++** — مُشوّه رمادي الصندوق موجّه بالتغطية؛ محرّك التنفيذ هنا.
- **libAFLDriver** — مكتبة ثابتة تتيح لحاويات AFL++ استخدام
اصطلاح نقطة دخول libFuzzer (`LLVMFuzzerTestOneInput`).
- **LCOV** — صيغة ملف تتبّع التغطية المعيارية في المجال. نُصدّر إليها
عبر `llvm-cov export -format=lcov` ونحلّلها بأنفسنا.
- **`stack_top_hash`** — تجزئة من 16 حرفًا لأعلى N إطارًا مُطبّعًا من
تتبّع مكدّس ASan/UBSan. تُستخدم لإزالة تكرار الأعطال.
- **المدوّنة الدائمة** — دليل خاص بكل حاوية عند
`<workspace>/corpus/harness_<id>/` يحمل مدخلات AFL المثيرة للاهتمام
عبر التكرارات وإعادات تشغيل الحملة نفسها.
- **المُشوّه الذكي** — `LLVMFuzzerCustomMutator` تُستخرج رموز الربط الخاصة به
من الشيفرة المصدرية للهدف نفسه (`generate_smart_mutator`).
- **المُشوّه المخصّص (libFuzzer)** — دالة C يوفّرها المستخدم يستدعيها
المحرّك بحرية كاملة في كيفية تشويه المخزن المؤقت؛ ويدعم AFL++ نفس
واجهة ABI.
- **أداة MCP** — دالة مزخرفة بـ FastMCP يمكن لوكيل LLM استدعاؤها.
- **OSS-Fuzz / Fuzz-Introspector** — البنية التحتية للتشويش مفتوح المصدر
من Google وأداة تحليل الرسم البياني للاستدعاءات/التغطية المرافقة لها.
العديد من ميزات هذا التدفق (مُشوّهات لكل صيغة، إزالة التكرار حسب المكدّس،
تقرير الرسم البياني للاستدعاءات + واجهات API غير الملموسة، حاويات متعددة المرشحين)
مستوحاة منهما.
---
## الترخيص
هذا المشروع مرخّص بموجب شروط ترخيص MIT مفتوح المصدر. يُرجى الرجوع إلى ملف [LICENSE](https://github.com/githubsecuritylab/seclab-taskflows-fuzzing/blob/main/LICENSE.txt) للاطلاع على الشروط الكاملة.
## المشرفون
انظر [CODEOWNERS](https://github.com/githubsecuritylab/seclab-taskflows-fuzzing/blob/main/CODEOWNERS) أو تواصل مع فريق GitHub Security Lab.
## الدعم
انظر [SUPPORT.md](https://github.com/githubsecuritylab/seclab-taskflows-fuzzing/blob/main/SUPPORT.md) للحصول على تفاصيل حول كيفية الحصول على المساعدة بشأن هذا المشروع.
## الإقرار
يبني هذا المشروع على مفاهيم وتقنيات [AFL++](https://github.com/AFLplusplus/AFLplusplus)، و[OSS-Fuzz](https://github.com/google/oss-fuzz)، و[Fuzz-Introspector](https://github.com/ossf/fuzz-introspector).