الدقة والاختبارات المعيارية
نوعان من النتائج، كلٌّ منهما موسوم بإصدار المحرك الذي أنتجه: قياس حالي على المجموعة الاصطناعية للمحرك (v3.6.3)، وملاحظات تاريخية على أهداف واقعية (v0.11.0). ولا يمثّل أيٌّ منهما دقة أو استدعاء في بيئات الإنتاج.
القياس الحالي — إصدار المحرك v3.6.3
المجموعة الاصطناعية الموسومة في مستودع المحرك، مُشغَّلة بأداة القياس من وسم الإصدار نفسه داخل صورة v3.6.3 الرسمية، مع تعطيل الشبكة.
الإجمالي: 38 إيجابية صحيحة، و0 إيجابية خاطئة، و0 سلبية خاطئة، و18 سلبية صحيحة — دقة واستدعاء وF1 بقيمة 1.000 عبر 7 فئات.
المصدر
- Fendix v3.6.3، إيداع المحرك c491c80a
- الصورة fendixapp/fendix@sha256:2a3b25df…fb9fad، وهي صورة الإصدار v3.6.3 الرسمية
- المجموعة والبيان من الوسم v3.6.3 (56 حالة موسومة، شجرة git 995d4eb8)
- قيس في 10 أكتوبر 2026
- Docker على معالج Apple (linux/arm64)، دون شبكة
- 4 تشغيلات بنتائج متطابقة
ما الذي يُظهره هذا وما الذي لا يُظهره
تصف هذه النتائج هذه المجموعة المضبوطة وحدها، وليست مقياسًا للدقة في بيئات الإنتاج. فهي تُظهر أن الإصدار ما زال يلتقط كل نمط في مجموعة الانحدار الخاصة به ولا يبلّغ عن أيٍّ من الحالات الآمنة. ولا تقيس الدقة أو الاستدعاء على قواعد شيفرة واقعية، ولا تقول شيئًا عن DAST أو فحص الاعتماديات، كما أن هذه المجموعة بوابة في CI للمحرك، فالنتيجة الكاملة هي الحالة المتوقعة لا اكتشاف. ولم يُعَد تشغيل المسارات الواقعية أدناه على v3.6.3.
إعادة الإنتاج
git clone --depth 1 --branch v3.6.3 https://github.com/Fendix-app/Fendix.git fendix-v3.6.3
mkdir -p out && chmod 0777 out
docker run --rm --network none \
-v "$PWD/fendix-v3.6.3/scripts/accuracy":/bench:ro -v "$PWD/out":/out \
--entrypoint python3 fendixapp/fendix@sha256:2a3b25df2b52e1bd9a5a4c7d82cf56ad9536a57a238e37ee264fd2eb1efb9fad \
/bench/run.py /usr/local/bin/fendix --python-engine --output-json /out/run.jsonنتائج تاريخية — إصدار المحرك v0.11.0
سُجّلت في مايو 2026 على إصدار المحرك v0.11.0، وتصف ذلك الإصدار لا الإصدار الحالي.
نطاق التنفيذ الحالي
- بيئة التشغيل
- لا تتطلب ملفات Go التنفيذية الجاهزة مترجم Go للفحص الأساسي. يتطلب البناء من المصدر Go 1.25+. لمحركات الفحص الاختيارية متطلبات تشغيل خاصة؛ راجع التغطية للتأكد من تنفيذها.
- DAST
- يفحص تحليل الروابط وواجهات API السلوك الظاهر أثناء التشغيل. تتطلب الاختبارات النشطة --enable-active. لا تثبت استجابة HTTP 200 وحدها الوصول إلى بيانات حساسة.
- SAST
- تغطي القواعد الساكنة الأصلية أنماطًا مدعومة في Go وJavaScript وJava والبنية التحتية. يوسّع Semgrep ومحرك Python الذي تحاول فحوصات الشيفرة تشغيله الفحوصات المناسبة عند توفرهما. دعم اللغة لا يعني تغطية جميع الأطر أو المسارات.
- SCA
- يستخدم تحليل Go أداة govulncheck. تستخدم محركات تبعيات Python وnpm ملفات التعريف والتثبيت المدعومة، ومنها poetry.lock وPipfile.lock وpackage-lock.json. قد تنقل استعلامات الثغرات أسماء الحزم وإصداراتها.
- الأدلة والسياسة
- يربط الترابط المشاهدات المتطابقة المدعومة؛ ليست لكل نتيجة مصادر متعددة. قد تكفي أدلة قوية من مصدر واحد. الشدة والثقة وحالة النتيجة وتوصية الإصدار مفاهيم منفصلة.
- التغطية والمراجعة البشرية
- قد يترك فشل محرك أو غياب أدلة مطلوبة الإصدار غير مكتمل. تعني PASS نتيجة وفق السياسة والتغطية المحددتين وليست ضمانًا للأمان أو موافقة بشرية.
الجداول أدناه ملاحظات تاريخية من المحرك v0.11.0. أما نتيجة v3.6.3 أعلاه فقياس مضبوط على المجموعة الاصطناعية للمحرك. ولا تمثّل أيٌّ منهما دقة أو استدعاءً في بيئة الإنتاج.
اقرأ معالجة البيانات حسب طريقة النشرF1 التركيبي
1.000
38 TP / 0 FP / 0 FN عبر 7 فئات كشف
Juice Shop مقابل v0.6.1
غير مُتحقق منها
الاستجابات العامة للتطبيق لا تثبت تسرب الملفات.
PyGoat واقعي
147 نتيجة
12 فئة ثغرة خلال 17 ثانية زمن فعلي
المسار 1 — مجموعة تركيبية موسومة
56 حالة اختبار موسومة عبر 7 فئات كشف. تحتوي كل فئة على متغيرات EXPECT_TP (يجب أن يبلّغ عنها المحرك) ومتغيرات EXPECT_TN (شكل آمن؛ يجب أن يتركها المحرك). تتوفر المجموعة في scripts/accuracy/corpus/؛ والحقيقة المرجعية في scripts/accuracy/manifest.json. تربط أداة التشغيل المخرجات بالحالات الموسومة حسب الفئة + جزء العنوان + الملف + سماحية ±6 أسطر، مع مطابقة أقرب TP غير مُطالَب به بحيث لا يمكن أن يُطالَب بـ TP واحد من قِبل عدة مخرجات.
| الفئة | TP | FP | FN | Precision | Recall | F1 |
|---|---|---|---|---|---|---|
| sqli | 5 | 0 | 0 | 1.000 | 1.000 | 1.000 |
| cmdi | 5 | 0 | 0 | 1.000 | 1.000 | 1.000 |
| path_traversal | 5 | 0 | 0 | 1.000 | 1.000 | 1.000 |
| ssrf | 3 | 0 | 0 | 1.000 | 1.000 | 1.000 |
| open_redirect | 3 | 0 | 0 | 1.000 | 1.000 | 1.000 |
| xss | 4 | 0 | 0 | 1.000 | 1.000 | 1.000 |
| secrets | 13 | 0 | 0 | 1.000 | 1.000 | 1.000 |
| OVERALL | 38 | 0 | 0 | 1.000 | 1.000 | 1.000 |
تحفظ صادق
1.000/1.000/1.000 يعني أن fendix لا يفوّت أبدًا هذه الأنماط المعيارية الـ56 المحددة، وليس أنه لا يفوّت أي شيء على الإطلاق. تقيس المجموعة التركيبية الجانب الإيجابي؛ أما انضباط FP الواقعي مقابل juice-shop والأهداف الإنتاجية فيُتابَع بشكل منفصل في tasks/FP_CORPUS.md ضمن مستودع المحرك. أما المساران 2 و3 فهما ملاحظات تاريخية، وليسا قياسًا محكّمًا للدقة أو الاستدعاء في بيئات الإنتاج.
إعادة الإنتاج
make build
python3 scripts/accuracy/run.py --python-engine
# Output:
# Running ./bin/fendix scan --code scripts/accuracy/corpus...
# 20 unique findings (40 after exploding affected_endpoints)
#
# CATEGORY TP FP FN TN PREC REC F1
# ----------------------------------------------------------------------
# sqli 5 0 0 3 1.000 1.000 1.000
# cmdi 5 0 0 3 1.000 1.000 1.000
# path_traversal 5 0 0 3 1.000 1.000 1.000
# ssrf 3 0 0 2 1.000 1.000 1.000
# open_redirect 3 0 0 2 1.000 1.000 1.000
# xss 4 0 0 2 1.000 1.000 1.000
# secrets 13 0 0 3 1.000 1.000 1.000
# ----------------------------------------------------------------------
# OVERALL 38 0 0 18 1.000 1.000 1.000تحسينات المحرك التي ظهرت خلال هذا التقييم
أظهرت المجموعة التركيبية، وقمنا بشحن تحسينين فعليين للمحرك + إصلاح كامن واحد للمنسّق، في الجلسة نفسها:
- Open redirect: كان الكاشف يتطلب مباشرًا
redirect(request.args.get("x"))؛ وكانت الإسنادات متعددة القفزات تُفوَّت بصمت. أما المصارف الستة الأخرى القابلة للوصول (SQLi / SSRF / XSS / cmd-injection / path-traversal) فكانت جميعها تطبّق مرشّح ثابت-مقابل-غير-ثابت من إصلاحات سابقة؛ وكان open-redirect أول مصرف شملته تلك الإصلاحات ولم يحصل بطريقة ما على معالجة السلسلة. Recall: 0/3 → 3/3. - cmd-injection: تمت مواءمة الوضعية مع المصارف الأخرى القابلة للوصول عبر مساعد جديد
_cmdi_arg_is_dangerous. قبل الإصلاح، كانos.system("echo hello")يطلق HIGH رغم انعدام قابلية الاستغلال (إذ كان تغيير سابق قد اختار "الإطلاق عند كل استدعاء طرفي"). Precision: 0.833 → 1.000. - المنسّق: يقوم
runWhiteboxScanالآن بحلّcode_pathوspecإلى مسارات مطلقة قبل إرسال ScanRequest. يضبط المُولِّدcmd.Dir = engineDir، لذا كان المسار النسبي يُحَل بصمت إلى لا شيء ضمن مجلد العمل للعملية الابنة. يظهر ذلك على شكل إبلاغ fendix عن 0 نتيجة في قواعد الكود الفعلية — وهو تراجع فعلي معطِّل للمستخدم كامن منذ تغيير سابق.
المسار 2 — OWASP Juice Shop (DAST واقعي)
أمر fendix scan --url القياسي مقابل bkimminich/juice-shop:v17.1.1. بدون مصادقة، وبدون --code، وبدون --enable-active — مجرد خط المعالجة الافتراضي للصندوق الأسود مقابل القياس المرجعي الحديث لتطبيقات الويب من OWASP.
| المقياس | خط الأساس v0.6.1 | v0.11.0 (تاريخي) | Δ |
|---|---|---|---|
| إجمالي النتائج (بعد إزالة التكرار) | 7 | 12 | +5 |
| CRITICAL | 0 | 5 | +5 |
| مدة الفحص | 42 s | 27 s | −35 % |
| نقاط النهاية المفحوصة | 97 | 97 | — |
صنّف التشغيل التاريخي خمس نتائج كحرجة. لم يُتحقق من كون الاستجابات تحتوي ملفات حساسة؛ لا نعدّها تسريبات مؤكدة.
تحفظ
قد تُعيد تطبيقات SPA الصفحة نفسها لمسارات غير موجودة. استجابة HTTP 200 وحدها لا تثبت تسرب ملف أو تسميم ذاكرة التخزين المؤقت. يلزم فحص المحتوى ومقارنته بمسار عشوائي قبل إثبات الخطر.
إعادة الإنتاج
JS_PORT=3001 FENDIX_BIN=./bin/fendix bash scripts/benchmark/run-juice-shop.sh
# Output (bench-results/juice-shop/<timestamp>/):
# Fendix benchmark — OWASP Juice Shop
# Fendix version: fendix v0.11.0 (darwin/arm64)
# Target image: bkimminich/juice-shop:v17.1.1
# Scan duration: 27 seconds
# Endpoints: 97
# Total findings: 12
#
# By severity: CRITICAL: 5 HIGH: 0 MEDIUM: 4 LOW: 2 INFO: 1المسار 3 — PyGoat (SAST واقعي)
نسخة من adeyosemanputra/pygoat — تطبيق Django مصمَّم ليكون قابلًا للاستغلال في كل فئة من OWASP Top 10. 52 ملف Python بالإضافة إلى أصول JavaScript. الفحص عبر fendix scan --code /tmp/pygoat --python-engine دون مصادقة أو فحص نشط.
إجمالي النتائج
147
1 CRITICAL, 146 HIGH
مدة الفحص
17.1 s
52 ملف Python + أصول JS
الفئات المكتشفة
12
فئات رُصدت في التشغيل التاريخي
| الخطورة | فئة الثغرة | أول اكتشاف |
|---|---|---|
| CRITICAL | Unsafe pickle deserialization (RCE) | dockerized_labs/insec_des_lab/main.py:36 |
| HIGH | Unsafe eval() with dynamic arg | introduction/mitre.py:218 |
| HIGH | subprocess(shell=True) | introduction/mitre.py:233 |
| HIGH | Unsafe yaml.load() (RCE) | introduction/lab_code/test.py:23 |
| HIGH | SSRF — dynamic URL | 2 sites (incl. views.py:963) |
| HIGH | innerHTML XSS | introduction/static/js/a9.js:40 |
| HIGH | Open redirect — 9 sites | broken_auth_lab/app.py:107 |
| HIGH | Hardcoded API key / password / JWT | 3 distinct files |
| HIGH × 133 | Vulnerable dependency (certifi, cryptography, django, …) | requirements.txt |
تحفظات
- لا يتوفر بيان حقيقة مرجعي على مستوى النتائج لهذا التشغيل؛ لا يمكن حساب precision أو recall منه.
- عدد النتائج لا يقيس الدقة. لا تسمح هذه التجربة باستنتاج عدد النتائج أو الإيجابيات الكاذبة في تطبيقات الإنتاج.
إعادة الإنتاج
git clone --depth 1 https://github.com/adeyosemanputra/pygoat /tmp/pygoat
./bin/fendix scan --code /tmp/pygoat --python-engine --max-duration 60s
# Output:
# scan complete duration=17.082s total=147 critical=1 high=146 medium=0
#
# By category:
# deps 135 (real CVE-tagged dependencies in requirements.txt)
# injection 9 (SSRF/XSS/eval/subprocess-shell/pickle/yaml/open-redirect)
# secrets 3 (hardcoded API key, password, JWT)تعمّق أكثر
- docs/accuracy.md — المصدر الأساسي لكل رقم في هذه الصفحة (يُحافَظ على مزامنته).
- /performance — كمون بدء التشغيل البارد + قياس حجم الملف الثنائي.
- scripts/accuracy/run.py — أداة التشغيل. نحو 250 سطر كود، تُقرأ بوضوح من الأعلى إلى الأسفل.
- tasks/FP_CORPUS.md — مجموعة انضباط FP الواقعية (juice-shop، fendix-self، TwiScope). الوجه الآخر لهذه الصفحة: ما لا يكتشفه fendix / ما يبلّغ عنه بالخطأ.