في 21 أكتوبر الساعة 11:39 بتوقيت UTC رُفعت سبع حزم من litellm==1.107.0 إلى PyPI. كل واحدة حملت برمجية خبيثة مُجمّعة: سارق بيانات اعتماد يقوم أيضاً بتنزيل وتشغيل أدوات تنفيذ كود عن بُعد. بعد ثماني دقائق كانت وسوم Docker وGHCR latest وmain-latest وmain-stable تشير إلى البناء المسموم نفسه.
بحلول 13:23 أُزيلت الحزمة. وبحلول 14:20 أُعيد توجيه وسوم الحاويات.
ساعتان. وقت كافٍ ليُثبّتها مشغّل CI، ويستوردها حاسوب محمول، وتخرج مجموعة مفاتيح API من المبنى.
إذا كنت تبني أي شيء بالذكاء الاصطناعي، فهذه هي بيئتك الآن. ليست استعارة ولا قصة مزوّد من قطاع آخر. LiteLLM هو الوسيط الذي تضعه فرق كثيرة أمام OpenAI وAnthropic وBedrock للحصول على واجهة واحدة ومفتاح واحد وفاتورة واحدة. وحين يُخترق، يرث الاختراق كل مفاتيح المزوّدين التي خزّنتها داخله.
الجزء الذي سيتجاوزه الجميع
الفشل المثير ليس البرمجية الخبيثة، بل كيفية توقيع الإصدار.
أمضت LiteLLM السنة التالية لحادثة مارس في تحصين خط النشر: إصدارات من مستودع خاص، وناشرو GitHub الموثوقون، ووسوم غير قابلة للتغيير، وصور موقّعة، وحاسوب نشر محبوس في المكتب. وبحسب روايتهم، لم يكسر المهاجم أياً من هذه الضوابط. استخدم بيانات اعتماد كان مسموحاً لها أصلاً بتشغيلها:
- رمز OAuth لواجهة GitHub يعود لمطور، وقادر على تشغيل مسارات العمل.
- رمز يعود لمالك مؤسسة على GitHub، قادر على تجاوز حماية الفروع وفرض تغيير في مسار النشر بقوة.
- بيانات اعتماد حساب ثالث، استُخدمت بعد النشر لحذف سجلات التشغيل.
من أين جاء الرمز الأول؟ من سجل.
وجد تحقيق LiteLLM أن Claude Code يدرج أحياناً رمز OAuth الخاص بواجهة GitHub للمستخدم داخل جسم الرد. وكان وسيطهم يسجّل أجسام الردود. انتهى الرمز في سجل نشر داخلي لـ LiteLLM مكشوف على الإنترنت. قرأ مهاجم يملك حساباً على ذلك النشر السجلات، وأخذ الرمز، ودخل إلى خط النشر.
اقرأ السلسلة مرة أخرى. لا أحد نفّذ تصيداً. لا أحد كسر كلمة مرور. مساعد برمجة تستخدمه فرق كثيرة اليوم وضع بيانات اعتماد حيّة في رد لم يكن يجب أن تحتويها، فكتبتها طبقة المراقبة على القرص، وكان القرص قابلاً للوصول.
لماذا هذه ليست مشكلة LiteLLM
النمط ينطبق على كل بيئة ذكاء اصطناعي في شركة عادية هذا الأسبوع:
- رموز الوصول تتحرك داخل سياق النموذج. تلصق الوكلاء الترويسات ومتغيرات البيئة ومخرجات الطرفية داخل الردود. وكل ما في الرد يمكن تسجيله أو تخزينه مؤقتاً أو تتبعه أو تقييمه.
- الوسطاء جامعون لبيانات الاعتماد. بوابة الذكاء الاصطناعي تحتفظ بمفاتيح كل مزوّد توجّه إليه. وظيفياً هي مدير أسرار بواجهة HTTP.
- الوكلاء يرثون هوية المطوّر. إذا كان مساعدك يعمل بجلسة
ghوصلاحيات مستودعاتك، فالرمز المسروق ليس «رمزاً»، بل أنت. - النشرات الخفية بلا مالك. «حساب مستخدم باسم غير مثير» على نشر داخلي مكشوف على الإنترنت هو أكثر اكتشاف عادي في العالم، وأغلاه ثمناً.
وشهد الأسبوع نفسه تحذيراً ثانياً مستقلاً. أعلنت Railway أن طرفاً غير مصرّح له ربما وصل إلى متغيرات بيئة مشفّرة، وحصل في بعضها على محتواها المفكوك، ورجّحت أن الحملة استهدفت شركات منصّات للوصول إلى مزوّدي استدلال الذكاء الاصطناعي. وطلبت من كل عملائها تدوير كل المفاتيح.
مزوّدان، أسبوع واحد، الفئة نفسها من الأصول: بيانات اعتماد تعيش بجوار بنية الذكاء الاصطناعي.
الضوابط الأربعة التي كانت ستقطع هذه السلسلة
لا شيء من هذا غريب. كل حلقة في السلسلة تُقتل بشيء ممل.
1. اعتبر السجلات سطح بيانات اعتماد. امسح عند الكتابة، لا عند القراءة. إذا كان جسم الرد قد يحتوي رمز حامل أو رمز OAuth أو سلسلة اتصال، فعلى المسجّل تصفيته قبل وصوله إلى التخزين. أبقِ مدة الاحتفاظ قصيرة لكل ما يحمل تعليمات وردوداً، واعتبر أي مخزن سجلات احتوى رموزاً حدثاً يستوجب التدوير.
2. افصل «النشر» عن «التجاوز». بوابة النشر كانت موجودة وتعمل. ما فشل هو أن الفئة نفسها من الهويات كانت قادرة على تعطيلها. حماية فرع يستطيع مالك مؤسسة تعطيلها برمز واحد هي اقتراح مع سجل تدقيق. يجب أن تكون صلاحية النشر خلف بيانات اعتماد قصيرة العمر مرتبطة بالعتاد وشخص ثانٍ، ولا شيء آخر يجب أن يعدّل مسار العمل الذي يستخدمها.
3. ثبّت ثم أثبت. pip install litellm بلا إصدار هو أمر بتشغيل آخر ما نشره الإنترنت. ثبّت إصدارات محددة وبصمات للصور. ثم اذهب أبعد: ملف القفل ادعاء لا دليل. أنشئ SBOM، وتحقق من التواقيع حيث توجد، وقارن ما تفعله النسخة الجديدة فعلاً في بيئتك.
4. افترض الانكشاف، ليكون الرد قائمة تحقق لا جدالاً. إرشادات LiteLLM نفسها هي النموذج: إذا ثبّتته، فاعتبر البيئة مخترقة. احذف ملفات الإسقاط، واقتل الخدمة التي تحتفظ بـ/tmp/remote_code_loader.lock، ودوّر دور النسخة السحابية، وكل مفتاح مزوّد في قاعدة الوسيط، والمفاتيح الرئيسية والافتراضية، وDATABASE_URL. ثم راجع CloudTrail بحثاً عن GetCallerIdentity من دور النسخة وقت التنصيب، وعن استخدام بيانات ذلك الدور من خارج بنيتك.
ما يجب فعله هذا الأسبوع
إذا كنت تشغّل وسيط LiteLLM، أنجز هذا قبل الاثنين:
pip show litellmعلى كل خادم وصورة ومشغّل CI. أي نسخة 1.107.0 مخترقة، لا «مُحتمل اختراقها».- ابحث في نظام الملفات عن
litellm-1.107.0.dist-infoوcook.pthوsitecustomize.py. الغياب لا يثبت شيئاً، والوجود يؤكد الانكشاف. - دوّر مفاتيح المزوّدين، والمفاتيح الرئيسية والافتراضية، وكلمة مرور قاعدة البيانات، ودور النسخة السحابية.
- إن كنت على Railway، دوّر متغيرات البيئة وبيانات اعتماد السجل الخاص.
- دقّق من يستطيع تعديل مسارات النشر، واحذف رموز مالك المؤسسة من كل ما هو مؤتمت.
إن أردت من يمشي معك في البيئة خطوة بخطوة، فهذا نوع العمل الذي ننفذه كمشروع بسعر ثابت: جرد بيانات الاعتماد، والتدوير، وضوابط خط النشر التي توقف الحالة التالية. اكتب إلى [email protected].
الخلاصة غير المريحة
الرواية المريحة أن مزوّداً مرّ بأسبوع سيئ. الرواية الدقيقة أن بيئة الذكاء الاصطناعي الحديثة تجمع ثلاثة أشياء لم تُصمّم لتعيش معاً: نموذج يكرّر بسعادة أي رمز في سياقه، ووسيط يخزّن مفاتيح كل شيء، وأدوات نشر تثق ببيانات اعتماد أكثر مما تثق بإنسان.
نافذة البرمجية الخبيثة كانت ساعتين. وأثر بيانات الاعتماد الذي تركته سيعيش أطول منها. أصلح الأثر.