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

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

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.

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

الأكثر شعبية

عرض الكل →

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

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

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

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

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)
  • إذا نجح التحقق من المخطط، تم تخزين المحتوى

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

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

root@kitploit:~
prosemirrorJson = content;
jsonToNode(prosemirrorJson);
return prosemirrorJson;

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

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

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

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

ثم:

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

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

root@kitploit:~
<a href={getFileUrl(url)} target="_blank">

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

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

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

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

root@kitploit:~
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.

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

root@kitploit:~
{
  "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 المخزن مع:
root@kitploit:~
"url": "javascript:alert(document.domain)"
  • POST /api/pages/info مع format: "html" أعادت HTML تحتوي على:
root@kitploit:~
<div data-type="attachment" data-attachment-url="javascript:alert(document.domain)" data-attachment-name="policy.pdf" data-attachment-mime="application/pdf" data-attachment-size="1"><a href="javascript:alert(document.domain)" class="attachment" target="blank">policy.pdf</a></div>

استجابة HTML هذه هي الدليل الحاسم.

لم أحتاج إلى الاعتماد على ادعاء غير محدد بأن "المتصفح قد يفعل شيئًا مثيرًا للاهتمام."

التطبيق نفسه عرض مصرف التنفيذ الدقيق.

بمجرد أن ينقر المستخدم على رابط/أيقونة المرفق ذلك، ينفذ المتصفح رابط javascript: في نطاق الصفحة التي أنشأته.


لماذا تم اختيار إثبات المفهوم بهذه الطريقة

بالنسبة لـ XSS القائم على المحرر، فإن لقطات الشاشة وحدها دليل ضعيف.

تظهر الأعراض، وليس فشل الحدود.

لهذا السبب بنيت إثبات المفهوم حول نقطتي تفتيش صريحتين:

  1. إثبات التخزين
  2. إثبات مصرف العرض

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

أظهر إثبات مصرف العرض أن التطبيق حول تلك القيمة المخزنة مرة أخرى إلى:

root@kitploit:~
<a href="javascript:...">

هذا التقسيم مهم.

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

إذا قام المنتج بتخزين إدخال خطر ثم يعرضه لاحقًا في مصرف تنفيذ حقيقي، فلديك سلسلة الثغرة الكاملة.

هذا ما حدث هنا.


تحليل الإصلاح

تم شحن الإصلاح في v0.71.0 وعالج مسار الاستغلال المعروض من خلال تطبيق تعقيم الرابط على روابط المرفقات.

يقوم ملحق المرفق الآن باستيراد واستخدام sanitizeUrl، بما في ذلك:

  • تعقيم data-attachment-url أثناء التحليل
  • تعقيم data-attachment-url أثناء العرض
  • تعقيم href للرابط

من الناحية المفاهيمية، غير التصحيح عقدة المرفق من:

  • ثق في رابط المرفق الخام
  • أخرج رابط المرفق الخام

إلى:

  • تطبيع رابط المرفق قبل أن يصبح جزءًا من العقدة المعروضة

تم أيضًا تحديث المساعد من جانب العميل getFileUrl() بحيث لا تمر المخططات غير المعروفة دون تغيير. في الإصدار المُصحح، يعيد المسار الاحتياطي sanitizeUrl(src) بدلاً من إعادة src كما هي.

هذا جزء مهم من الإصلاح لأن التصميم المعرض للخطر كان به مشكلتان معززتان:

  • العقدة عرضت href خام
  • المسار الاحتياطي من جانب العميل تعامل مع المخططات غير المعروفة على أنها مقبولة

أزال التصحيح كلا الافتراضين.

كان هذا إصلاحًا جيدًا لمسار XSS الحي لأنه أعاد معالجة رابط المرفق إلى التوافق مع بقية النموذج الأمني للمحرر.

ومع ذلك، لا يزال هناك درس أوسع في التعزيز:

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

النموذج الأكثر أمانًا على المدى الطويل هو:

  • رفض المخططات الخطرة بوضوح عند الاستيعاب
  • تعقيم مرة أخرى عند حدود العرض

الدفاع في العمق مهم في أنظمة المحتوى الغني.


حالات الانحدار المهمة

للتغطية طويلة المدى، هذه هي الحالات الأكثر أهمية:

  • تحديثات JSON للصفحة تحتوي على attachment.attrs.url = "javascript:..."
  • استيرادات HTML تحتوي على data-attachment-url="javascript:..."
  • عرض المرفق يجب ألا يصدر أبدًا href="javascript:..."
  • مساعدات الاحتياط من جانب العميل يجب ألا تعيد مخططات قابلة للتنفيذ غير معروفة دون تغيير
  • عُقد المرفقات وعُقد الروابط العادية يجب أن تشارك سياسة مخطط رابط متكافئة
  • مسارات المرفق الداخلية الآمنة مثل /api/files/... و /files/... يجب أن تستمر في العمل بشكل طبيعي

النقطة الرئيسية هي الاتساق.

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

لديه أجزاء، والأجزاء هي المكان الذي تعيش فيه ثغرات XSS.


الخطورة والتصنيف

صنفت التوصية المنشورة هذه المشكلة على أنها:

  • CWE-79: تحييد غير صحيح للإدخال أثناء إنشاء صفحة الويب
  • CVSS v3.1:
root@kitploit:~
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:L/A:N

يقع هذا عند 7.6 / عالية.

هذا تصنيف يمكن الدفاع عنه.

الخصائص المهمة هي:

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

يبقى التفاعل مطلوبًا لأن الضحية يجب أن تنشط رابط/أيقونة المرفق. لهذا السبب UI:R صحيحة.

لكن بمجرد حدوث هذا التفاعل، فإن الحدود الأمنية قد فشلت بالفعل في وقت أبكر بكثير: التطبيق خزن مخططًا خطرًا وأعاده عرضه في مصرف تنفيذ.


الإفصاح

أبلغت عن المشكلة بشكل خاص عبر توصيات GitHub الأمنية مع:

  • تحليل السبب الجذري
  • إثبات مفهوم HTTP حي
  • أدلة JSON مخزنة
  • أدلة مصرف HTML معروض
  • مختبر اختبار يمكن التخلص منه ومثبت

تم قبول المشكلة، وتم تخصيص CVE-2026-34212 لها، ونشرت في 14 أبريل 2026.

تسرد التوصية العامة حاليًا:

  • الإصدار المتأثر: 0.70.3
  • الإصدار المُصحح: 0.71.0

تم إجراء التحقق المباشر على v0.70.3، والذي يطابق الإصدار المعرض للخطر المنشور.


ما تعلمه هذه الثغرة بالفعل

الدرس الرئيسي هنا ليس فقط "قم بتعقيم الروابط."

الجميع يعرف ذلك بالفعل.

الدرس الأكثر إثارة للاهتمام هو:

إذا كان التطبيق يحتوي على نوع عقدة رابط آمنة ونوع عقدة رابط غير آمنة، فإن النوع غير الآمن هو السياسة الحقيقية.

غالبًا ما تتراكم أنظمة النص الغني امتدادات مخصصة أسرع من تراكم المراجعة الأمنية.

يخلق ذلك بالضبط هذا النوع من التباين:

  • مسار الرابط القياسي مُقوى
  • مسار المرفق يُعامل على أنه "داخلي" أو "خاص"
  • المسار الخاص يصبح بهدوء مصرف XSS الأسهل

تظهر هذه الثغرة أيضًا لماذا التحقق من المخطط ليس كافيًا.

jsonToNode() تحقق من أن المحتوى كان صحيحًا من الناحية الهيكلية لبيانات ProseMirror. لم يثبت أن المحتوى آمن للعرض.

تلك أسئلة مختلفة.

تصبح المراجعة الأمنية أكثر حدة عندما تبقى هذه الأسئلة منفصلة:

  • هل هذا المحتوى صحيح هيكليًا؟
  • هل هذا المحتوى آمن للتخزين؟
  • هل هذا المحتوى آمن للعرض في كل مصرف؟

عقدة المرفق اجتازت السؤال الأول وفشلت في الثالث.

هكذا تبقى ثغرات المحتوى المخزن داخل خطوط المحرر المنظمة جيدًا.


النقاط الرئيسية

  • قبل Docmost روابط عُقد المرفقات الخام في محتوى الصفحة.
  • تحقق الخادم من مخطط ProseMirror الهيكلي، وليس سلامة مخطط الرابط.
  • عرضت عقدة المرفق المعرضة للخطر data-attachment-url و href للرابط مباشرة من إدخال يتحكم به المهاجم.
  • أعاد المساعد من جانب العميل getFileUrl() المخططات غير المعروفة دون تغيير.
  • عُقد الروابط العادية كانت تمنع بالفعل javascript:، لكن عُقد المرفقات لم تفعل.
  • يمكن لمحرر منخفض الامتياز زرع الحمولة مرة واحدة واستهداف المشاهدين اللاحقين.
  • أثبت إثبات المفهوم الحي كلاً من الاستمرار المخزن ومصرف التنفيذ المعروض.
  • أضاف الإصلاح في v0.71.0 معالجة sanitizeUrl إلى عقدة المرفق ومسار الاحتياط من جانب العميل.

كلمات ختامية

لم تكن هذه الثغرة حول خلل في المتصفح.

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

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

لهذا السبب أصبحت CVE-2026-34212.

أغلق التصحيح في v0.71.0 مسار XSS النشط بشكل نظيف، لكن الدرس الأوسع هو الذي يستحق الاحتفاظ به:

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

تنزيل الأداة