Skip to content
KitploitKITPLOIT
أدواتالمدونة
Log in
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2026-34212 — Docmost قبلت رابط javascript: داخل عقدة مرفق، وحافظت عليه خلال التخزين والعرض، وأعادته كرابط قابل للنقر في نطاق Docmost. | Kitploit
أدوات/GitHubGitHub/0xmrma/cve-2026-34212
تحليل الثغرات الأمنيةالاستغلالأمن الويباختبار الاختراقالأوراق والأبحاثالتعلم والتعليم
GitHub0xmrma/cve-2026-34212

CVE-2026-34212

Docmost قبلت رابط javascript: داخل عقدة مرفق، وحافظت عليه خلال التخزين والعرض، وأعادته كرابط قابل للنقر في نطاق Docmost.

عرض المستودع
4منذ 3 أشهرلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

CVE-2026-34212

قام Docmost بقبول رابط javascript: داخل عقدة مرفق، وحافظ عليه من خلال التخزين والعرض، ثم حوله مرة أخرى إلى رابط قابل للنقر في نطاق Docmost.

مقدمة

لقد حددت، وكشفت بطريقة مسؤولة، وأعدت إنتاج مشكلة XSS مخزنة عالية الخطورة في Docmost، منصة التوثيق التعاونية مفتوحة المصدر.

يقدم الموقع الرسمي لـ Docmost المنصة كويكي جاهز للمؤسسات مع أكثر من 3 ملايين تحميل، ويذكر أنها موثوقة من قبل فرق في مؤسسات تشمل مدينة فيلنيوس، Bechtle، الحكومة الأسترالية، الصليب الأحمر، و ETS Quebec.

كانت الثغرة موجودة في مكان يسهل التغاضي عنه في أنظمة النص الغني:

ليس في ملحق الرابط العادي، بل في نوع عقدة مخصص منفصل يُستخدم للمرفقات.

كنت أراجع خط المحرر مع سؤال محدد جدًا في ذهني:

إذا كانت الروابط العادية تمنع روابط javascript:، فهل تفرض عُقد المرفقات نفس القاعدة قبل أن تصل إلى مصرف رابط؟

في الإصدارات المعرضة للخطر، لم تكن تفرضها.

قبل Docmost عقدة مرفق خبيثة في JSON الصفحة، وخزن سمة url الخاصة بها كما هي، ثم عرض تلك القيمة لاحقًا كعنصر <a href="javascript:..."> قابل للنقر.

أصبحت هذه المشكلة CVE-2026-34212.

Docmost: docmost/docmost
التوصية: GHSA-cf68-cff9-hq4w
CVE: CVE-2026-34212
تم التصحيح في: v0.71.0

photo0

سلسلة الهجوم

رابط عقدة مرفق يتحكم به المهاجم -> يتم قبول JSON الصفحة وتخزينها دون تغيير -> عرض HTML/React يحول ذلك الرابط إلى href للرابط -> يضحي المستخدم على إجراء المرفق -> يتم تنفيذ JavaScript يتحكم بها المهاجم في نطاق Docmost


ما يفعله هذا الجزء من Docmost

يخزن Docmost محتوى الصفحة بتنسيق JSON متوافق مع ProseMirror/Tiptap.

يتضمن نموذج المحتوى هذا عُقد كتلة مخصصة لأشياء مثل:

  • الصور
  • الرسوم التخطيطية
  • المضمنات
  • المرفقات

تخزن عقدة المرفق حقولاً مثل:

  • url
  • name
  • mime
  • size
  • attachmentId

يقبل الخادم محتوى الصفحة بعدة تنسيقات:

  • json
  • markdown
  • html

ويقوم بتطبيعه إلى JSON ProseMirror قبل تخزينه.

هذا يعني أن أي نوع عقدة يمكن أن يحمل رابطًا هو جزء من حدود الثقة المباشرة.

إذا قام أحد أنواع العُقد هذه في النهاية بعرض رابط <a href>، فإن معالجة مخطط الرابط ليست اختيارية. إنها جزء من النموذج الأمني.


لماذا كان هذا السطح يستحق النظر

ملحقات المحرر المخصصة هي مصدر متكرر للانحراف الأمني.

قد يعرف النظام الأساسي بالفعل كيفية التعامل مع الروابط الخطرة بشكل صحيح، لكن كل عقدة مخصصة لا تزال بحاجة إلى إعادة تطبيق نفس القواعد على مصارفها الخاصة.

يخلق ذلك استراتيجية مراجعة يمكن التنبؤ بها:

  • ابحث عن كل نوع عقدة يخزن حقلاً يشبه الرابط
  • تتبع أين يتم قبول هذا الحقل
  • تتبع أين يتم عرض هذا الحقل
  • قارن سلوك التعقيم الخاص به مع معالجة الرابط العادية للمنصة

هذا هو بالضبط ما كشف هذه الثغرة.

ملحق الرابط العادي في Docmost كان يعالج بالفعل javascript: على أنه خطر.

عقدة المرفق الخاصة به لم تفعل ذلك.

بمجرد أن ترى هذا التباين، يصبح السؤال الأمني واضحًا:

هل يمكنني الاحتفاظ بعقدة مرفق يكون عنوان url الخاص بها هو javascript: والحصول عليها معروضة مرة أخرى في رابط مباشر؟

كان الجواب نعم.


السبب الجذري

كان السبب الجذري هو عدم تناسق تعقيم الرابط عبر أنواع عُقد المحتوى.

مسار المحتوى في الخادم قبل روابط مرفق عشوائية طالما أن المحتوى الكلي يتطابق مع مخطط ProseMirror.

في الإصدار المعرض للخطر:

  • CreatePageDto قبل content?: string | object
  • PageService.parseProsemirrorContent() قام بتطبيع markdown أو html أو json
  • ثم استدعى الخادم jsonToNode(prosemirrorJson)
  • إذا نجح التحقق من المخطط، تم تخزين المحتوى

تلك الخطوة التحقق من الصلاحية الهيكلية، وليس سلامة الرابط.

الجزء الحرج من منطق الخادم المعرض للخطر كان بشكل فعال:

prosemirrorJson = content;
jsonToNode(prosemirrorJson);
return prosemirrorJson;

لم يحدث أي تطبيع لمخطط رابط المرفق هناك.

لاحقًا، عرض ملحق المرفق القيمة التي يتحكم بها المهاجم مباشرة.

قامت عقدة المرفق المعرضة للخطر بذلك:

url: {
  default: "",
  parseHTML: (element) => element.getAttribute("data-attachment-url"),
  renderHTML: (attributes) => ({
    "data-attachment-url": attributes.url,
  }),
},

ثم:

[
  "a",
  {
    href: HTMLAttributes["data-attachment-url"],
    class: "attachment",
    target: "blank",
  },
  `${HTMLAttributes["data-attachment-name"]}`,
]

على جانب العميل، قام عرض عقدة React بتغليف ذلك مرة أخرى في:

<a href={getFileUrl(url)} target="_blank">

لكن getFileUrl() قامت فقط بمعالجة حالات خاصة:

  • روابط http المطلقة
  • /api/...
  • /files/...

أي شيء آخر تم إرجاعه دون تغيير.

لذا فإن حمولة مثل:

javascript:alert(document.domain)

نجت من:

  • تخزين JSON
  • التحقق من المخطط من جانب الخادم
  • عرض HTML
  • معالجة الرابط من جانب العميل

هذا وحده كان كافياً لـ XSS مخزنة.

ما يوضح السبب الجذري بشكل خاص هو نقطة المقارنة.

ملحق الرابط العادي في Docmost منع javascript: بشكل صريح:

  • رفض javascript: في parseHTML()
  • أفرغ href من javascript: في renderHTML()

لذا كان المنتج يعرف بالفعل أن هذا المخطط خطر.

عقدة المرفق فشلت ببساطة في تطبيق نفس السياسة.

لهذا السبب لم يكن هذا "XSS عام في المحرر."

لقد كانت فجوة حدود ثقة خاصة بالعقدة.


لماذا هذه مشكلة أمنية، وليست مجرد نقص في التعقيم

لم تكن هذه الثغرة مجرد مسألة جماليات HTML غير آمنة.

لقد سمحت للمهاجم الذي يمكنه تحرير صفحة بالاحتفاظ بحمولة خبيثة سيتم تنفيذها لاحقًا في نطاق Docmost عندما يتفاعل مستخدم آخر مع المرفق المعروض.

هذا مهم لأن البرنامج النصي داخل النطاق يمكنه:

  • قراءة البيانات التي يمكن للضحية الوصول إليها
  • إصدار طلبات مصادق عليها نيابة عن الضحية
  • تعديل المحتوى الذي يُسمح للضحية بتعديله
  • إساءة استخدام أي واجهة DOM أو API مكشوفة للجلسة

لا يقلل شرط النقر من هذه المشكلة إلى مسألة تافهة.

النقر جزء من سلوك المنتج العادي: تقدم واجهة المستخدم المرفق عمداً كرابط/أيقونة قابلة للتنفيذ.

لذا فإن السؤال الأمني ليس "هل يمكن للمهاجم إجبار JS عشوائي دون أي تفاعل؟"

السؤال الحقيقي هو:

هل يقوم التطبيق بتخزين محتوى يحمل برنامجًا نصيًا يتحكم به المهاجم ثم يقدمه لاحقًا لمستخدمين آخرين كمسار تفاعل موثوق؟

في الإصدارات المعرضة للخطر، فعل ذلك.

هذا هو XSS مخزنة.


لماذا كان الاستغلال عمليًا

كان مسار الاستغلال مباشرًا:

  • أي مستخدم لديه صلاحيات تحرير الصفحة يمكنه زرع الحمولة
  • نجت الرابط الخبيث من التخزين دون تغيير
  • الصفحة عرضت بشكل طبيعي
  • المشاهدون احتاجوا فقط إلى وصول قياسي للصفحة
  • نقرة واحدة على إجراء المرفق كانت كافية لبدء التنفيذ

هذا جعل أيضًا المستخدمين ذوي الامتيازات الأعلى أهدافًا واقعية.

إذا كان مالك مساحة العمل أو مديرها أو محرر موثوق على نطاق واسع قد شاهد محتوى يتحكم به المهاجم ونقر على إجراء المرفق، فسيتم تشغيل البرنامج النصي للمهاجم في سياق تلك الجلسة ذات الامتيازات الأعلى.

هذه هي النقطة العملية المهمة:

متطلبات امتياز المهاجم كانت منخفضة فقط. مستوى امتياز الضحية هو الذي يحدد مقدار القيمة التي تحملها جلسة XSS.


إثبات المفهوم

لقد تحققت من المشكلة مباشرة ضد Docmost v0.70.3.

استخدم إثبات المفهوم طلبات HTTP عادية وواجهات برمجة التطبيقات الخاصة بالصفحة في التطبيق.

كان التدفق:

  1. تسجيل الدخول كمستخدم يمكنه تحرير صفحة.
  2. إنشاء أو تحديد صفحة.
  3. إرسال POST /api/pages/update مع format: "json" وعقدة مرفق يكون عنوان url الخاص بها هو حمولة javascript:.
  4. طلب الصفحة مرة أخرى عبر POST /api/pages/info.
  5. تأكيد أن JSON المخزن لا يزال يحتوي على الرابط الخبيث.
  6. طلب نفس الصفحة بصيغة HTML وتأكيد أن الخادم يعيد رابطًا لا يزال href الخاص به هو javascript:....
  7. في واجهة المستخدم، نقرة المشاهد على إجراء المرفق المعروض تنفذ الحمولة في نطاق Docmost.

كان المحتوى الخبيث الأدنى:

{
  "pageId": "<pageId>",
  "content": {
    "type": "doc",
    "content": [
      {
        "type": "attachment",
        "attrs": {
          "url": "javascript:alert(document.domain)",
          "name": "policy.pdf",
          "mime": "application/pdf",
          "size": 1
        }
      }
    ]
  },
  "operation": "replace",
  "format": "json"
}

النتيجة المباشرة التي لوحظت من اختباري كانت:

  • قبلت API عقدة المرفق الخبيثة دون تغيير
  • معرف الصفحة المخزنة كان 019d18cf-4212-70b0-894a-fe20080fb0f1
  • POST /api/pages/info أعادت JSON المخزن مع:
تنزيل الأداة