في كل مرة تظهر هجمة جديدة على npm يتكرّر السؤال نفسه: «ما رقم الثغرة؟». والجواب في 2026 صار ثابتاً إلى حدّ مزعج: لا يوجد رقم. تحليل غطّى 59 حملة و657 حزمة خبيثة عبر npm وPyPI وأدوات وكلاء الذكاء الاصطناعي انتهى إلى صفر ثغرات مسجّلة.

هذا ليس تقصيراً في التوثيق، بل وصف دقيق لما يحدث. المهاجم لا يكسر شيئاً في الكود — يسجّل الدخول بحساب صائن حقيقي وينشر نسخة جديدة. من وجهة نظر السجلّ كله، العملية سليمة تماماً.

الرقم الذي يفسّر كل شيء

دودة بلا ثغرة: لماذا تتجمّع هجمات سلسلة التوريد في npm تحديداً؟ — برمجة وتطوير

قبل الحديث عن الهجمات، رقمان يقلبان السرد الشائع.

انخفضت البرمجيات الخبيثة في PyPI بنسبة 43% وفي NuGet بنسبة 60%، بينما استوعبت npm الحصّة الأكبر من الحجم المُزاح. القراءة المباشرة: ضوابط السجلّات تعمل فعلاً، والمهاجمون لا يصرّون على هدف محصَّن — ينتقلون إلى الأسهل.

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

كيف تشتغل الدودة فعلياً

الأحداث الكبرى في 2026 تشترك في بنية واحدة تقريباً:

  1. رسالة تصيّد تنتحل صفة npm — «تحقّق من حسابك» أو «تنبيه أمني». الصائن يدخل كلمة المرور، وحين يكون التحقّق بخطوتين ضعيفاً أو غائباً يُلتقط رمز النشر معه.
  2. نشر نسخة خبيثة بحمولة تعمل عبر خطّاف دورة الحياة preinstall أو postinstall — أي أن مجرّد npm install يشغّل الكود، بلا استيراد الحزمة أصلاً.
  3. سرقة الأسرار من جهاز الضحية — رموز npm، بيانات اعتماد سحابية، مفاتيح واجهات برمجية.
  4. الانتشار الذاتي — الدودة تستخدم الرموز المسروقة للوصول إلى حسابات أخرى وتنشر نفسها فيها. الحلقة تدور بلا تدخّل بشري.

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

حوادث تستحقّ المعرفة

الحادثة التاريخ الحجم ما يميّزها
Axios مارس 2026 حزمة أساسية واسعة الانتشار اختراق حساب صائن رئيسي، وحمولة تنصّب باب خلفي على ويندوز وماك ولينكس
node-ipc مايو 2026 +10 مليون تنزيل أسبوعياً ثلاث نسخ خبيثة دفعة واحدة عبر خطّي إصدار — تعظيم متعمّد لدائرة الأثر
IronWorm يونيو 2026 37 حزمة في 9 منظّمات قفزة هندسية: ملف Rust مُصرَّف بدل سكربت، تشفير نصوص، واتصال قيادة عبر Tor
ChainDrop أغسطس 2026 +400 حزمة، +1300 نسخة دودة تسرق بيانات الاعتماد بحمولة مبهمة، بمجموع تنزيلات يقارب ملياري شهرياً

النقلة في IronWorm تحديداً تستحقّ وقفة. الانتقال من سكربت جافاسكريبت مقروء إلى ملف ثنائي مُصرَّف بلغة Rust ليس مجرّد تحسين تقني — إنه يُخرج الحمولة من متناول أدوات الفحص التي تقرأ النصوص، ويشير إلى فرق تعمل باحتراف لا إلى هواة يجرّبون.

وحادثة node-ipc تحمل الدرس العملي الأوضح: النسخ الخبيثة التُقطت تلقائياً من مشاريع تستخدم محدّدات نطاق مثل ^ و~. لم يفعل أحد شيئاً خاطئاً — الإعداد الافتراضي هو الذي جلب الكود.

ما فعلته npm فعلاً

خلافاً للانطباع الشائع بأن «لا أحد يتحرّك»، جرت في السجلّ أكبر عملية تشديد منذ سنوات:

  • إلغاء الرموز التقليدية نهائياً في 9 ديسمبر 2025 — تلك الرموز الطويلة الأجل بلا تاريخ انتهاء كانت العمود الفقري لكل عمليات الاستيلاء تقريباً.
  • رموز دقيقة بعمر أقصاه 90 يوماً، والرموز الجديدة ذات صلاحية الكتابة تنتهي افتراضياً خلال 7 أيام.
  • النشر المحلي انتقل إلى جلسات قصيرة مدّتها ساعتان بدل الرموز الدائمة.
  • النشر الموثوق عبر OIDC، وهو الحلّ الجذري: لا يوجد رمز نشر في نظام البناء أصلاً كي يُسرق، مع بيان مصدر موقّع لكل إصدار.

