
توثيق CVE-2026-22874: قائمة السماح غير مكتملة لـ SSRF في webhook/الترحيل في Gitea (انتقال IPv6 وبيانات وصف السحابة). تم الإصلاح في Gitea 1.26.3.
شرح فني ومراجع لـ CVE-2026-22874 (GHSA-2r5c-gw76-rh3w): قائمة سماح SSRF غير مكتملة في تسليم webhook وترحيل المستودعات في Gitea، تم إصلاحها في Gitea 1.26.3.
لقد أبلغتُ بشكل مستقل عن هذه الفئة من SSRF إلى القائمين على صيانة Gitea، وأُدرجتُ كمساهم (other) في النشرة الأمنية المنشورة؛ والمبلّغ الرئيسي للنشرة هو J. Leitschuh. هذا المستودع هو شرح دفاعي وتعليمي للنشرة العامة — المشكلة تم إصلاحها.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N)<= 1.26.2 — تم الإصلاح في: 1.26.3تعتمد قائمة السماح الافتراضية لـ SSRF في Gitea (MatchBuiltinExternal، المستخدمة في كلٍّ من تسليم webhook وترحيل المستودعات) على دالة من المكتبة القياسية للغة Go، التي لا تعترف إلا بنطاقات RFC 1918 (, , ) وRFC 4193 (). إن العديد من نطاقات العناوين المستخدمة بشكل شائع لخدمات بيانات تعريف السحابة والشبكات الداخلية وآليات انتقال IPv6 ليست «خاصة» وفق هذا التعريف، وبالتالي اجتازت مرشح «الخارجي»، مما يسمح لمستخدم مُصادَق بجعل الخادم يرسل طلبات HTTP إلى تلك الوجهات.
net.IP.IsPrivate()10/8172.16/12192.168/16fc00::/7ولأن تسليم webhook يسجّل حالة الاستجابة والترويسات وما يصل إلى ~1 MiB من نص الاستجابة ويعرضها في واجهة سجل webhook، فإن ثغرة SSRF هذه ليست عمياء: يمكن للمهاجم قراءة ما تُرجعه الخدمة الداخلية المستهدفة.
net.IP.IsPrivate()| النطاق | المعنى |
|---|---|
100.64.0.0/10 | RFC 6598 NAT بدرجة الناقل (Carrier-Grade NAT) |
168.63.129.16/32 | Azure WireServer / نقطة نهاية بيانات تعريف المثيل |
64:ff9b::/96 | RFC 6052 NAT64 (يمكنها تضمين 169.254.169.254، مثل AWS IMDS) |
2001::/32 | RFC 4380 Teredo |
2002::/16 | RFC 3056 6to4 |
تتأثر بالطريقة نفسها أيضًا الصيغ IPv4-mapped من IPv6 للنطاقات أعلاه.
وبالتالي، يمكن لمستخدم مُصادَق يمكنه إنشاء أو تعديل webhook (أو بدء ترحيل) الوصول إلى نقاط نهاية بيانات تعريف السحابة — على سبيل المثال AWS IMDS عبر تعيين NAT64، أو Azure WireServer على العنوان 168.63.129.16 — والخدمات الداخلية فقط، ثم قراءة الاستجابة من خلال عرض سجل webhook.
السياسة الافتراضية هي MatchBuiltinExternal في فحص HostMatchList في Gitea، والتي كانت تعتبر أي عنوان unicast عام غير IsPrivate() مسموحًا به:
case MatchBuiltinExternal:
if ip.IsGlobalUnicast() && !ip.IsPrivate() {
return true
}
إن net.IP.IsPrivate() ليست حدًا أمنيًا لمفهوم «الخارجي»: فهي لا تأخذ في الحسبان NAT بدرجة الناقل، أو نقاط نهاية بيانات تعريف السحابة، أو نطاقات انتقال IPv6 التي يمكن توجيهها إلى وجهات داخلية أو وجهات بيانات التعريف.
تم إصلاحها في Gitea 1.26.3 عن طريق توسيع المرشح المدمج لحظر النطاقات الإضافية المذكورة أعلاه. يجب على المشغّلين الترقية إلى الإصدار 1.26.3 أو أحدث. ومن باب الدفاع المتعمق: