الأمن
الـ middleware ليس authorization
4 ثغرات في NestJS خلال 7 أشهر، وكلها ثغرة واحدة: الـ matcher والـ handler اختلفا على العنوان نفسه. مكان التحقق هو حيث تُقرأ البيانات.
في 11 أيار 2026، بين الساعة 20:19 و22:56 بتوقيت UTC، دفع شخص يملك publish token مسروقاً 18 إصداراً من @beproduct/nestjs-auth — من 0.1.2 حتى 0.1.19 — تحمل payload دودة سلسلة التوريد Mini Shai-Hulud. تُتابَع باسم CVE-2026-46412 بدرجة 10.0، ولا إصدار مُعالَج لها، لأنه لا علاج لـ package كانت خبيثة عن قصد. أزالتها npm.
الـ payload كان يعمل عند التنصيب ويبحث عن بيانات الاعتماد: npm tokens وGitHub PATs وOAuth tokens وOIDC tokens التي تستخدمها مهام الـ CI للمصادقة لدى مزوّدي السحابة. ثم يستخدمها لينشر نفسه أبعد. هذا ما يجعلها دودة لا سرقة: كل مطوّر نصّبها صار ناشراً لها.
لم يكن على أحد أن يشغّل التطبيق. كان npm install كافياً.
الـ lifecycle script — سواء preinstall أو install أو postinstall — هو كود من غريب، تنفّذه الـ shell عندك، بحساب المستخدم نفسه، وببيئته. والبيئة تحوي NPM_TOKEN وGITHUB_TOKEN و~/.ssh و~/.aws وملف .env، وعلى الـ CI رمز OIDC قادر على توليد اعتمادات سحابية.
نقبل هذا مئة مرة يومياً لأن البديل يبدو غير عملي. وهو ليس كذلك.
نصّب مع تعطيل الـ scripts. في معظم شجرات الـ dependencies ينجح هذا ببساطة:
npm ci --ignore-scriptsبعض الـ packages تحتاج خطوة build حقيقية — الـ native modules غالباً. حدّدها وأدرجها واسمح لها وحدها بدل السماح للجميع. وإن كنت تستخدم pnpm، فخيار onlyBuiltDependencies يعبّر عن هذا بالضبط.
لا تنصّب من floating range في الـ CI. الأمر npm ci ينصّب الـ lockfile، أما npm install فقد يحلّ مدى ^ إلى إصدار نُشر قبل تسع دقائق. الإصدارات الـ 18 الخبيثة أعلاه كانت كلها داخل ^0.1.0 عند أحدهم.
أخّر التبنّي. فترة cooldown — رفض تنصيب أي إصدار نُشر في الأيام القليلة الماضية — كانت لتغطي نافذة هذه الحادثة كاملة، ومعظم ما يشبهها. الإصدارات الخبيثة بقيت حيّة ساعات لا أسابيع.
ضيّق نطاق الـ tokens. publish token يستطيع دفع كل package تملكها خسارة أكبر من واحد يدفع package واحدة. فضّل OIDC قصير العمر على الأسرار طويلة العمر في الـ CI، وأبقِ الـ publish tokens خارج حواسيب المطوّرين تماماً.
الثغرة CVE-2025-54782 في @nestjs/devtools-integration، والمعالَجة في 0.2.1، هي الدرس نفسه من الجهة المقابلة. كانت الـ package تشغّل HTTP server محلياً بـ sandbox غير آمن ودون حماية من طلبات cross-origin، فأي موقع يزوره المطوّر أثناء عملها كان بإمكانه تنفيذ كود على جهازه.
الـ dev server المربوط بـ localhost ليس خاصاً. كل صفحة في المتصفح تستطيع إرسال طلبات إليه. عامل أدوات التطوير على أنها شيء يجب أن يُطفأ حين لا تستخدمه، وثبّتها خارج dependencies الإنتاج.
افترض أن كل بيانات الاعتماد التي كانت في تلك البيئة قد ضاعت، ودوّرها كلها: npm tokens وGitHub tokens وSSH keys ومفاتيح السحابة، وكل ما في ملف .env على ذلك الجهاز. ثم اقرأ audit logs في npm وGitHub بحثاً عن عمليات publish وpush لم تقم بها — فالسرقة ليست الضرر، بل استعمال المسروق.
وبالنسبة لشركة تنشر مشاريع الآخرين، الانكشاف ليس حاسوباً واحداً، بل كل عميل كان deploy key الخاص به على ذلك الحاسوب.
لا تستطيع قراءة كل dependency. لا أحد يفعل. لكن ما تستطيعه هو أن تتوقف عن منح تنفيذ الكود وقت التنصيب افتراضياً، وأن تتوقف عن حلّ الإصدارات وقت الـ build، وأن تحمل اعتمادات تنتهي صلاحيتها. لا شيء من هذا يتطلب أن تثق بالمنظومة أقل مما ينبغي أن تثق به أصلاً، بهدوء.
الأمن
4 ثغرات في NestJS خلال 7 أشهر، وكلها ثغرة واحدة: الـ matcher والـ handler اختلفا على العنوان نفسه. مكان التحقق هو حيث تُقرأ البيانات.
الأمن
ثغرة RCE بدرجة 10.0، ثم 6 ترقيعات DoS في 8 أشهر. حين يكون العقد "اقبل كل ما يرمّزه الـ protocol"، فإغلاق ثغرة يترك البقية.
الأمن
16 advisory في يوم واحد عبر 14 مشروعاً، ومعظمها access bypass. الحل ليس مزيداً من الاجتهاد، بل قائمة modules أقصر.