لكن من الإنصاف ذكر القيود الحقيقية:

  • النشر الموثوق مدعوم فقط على منفّذات GitHub وGitLab المستضافة — لا يعمل على المنفّذات الذاتية.
  • أول نسخة من أي حزمة يجب نشرها يدوياً؛ لا يمكن ضبط النشر الموثوق إلا بعدها.
  • متغيّر NODE_AUTH_TOKEN يجب أن يكون غير معرَّف تماماً، لأن القيمة الفارغة تبقى قيمة سيحاول npm استخدامها بدل الانتقال إلى OIDC. هذا سبب شائع لفشل التهيئة.

ونقد منظّمة OpenJS يستحقّ الإصغاء: نقل النشر إلى التكامل المستمر يقلّل خطر سرقة الرمز، لكنه يزيد أثر اختراق خطّ البناء، ويقلّل قابلية التدقيق العلني حين تمرّ الإصدارات عبر حسابات آلية. إلغاء الرموز القديمة يفرض هجرة متأخّرة، لكنه لا يجعل الإصدار عبر التكامل المستمر آمناً تلقائياً.

خمس خطوات مرتّبة بالأثر لا بالعدد

  1. عطّل سكربتات التثبيت. استخدم npm ci --ignore-scripts في التكامل المستمر. هذه الخطوة وحدها تُبطل غالبية الحمولات المذكورة أعلاه، لأنها جميعاً تعتمد على خطّافات دورة الحياة. بعض الحزم تحتاج السكربتات فعلاً — استثنِها بالاسم، لا تفتح الباب كلّه.
  2. ثبّت الإصدارات واحترم ملف القفل. npm ci لا npm install في البناء. محدّدات النطاق هي ما جلب النسخ الخبيثة في حادثة node-ipc.
  3. أضف فترة تهدئة. ارفض أي حزمة نُشرت خلال آخر 7 أيام. أغلب الإصابات تُكتشف وتُزال خلال ساعات أو أيام؛ تأخير التبنّي أسبوعاً يُخرجك من النافذة التي تقع فيها الأغلبية — دفاع بالوقت لا بالتحليل.
  4. إن كنت تنشر حزمة، انتقل إلى النشر الموثوق. الرمز غير الموجود لا يُسرق. وإن تعذّر، فرمز دقيق قصير العمر مع تحقّق بخطوتين مدعوم بجهاز مادي.
  5. دوّر بيانات الاعتماد بعد أي حادثة في تبعياتك، لا بعد أن تتأكّد أنك متأثّر. الدودة تسرق أولاً وتنتشر لاحقاً؛ والانتظار حتى التأكّد هو بالضبط المدّة التي تحتاجها.

أسئلة شائعة

هل أنا متأثّر لو لم أستخدم الحزم المذكورة مباشرة؟

ربما. الخطر ليس في تبعياتك المباشرة بل في شجرة التبعيات كاملة — الحزم المصابة غالباً تبعيات لتبعيات. الفحص العملي: npm ls <اسم-الحزمة> يخبرك إن كانت موجودة في الشجرة، ومراجعة ملف القفل تكشف النسخة المثبّتة بالضبط.

هل التحقّق بخطوتين كافٍ لحماية حسابي كصائن؟

كافٍ ضد إعادة استخدام كلمة المرور، وغير كافٍ ضد التصيّد المتقن. صفحة تصيّد تطلب الرمز وتمرّره فوراً إلى npm تتجاوز التحقّق المبني على الرموز المؤقّتة. الحماية الفعلية هي مفتاح أمان مادي أو passkey، لأنه مرتبط بالنطاق ولا يعمل على صفحة مزيّفة.

لماذا لا يحلّ الفحص الآلي المشكلة ببساطة؟

لأن الفحص يبحث عن أنماط معروفة، والحمولات صارت مُصرَّفة ومشفَّرة النصوص. الفحص طبقة مفيدة لكنها لاحقة للحدث بطبيعتها؛ أمّا تعطيل السكربتات وفترة التهدئة فيعملان بلا حاجة إلى معرفة مسبقة بالحمولة — وهذا ما يجعلهما أرخص وأمتن.

الخلاصة

ما يحدث في npm ليس قدراً محتوماً للمصادر المفتوحة. تراجع الهجمات في PyPI وNuGet يثبت أن الضوابط تعمل، وأن المهاجم ينتقل إلى الأسهل بدل أن يصرّ على المحصَّن.

والدرس الذي يخصّك مباشرة: الهجمات هذه لا تستهدف ثغرة في كودك، بل تستهدف الثقة الافتراضية في أن تثبيت حزمة عملية آمنة. تعطيل السكربتات، وملف قفل محترم، وأسبوع تهدئة — ثلاثة إعدادات تُضبط مرّة واحدة وتبطل الجزء الأكبر من هذه الفئة كلها. وهي أرخص بكثير من اكتشاف أن مفاتيحك السحابية غادرت جهازك أثناء npm install روتيني.