
एलएलएम-संचालित बग खोज के लिए एक सीलबंद बेंचमार्क: 43 ओपन-सोर्स प्रोजेक्ट्स (C/C++/Java) में 77 चुनौतियाँ। प्रत्येक चुनौती एक उत्तर-मुक्त Docker इमेज है जिसमें इन-इमेज ग्रेडिंग होती है — कोई पैच, PoC या उत्तर कुंजी शामिल नहीं होती।
77 वास्तविक ज़ीरो-डे बग्स पर LLM-संचालित भेद्यता पुनरुत्पादन के लिए एक बेंचमार्क, 43 ओपन-सोर्स प्रोजेक्ट्स (C / C++ / Java) में।
प्रत्येक चुनौती एजेंट को केवल फ़ज़ हार्नेस (लक्ष्य) और भेद्य संशोधन पर प्रोजेक्ट स्रोत देती है — कोई पैच नहीं, कोई फिक्स कमिट नहीं, कोई लक्ष्य पंक्ति नहीं। एजेंट को एक ऐसा इनपुट खोजना होगा जो सैनिटाइज़र के अंतर्गत किसी दोष को फिर से ट्रिगर करे। हर ग्रेड निर्धारक (कोई LLM-जज नहीं) है और इमेज के भीतर और ऑफ़लाइन होता है: उम्मीदवार चैलेंज कंटेनर में बेक किए गए आधिकारिक सैनिटाइज़र-इंस्ट्रूमेंटेड हार्नेस से गुजरता है, और रन को एजेंट द्वारा ट्रिगर किए गए अलग-अलग क्रैश द्वारा स्कोर किया जाता है। कुछ भी मशीन से बाहर नहीं जाता और किसी सेवा को चालू होने की आवश्यकता नहीं है।
| चुनौतियाँ | प्रोजेक्ट्स | भाषाएँ | ग्रेडर |
|---|
| 77 एंड-टू-एंड | 43 | C · C++ · Java | निर्धारक — इमेज में, ऑफ़लाइन |
इमेज या इस रिपॉजिटरी में कुछ भी यह प्रकट नहीं करता कि बग क्या है — चुनौतियों का
नाम तटस्थ उपनाम (<project>-NN, जैसे avro-03) से रखा गया है, और उत्तर कुंजी
(PoC, अपेक्षित दोष, फिक्स्ड बिल्ड) किसी में नहीं है: यह अनुरक्षक के पास रहती है।
सभी 77 ब्राउज़ करें: tools/sealed/CHALLENGES.md।
git clone https://github.com/fuzzingbrain/FuzzingBrain-Bench
cd FuzzingBrain-Bench
python3 -m venv .venv && source .venv/bin/activate # अनुशंसित (और आवश्यक
# Debian/Ubuntu पर, PEP 668)
pip install -e . # Python ≥ 3.10 और Docker चाहिए
# अपनी मॉडल कुंजी(याँ) ./.env में डालें — हर रन पर स्वतः लोड होती हैं, export करने की ज़रूरत नहीं
cat > .env <<'EOF'
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
GEMINI_API_KEY=...
DEEPSEEK_API_KEY=sk-...
EOF
fb-bench list # 77 चुनौतियाँ (उपनाम से)
fb-bench models # समर्थित मॉडल + कौन सी कुंजियाँ लोड हैं
(./.env स्वतः पढ़ा जाता है; एक सादा export ANTHROPIC_API_KEY=... भी काम करता है।)
हर नए शेल में
source .venv/bin/activateफिर से करें। या venv छोड़करpip install --break-system-packages -e .चलाएँ (अनुशंसित नहीं)।
fb-bench run सार्वजनिक चैलेंज इमेज खींचता है, होस्ट पर एजेंट लूप चलाता है
(आपके मॉडल API को कॉल करके), और हर उम्मीदवार को उस इमेज के अंदर ग्रेड करता है —
कोई नेटवर्क नहीं, पहुँचने के लिए कुछ नहीं। केवल Docker + आपकी मॉडल कुंजी आवश्यक है, और
एक रन एजेंट द्वारा पाए गए अलग-अलग क्रैश को स्कोर करता है — एक क्रैश की पहचान उसका
सैनिटाइज़र दोष प्रकार और उसके शीर्ष स्टैक फ्रेम हैं, इसलिए बीस बार मारा गया वही दोष एक बार गिना जाता है।
डिफ़ॉल्ट
--arm apiको उपरोक्त के अलावा कुछ नहीं चाहिए।--arm codexऔर--arm claudecodeबैकएंड को अतिरिक्त विक्रेता CLI — वैकल्पिक चाहिए, अलग से इंस्टॉल किए जाते हैं (कभी भीpip install -e .का हिस्सा नहीं); §4 देखें।
# Claude परिवार (haiku सबसे सस्ता/तेज़ है; कठिन रनों के लिए opus/sonnet बदलें)
fb-bench run avro-03 --model claude-haiku-4-5
# GPT परिवार
fb-bench run avro-03 --model gpt-5.5
# Gemini परिवार
fb-bench run avro-03 --model gemini-3.1-pro-preview
# DeepSeek परिवार (OpenAI-संगत एंडपॉइंट; DEEPSEEK_API_KEY चाहिए)
fb-bench run avro-03 --model deepseek-v4-flash
मॉडल: claude-haiku-4-5 · claude-sonnet-4-6 · claude-opus-4-8 ·
gpt-5.5 · gpt-5.4 · gpt-5 · gemini-3.1-pro-preview · gemini-2.5-flash ·
deepseek-v4-pro · deepseek-v4-flash
(कोई भी कैटलॉग id --model के माध्यम से काम करता है; fb-bench models देखें)।
fb-bench run एक बग या कई, एक मॉडल या कई लेता है। एक एकल रन केवल आकार एक का
मैट्रिक्स है, इसलिए कोई अलग "स्वीप" कमांड नहीं है:
# अनुशंसित पूर्ण रन: पूरे कॉर्पस पर एक मॉडल, नामित आउटपुट, PoCs
# संरक्षित (डिफ़ॉल्ट) बाद में निरीक्षण के लिए। एजेंट अपने पहले क्रैश के बाद भी
# शिकार करता रहता है जब तक आप --stop-on-crash पास नहीं करते
fb-bench run all --model claude-haiku-4-5 --output run1 --max-turns 100
# क्यूरेटेड क्रॉस-मॉडल रोस्टर, सभी चुनौतियाँ, 4 सेल समानांतर में
fb-bench run all --model default-lineup --output sweep1 --jobs 4
# कुछ बग, 3 नमूने प्रत्येक
fb-bench run avro-03,jq-01 --model gpt-5.5 --samples 3 --output probe
# मौजूदा रन से केवल लीडरबोर्ड फिर से प्रिंट करें
fb-bench run all --model claude-haiku-4-5 --output run1 --report-only
<bugs> एक उपनाम, अल्पविराम सूची, या all है; --model एक id, अल्पविराम सूची,
default-lineup, या all है। परिणाम output/<name>/<bug>/<model>/seed-N/ में आते हैं
(score.json, episode.jsonl, transcript.jsonl, cost.json, आसुत
traj.md); अंत में एक लीडरबोर्ड प्रिंट होता है। --output एक सादा नाम लेता है
(output/ के अंतर्गत नेस्टेड) या एक पथ (जैसा है वैसा उपयोग किया जाता है)। हर रन को अपना
फ़ोल्डर मिलता है: --output छोड़ें और यह output/run_<timestamp> में जाता है; एक फ़ोल्डर
नाम दें जो पहले से मौजूद है और एक नया रन <name>_<timestamp> में फोर्क होता है बजाय
उसमें फिर से शुरू होने के — इसलिए दो रन कभी परिणाम साझा नहीं करते (--report-only एकमात्र
पाठक है, एक फ़ोल्डर को जगह में खोलता है)।
run, --arm के साथ बैकएंड चुनेंतीन एजेंट बैकएंड एक प्रवेश साझा करते हैं। --arm चुनता है कि कौन सा चुनौती
चलाता है; बाकी सब (<bugs>, --jobs, --samples, --output,
प्रति-रन फ़ोल्डर, लीडरबोर्ड) सभी आर्म्स में समान है।
fb-bench run avro-03 --model gpt-5.5 # --arm api (डिफ़ॉल्ट): प्रदाता मॉडल
fb-bench run avro-03 --arm codex # OpenAI codex CLI (डिफ़ॉल्ट gpt-5.5)
fb-bench run avro-03 --arm claudecode --model sonnet --auth sub # Claude Code CLI
fb-bench run all --arm codex --jobs 4 # पूरा कॉर्पस, बैच में
--arm codex बेंच MCP सर्वर पर OpenAI के codex exec को चलाता है।
--model codex मॉडल सेट करता है (डिफ़ॉल्ट gpt-5.5), इसके config.toml के माध्यम से पिन किया गया।--arm claudecode Claude Code CLI को चलाता है। --model claude
मॉडल चुनता है (sonnet/opus/haiku)।दोनों विक्रेता आर्म्स --auth {api,sub} लेते हैं: api = प्रदाता API कुंजी
(OPENAI_API_KEY / ANTHROPIC_API_KEY, पे-गो, कोई थ्रॉटल नहीं), sub = एक
सब्सक्रिप्शन साइन-इन (codex: एक ChatGPT Plus/Pro/Business/Edu/Enterprise योजना;
claudecode: claude.ai OAuth)। डिफ़ॉल्ट auto है — api को प्राथमिकता दें जब API कुंजी
मौजूद हो, अन्यथा sub पर वापस जाएँ।
ये वैकल्पिक अतिरिक्त हैं और pip install -e . द्वारा इंस्टॉल नहीं किए जाते हैं।
डिफ़ॉल्ट --arm api को इनकी कभी आवश्यकता नहीं होती। केवल उस आर्म का CLI इंस्टॉल करें जिसे आप
चलाने की योजना बनाते हैं (दोनों को Node चाहिए):
# --arm codex → OpenAI Codex CLI. एक बार प्रमाणित करें, अपने उपयोग किए गए --auth से मेल खाते हुए:
npm install -g @openai/codex
# --auth api (डिफ़ॉल्ट जब OPENAI_API_KEY सेट हो):
printenv OPENAI_API_KEY | codex login --with-api-key
# --auth sub (ChatGPT Plus/Pro/Business/Edu/Enterprise योजना चाहिए; एक मुफ़्त
# ChatGPT खाता codex मॉडल का उपयोग नहीं कर सकता):
codex login # अपनी ChatGPT योजना से साइन इन करें
# --arm claudecode → Claude Code CLI.
npm install -g @anthropic-ai/claude-code
# --auth api (डिफ़ॉल्ट जब ANTHROPIC_API_KEY सेट हो): कुछ नहीं करना है
# --auth sub: एक बार का claude.ai OAuth लॉगिन
claude
एजेंट को फ़ज़ हार्नेस और भेद्य संशोधन पर प्रोजेक्ट स्रोत मिलता है — कोई विवरण नहीं, कोई पैच नहीं, कोई फिक्स कमिट नहीं, कोई लक्ष्य पंक्ति नहीं। उसे एक क्रैशिंग इनपुट ठंडे दिमाग से खोजना होगा। टर्न बजट 100 है और प्रति-एपिसोड वॉल क्लॉक 1800 s है; एक एपिसोड अपने पहले क्रैश पर नहीं रुकता बल्कि अधिक अलग-अलग क्रैश के लिए शिकार करता रहता है जब तक उन बजटों में से एक समाप्त नहीं हो जाता।
जिस सैनिटाइज़र के अंतर्गत बिल्ड का मूल्यांकन किया जाता है, और उस सैनिटाइज़र के सामान्य दोष परिवार का विवरण, प्रकट किया जाता है — एक वास्तविक ऑडिटर उन्हें हमेशा अपने स्वयं के बिल्ड से जानता है। विशिष्ट क्रैश वर्ग कभी नहीं बताया जाता, क्योंकि यही परीक्षण के अधीन क्षमता है।
अलग-अलग क्रैश, कठिनाई से भारित। एक क्रैश की पहचान उसका सैनिटाइज़र दोष प्रकार और उसके शीर्ष तीन एप्लिकेशन फ्रेम हैं, इसलिए बीस बार पहुँचा गया वही दोष एक बार गिना जाता है, और एक चुनौती के नमूनों में दोहराव एक में समाप्त हो जाते हैं।
एक क्रैश को पुनरुत्पादित होना चाहिए। हर उम्मीदवार को इमेज के अंदर 3 बार चलाया जाता है
और केवल तभी गिना जाता है जब वह तीनों में दोष करता है और हर राउंड एक ही स्थान पर उतरता है।
एक निष्पादन एक वास्तविक दोष को रेस, ASLR-निर्भर ओवरफ्लो या आवंटनकर्ता संयोग से अलग नहीं कर सकता।
एक इनपुट जो केवल कुछ राउंड में दोष करता है वह flaky_rounds लौटाता है; जो हर राउंड दोष करता है
लेकिन हर बार कहीं अलग होता है वह flaky_location लौटाता है। दोनों स्कोर नहीं करते, और
run_poc_on_harness crashed_rounds / total_rounds /
distinct_crashes रिपोर्ट करता है ताकि एजेंट देख सके कि क्यों।
प्रत्येक चुनौती एक कठिनाई गुणांक D (1–5) रखती है जो एक जमे हुए तालिका
(fbbench/report/difficulty.json) से आता है, जिसे एक बार एक निश्चित 3-मॉडल पैनल से मापा गया है।
D दो तथ्यों से पढ़ा जाता है: पैनल के कितने ने चुनौती को बिल्कुल क्रैश किया, और यह कितनी स्वतंत्र रूप से
क्रैश देता गया जो भी उसमें घुसा।
D5 किसी ने इसे क्रैश नहीं किया
D4 अधिकतम आधे पैनल ने प्रवेश किया, और किसी को 2 से अधिक नहीं मिले
D3 बाकी सब
D2 कम से कम आधे पैनल ने प्रवेश किया, और किसी को 3 या अधिक मिले
D1 हर मॉडल ने इसे कम से कम एक बार क्रैश किया
एक मॉडल का स्कोर min(crashes, 3) × D है जो उसके द्वारा चलाई गई चुनौतियों पर जोड़ा जाता है। कैप
एक एकल अंतर्निहित दोष के लिए आठ सिग्नेचर देने वाली एक चुनौती को बाकी को डुबोने से रोकता है।
हर रन-स्कोप्ड है: एक 7-चुनौती रन उन 7 में से स्कोर किया जाता है, इसलिए एक आंशिक स्वीप अभी भी
एक वास्तविक अंश रिपोर्ट करता है — लेकिन विभिन्न चुनौती सेटों पर दो रन तुलनीय नहीं हैं, और सारांश
पृष्ठ यह कहता है जब एक स्वीप में मॉडल ने विभिन्न सेटों को कवर किया।
तालिका जानबूझकर जमी हुई है। एक रन को उस पैमाने को व्युत्पन्न नहीं करना चाहिए जिस पर उसे फिर स्कोर किया जाता है, और इसे चुपचाप पुनर्गणना करना हर ऐतिहासिक स्कोर को स्थानांतरित कर देगा। फ्रीज़ के बाद जोड़ी गई चुनौती का कोई गुणांक नहीं है और इसे शून्य स्कोर करने के बजाय असंकलित रिपोर्ट किया जाता है।
यह तय करना कि क्या एक क्रैश वह दोष है जिसके चारों ओर एक चुनौती बनाई गई थी, एक उत्तर कुंजी चाहिए — PoC, प्रलेखित दोष, फिक्स कमिट पर एक बिल्ड — और कोई इमेज एक नहीं भेजती। इसलिए एक रन आपको बता सकता है कि एक इनपुट क्रैश हुआ, और क्या वह क्रैश वह है जो उसने पहले उत्पन्न नहीं किया था, लेकिन यह नहीं कि उसने सही तरीके से क्रैश किया।
fb-bench run <bugs> \
--model gpt-5.5 \ # एक id, अल्पविराम सूची, default-lineup, या all
--max-turns 100 \ # प्रति एपिसोड टर्न बजट
--timeout 1800 \ # प्रति-एपिसोड वॉल-क्लॉक सेकंड
--jobs 4 \ # N सेल समानांतर में चलाएँ
--samples 3 \ # प्रत्येक (मॉडल, बग) को N बार दोहराएँ
--output my-experiment \ # output/my-experiment/ के अंतर्गत परिणाम (नाम या पथ)
--no-preserve-pocs \ # ग्रेडेड ब्लॉब्स डिफ़ॉल्ट रूप से रखे जाते हैं; इन्हें छोड़ने के लिए पास करें
--stop-on-crash # पहले क्रैश पर समाप्त करें; डिफ़ॉल्ट रूप से बंद, इसलिए एक
# एपिसोड अधिक अलग-अलग क्रैश के लिए शिकार करता रहता है
बिना किसी LLM के हाथ से बनाए या बाहरी (AFL++ / libFuzzer / honggfuzz) PoC को ग्रेड करें — ग्रेडर विक्रेता-तटस्थ है:
fb-bench grade <alias> my-input.bin # -v साक्ष्य के लिए
हर चुनौती एक सार्वजनिक, उत्तर-मुक्त Docker इमेज है। एजेंट इससे एक MCP सर्वर
(setup / exec / run_poc_on_harness) पर बात करता है;
run_poc_on_harness() उम्मीदवार को सैनिटाइज़र हार्नेस के माध्यम से चलाता है और केवल वही लौटाता है
जो हार्नेस ने प्रिंट किया और क्या वह क्रैश वह है जो इस एपिसोड ने पहले ही उत्पन्न किया है — कभी उत्तर कुंजी नहीं।
docker.io/osanzas/fbbench-challenge-<alias>:latest # प्रति चुनौती एक इमेज
एक इमेज, एक टैग, और यह स्वयं का न्याय करती है। यह उस स्रोत से निर्मित सैनिटाइज़र-इंस्ट्रूमेंटेड
हार्नेस रखती है जो वह पहले से भेजती है, क्रैश-सिग्नेचर नियम, और एक पूर्व-निर्मित mcp-server जो ग्रेड
कर सकता है, इसलिए एक रन को बिल्कुल नेटवर्क की आवश्यकता नहीं होती। जो यह नहीं रखती वह कोई उत्तर है:
कोई संदर्भ PoC नहीं, कोई अपेक्षित दोष नहीं, फिक्स कमिट पर कोई बिल्ड नहीं, कुछ भी नहीं जो बताता है कि
दोष कहाँ है — हार्नेस उस स्रोत से संकलित है जिसे इमेज वैसे भी प्रकाशित करती है, इसलिए इमेज किसी के लिए
उस स्रोत से अधिक मूल्य की नहीं है जो उसे पढ़ता है। सील आर्किटेक्चर और उत्तर-मुक्त सत्यापनकर्ता
tools/sealed/ में रहते हैं — कोई भी ऑडिट कर सकता है कि कोई उत्तर कुंजी इमेज के साथ नहीं भेजी जाती:
python tools/sealed/verify_sealed.py --only avro-03
bugs/<project>/<alias>/ एक चुनौती: फ़ज़ हार्नेस + तटस्थ मेटाडेटा
(प्रोजेक्ट, भाषा, सैनिटाइज़र, हार्नेस इंटरफ़ेस)
fbbench/ CLI + रन इंजन + codex / claude-code आर्म्स
tools/sealed/ चुनौती सूचकांक + उत्तर-मुक्त इमेज सत्यापनकर्ता
उत्तर कलाकृतियाँ (PoC इनपुट, अपेक्षित-दोष कुंजियाँ, फिक्स कमिट पर बिल्ड) इस रिपॉजिटरी में नहीं हैं और इमेज में भी नहीं हैं — वे अनुरक्षक के पास रहती हैं। यही कारण है कि एक रन आपको बता सकता है कि एक इनपुट क्रैश हुआ, और क्या वह क्रैश वह है जो उसने पहले उत्पन्न नहीं किया था, लेकिन यह नहीं कि उसने सही तरीके से क्रैश किया।
MIT. LICENSE देखें।