لو عندك فورم «تواصل معنا» معمول بـ Ninja Forms، فيه احتمال إن أي زائر مجهول يبعتلك رسالة شكلها عادي، وأول ما تفتحها من ووردبريس لتضيف له ميزة جديدة، مثل متجر أو نموذج تواصل أو تحسين للسيو، دون كتابة كود. اختر الإضافات الموثوقة المحدّثة، ولا…">الإضافات والقوالب والمستخدمين والإعدادات، وما يظهر فيها يختلف حسب دور المستخدم.">لوحة التحكم يبقى معاه صلاحيات الأدمن. مفيش باسورد اتسرق ولا سيرفر اتخرق، كله من حقل «الرسالة». خلّينا نفهم حصل إيه، وتتأكد من موقعك في خمس دقايق.
الثغرة في سطور
| البند | التفاصيل |
|---|---|
| المعرّف | CVE-2026-94504 |
| — | — |
| الإضافة (Plugin) | Ninja Forms، الإصدار 3.15.3 وما قبله |
| النوع | الصفحة المصابة، وأخطرها ما يصيب حسابات المديرين لأنه يمنح…">حقن السكربت المخزَّن (Stored السيرفر للمتصفح مع كل صفحة، مثل HSTS وX-Content-Type-Options، لمنع هجمات شائعة في المتصفح. تكلفتها صفر، لكن Content Security Policy يحتاج اختبارًا مع منشئات الصفحات.">CSP من أقوى وسائل الحد…">XSS) — CWE-79 |
| الخطورة | 7.2 من 10 على مقياس CVSS (عالية) |
| من يستغلها | أي زائر بدون تسجيل دخول |
| شرط التنفيذ | أن يفتح المدير الرسالة المصابة |
| الإصلاح | الإصدار 3.15.4 |
كيف تعمل الثغرة؟
يتعامل Ninja Forms مع حقول النص الطويل (Textarea) بنوعين: حقل بمحرر نصوص منسق (RTE)، وحقل نص عادي. المشكلة في النوع الثاني، وتحديدًا في شاشة عرض الرسائل القديمة داخل لوحة التحكم.
تشارك ثلاث نقاط في الكود في صنع الثغرة، وفق إعادة البناء التي نشرها كاتب التحليل الأصلي (الكود التالي إعادة بناء توضيحية وليس منسوخًا حرفيًا من الإضافة):
1) لا تهريب للحقل العادي
// includes/Fields/Textarea.php (3.15.3, reconstructed)
class NF_Fields_Textarea extends NF_Abstracts_Field
{
protected $_type = 'textarea';
// How the value gets rendered in admin screens depends on whether RTE is on.
public function format_value_for_admin_table( $value )
{
if ( ! $this->get_setting( 'rte' ) ) {
// ❌ No esc_textarea() / esc_html() call here.
// The raw submitted string is returned as-is.
return $value;
}
return wp_kses_post( $value ); // RTE fields at least go through wp_kses_post
}
}
افترض المطوّر أن «النص العادي لا يحتاج إلى تهريب»، وهذا افتراض خاطئ بمجرد أن يُطبع النص داخل وسم HTML.
2) فك الترميز يلغي أي حماية سابقة
// includes/Database/Models/Submission.php (3.15.3, reconstructed, ~L205)
class NF_Database_Models_Submission extends NF_Abstracts_Model
{
public function get_field_value_for_editor( $field_id )
{
$value = $this->get_field_value( $field_id ); // raw stored submission value
// ⚠️ Decoded again for legacy editor compatibility —
// e.g. an '<' that was stored encoded gets turned back into '<'.
$value = html_entity_decode( $value, ENT_QUOTES, 'UTF-8' );
return $value;
}
}
حتى لو رمّزت ووردبريس بعض الرموز عند الحفظ، فإن html_entity_decode() يعيدها إلى أصلها قبل العرض مباشرة.
3) الطباعة المباشرة داخل <textarea>
// legacy submission editor template (reconstructed)
<textarea class="widefat" rows="6" disabled>
<?php echo $submission->get_field_value_for_editor( $field_id ); // ❌ no escaping on output ?>
</textarea>
إذا احتوت الرسالة على </textarea> فإنها تُغلق الوسم فعليًا، وكل ما بعدها يُقرأ كـ HTML حي يتضمن سكربت المهاجم.
سيناريو الهجوم خطوة بخطوة
CVE-2026-94504
مسار الهجوم في 4 خطوات
زائر مجهول يرسل النموذج
رسالة تبدأ بـ </textarea> في حقل نص عادي.
الحفظ كما هي
تُخزَّن القيمة في جدول الرسائل دون تهريب.
المدير يفتح الرسالة
فك الترميز ثم طباعة مباشرة بلا esc_textarea.
تنفيذ بصلاحيات المدير
السكربت يستدعي REST API بكوكي المدير.
- الإرسال: يملأ المهاجم حقل «الرسالة» في نموذج عام برسالة تبدأ بـ
</textarea>ويليها وسم HTML يحمل كود JavaScript. يمر الطلب عبرadmin-ajax.phpبالإجراءnf_ajax_submitولا يحتاج إلا إلى الـ Nonce العام الموجود في الصفحة. - التخزين: يحفظ Ninja Forms القيمة في جدول الرسائل كما هي.
- التفعيل: يفتح المدير الرسالة من Submissions في لوحة التحكم، فيُغلق الوسم ويُنفَّذ السكربت في متصفحه.
- السيطرة: يعمل السكربت بكوكي المدير وصلاحياته، فيستطيع استدعاء API في ووردبريس واجهة مدمجة تتيح قراءة المحتوى وإنشاءه وتعديله عبر روابط HTTP تحت /wp-json/، دون فتح لوحة التحكم. عليها تعتمد تطبيقات الموبايل والمواقع المنفصلة…">REST API لإنشاء حساب مدير جديد، أو تغيير كلمة المرور، أو رفع إضافة خبيثة.
الهجوم ليس «بدون نقرة» تمامًا لأنه يحتاج إلى فتح الرسالة، لكن مراجعة الرسائل الجديدة عادة يومية عند أغلب أصحاب المواقع، فالنافذة قصيرة جدًا.
الإصلاح في 3.15.4
أضاف الإصدار الجديد تهريب المخرجات (Output Escaping) عند نقطة الطباعة:
// 3.15.4+ (reconstructed)
<textarea class="widefat" rows="6" disabled>
<?php echo esc_textarea( $submission->get_field_value_for_editor( $field_id ) ); ?>
</textarea>
تحوّل esc_textarea() الرموز < و> و& إلى نص خامل، فلا يهم بعد ذلك ما حدث للقيمة قبل الطباعة.
تحقق من موقعك الآن
- اعرف الإصدار: من Plugins في لوحة التحكم، أو من السطر
Stable tagفي الملفwp-content/plugins/ninja-forms/readme.txt. أي إصدار حتى 3.15.3 مصاب. - حدّث فورًا إلى 3.15.4 أو أحدث؛ هذا هو الحل الموثوق الوحيد. ومن WP-CLI:
wp plugin update ninja-forms
- لا تفتح رسائل مشبوهة وصلت قبل التحديث من الشاشة القديمة، وراجعها من قاعدة البيانات أو بعد التحديث.
- راجع حسابات المديرين من Users بحثًا عن أي حساب لا تعرفه أُنشئ مؤخرًا.
- حل مؤقت إن تعذّر التحديث: عطّل النموذج العام، أو أضف قاعدة في جدار حماية تطبيقات الويب (WAF) مثل Cloudflare تحجب أي طلب يحتوي على
</textarea>.
في Elementor: إن كانت نماذجك مبنية بـ Elementor Pro Forms أو JetFormBuilder فهذه الثغرة تحديدًا لا تخصك، لكن الدرس نفسه ينطبق على أي إضافة نماذج. فعّل التحديثات التلقائية للإضافات الأمنية الحساسة، خصوصًا على مواقع العملاء التي لا تتابعها يوميًا.
الدرس للمطورين: اهرب عند الطباعة
الثغرة لم تنتج عن غياب فلترة المدخلات، بل عن غياب التهريب عند المخرجات. القاعدة في تطوير الإضافات: نظّف عند الحفظ (sanitize_*)، واهرب دائمًا عند الطباعة حسب السياق:
| السياق | الدالة |
|---|---|
| نص داخل HTML | esc_html() |
| — | — |
داخل <textarea> | esc_textarea() |
| قيمة خاصية HTML | esc_attr() |
| رابط | esc_url() |
| HTML مسموح جزئيًا | wp_kses_post() |
اقرأ أيضًا
الأسئلة الشائعة
س: هل موقعي مصاب لو أستخدم Ninja Forms بدون حقل رسالة؟
ج: الخطر يتطلب وجود حقل نص طويل عادي (بدون محرر منسق) في نموذج عام. لكن التحديث يبقى ضروريًا في كل الأحوال.
س: هل يحتاج المهاجم إلى حساب على الموقع؟
ج: لا، يكفي أن يرسل النموذج كأي زائر. التنفيذ يحدث عندما يفتح المدير الرسالة.
س: حدّثت الإضافة، فهل انتهى الخطر؟
ج: التحديث يمنع تنفيذ الرسائل المخزنة مستقبلًا. لكن إن كنت فتحت رسائل مشبوهة قبل التحديث، فراجع حسابات المديرين والإضافات المثبتة وغيّر كلمات المرور ومفاتيح الأمان.
س: ما الفرق بين XSS المخزَّن والعادي؟
ج: في XSS المخزَّن يُحفظ الكود في قاعدة البيانات ويصيب كل من يفتح الصفحة، أما العاكس فيحتاج إلى خداع الضحية لفتح رابط معيّن.
الخلاصة
ثغرة Ninja Forms دي مثال كلاسيكي: سطر تهريب ناقص حوّل فورم تواصل لباب خلفي للوحة التحكم. حدّث الإضافة النهارده، وراجع حسابات الأدمن، ولو بتكتب إضافات بنفسك خلّي esc_* عادة عند كل echo.
مرجع المقال (بالإنجليزية): CVE-2026-94504 Analysis: Ninja Forms Stored XSS
المقال ده مش ترجمة حرفية: متكيّف للقارئ العربي ومضاف عليه سياق ووردبريس وElementor وJetEngine.



