نزّلت LiteLLM 1.107.0 أو سحبت صورة latest؟ شو لازم تعمل هلق

نسخة LiteLLM 1.107.0 وصورها على Docker فيها برنامج بيسرق المفاتيح. لا تشغّل pip بالبيئة المصابة: دوّر على cook.pth بأدوات النظام ونضّف وغيّر كل مفتاح كان الجهاز بيوصله.

نُشر في 15 دقيقة قراءة#أمن سلسلة التوريد#LiteLLM#Python#AI

إذا مشروعك بيحكي مع نماذج الـ <span dir="ltr">AI</span> عن طريق <span dir="ltr">LiteLLM</span>، ويوم 21 تشرين الأول 2026 نزّلت النسخة <span dir="ltr">1.107.0</span>، اعتبر كل مفتاح كان الجهاز بيوصله مسروق. وإذا سحبت صورة <span dir="ltr">Docker</span> بـ <span dir="ltr">tag</span> متل latest بنفس اليوم، أول شي قارن بصمة الصورة (الـ <span dir="ltr">digest</span>) مع بصمات الصور المصابة. <span dir="ltr">LiteLLM</span> مكتبة <span dir="ltr">Python</span> وبوابة (<span dir="ltr">proxy</span>) بتخليك تحكي مع أكتر من مزوّد نماذج بنفس الطريقة، والبوابة بتخزّن مفاتيح هالمزوّدين بقاعدة بيانات <span dir="ltr">PostgreSQL</span>.

مين متأثر بنسخة <span dir="ltr">LiteLLM 1.107.0</span>؟

نسخة <span dir="ltr">LiteLLM 1.107.0</span> بتصيب أي حدا نزّل litellm==1.107.0 من <span dir="ltr">PyPI</span> يوم 21 تشرين الأول 2026، أو سحب صور <span dir="ltr">LiteLLM</span> بـ v1.107.0، أو بـ latest أو main-latest أو main-stable بين 11:48 و14:32 بتوقيت <span dir="ltr">UTC</span> بنفس اليوم. آخر نسخة نضيفة هي <span dir="ltr">1.106.2</span>.

حسب تقرير فريق <span dir="ltr">Upwind</span> يلي فتح التذكرة على ريبو المشروع، كل ملفات الـ <span dir="ltr">wheel</span> السبعة تبع النسخة فيها الكود الخبيث، لـ <span dir="ltr">macOS</span> و<span dir="ltr">Linux</span> و<span dir="ltr">Windows</span>. ملف المصدر (<span dir="ltr">sdist</span>) ما فيه الملفات، بس فيه سطر زايد بـ pyproject.toml. وبـ <span dir="ltr">Docker</span> انصابت أربع صور: ghcr.io/berriai/litellm وlitellm-database وlitellm-non_root على <span dir="ltr">GHCR</span>، وlitellm/litellm على <span dir="ltr">Docker Hub</span>.

الوقت (<span dir="ltr">UTC</span>)

شو صار

08:56 لـ 10:46

10 <span dir="ltr">commits</span> خبيثة على ريبو شبيه اسمه Berri-AI/litellm

11:00 لـ 11:06

انبنت صور <span dir="ltr">Docker</span> تبع v1.107.0 من هالريبو

11:39 لـ 11:40

انرفعت النسخة على <span dir="ltr">PyPI</span>

11:48

انرفعت الصورة على <span dir="ltr">Docker Hub</span>، وصارت latest وmain-latest وmain-stable تأشّر عليها

12:06

<span dir="ltr">Upwind</span> فتحت التذكرة رقم 47826

قبل 13:23

<span dir="ltr">PyPI</span> حجزت النسخة وما عاد فيك تنزّلها (<span dir="ltr">Wiz</span> كاتبة الساعة 1:20، والمقصود غالباً 13:20)

13:30

<span dir="ltr">GitHub</span> شالت ريبو letters9813/pythonclient-test يلي بيقرا منه الكود الخبيث لوين يتصل

حوالي 13:53

<span dir="ltr">Wiz</span> شافت الصور الخبيثة انشالت من <span dir="ltr">GHCR</span> و<span dir="ltr">Docker Hub</span>

14:32

فريق <span dir="ltr">LiteLLM</span> أكّد إنو الصور انشالت، وإنو لسا ما عرف كيف انرفعت النسخة

16:32

فريق <span dir="ltr">LiteLLM</span>: المهاجم اشتغل من حسابات <span dir="ltr">GitHub</span> تبع تلات مهندسين بالفريق، والظاهر بتوكنات مسروقة

الأوقات من تقرير <span dir="ltr">Upwind</span> وتحليل <span dir="ltr">Wiz</span> وردود فريق <span dir="ltr">LiteLLM</span> على التذكرة، لحد الساعة 16:40 بتوقيت <span dir="ltr">UTC</span> يوم 21 تشرين الأول. الفريق وعد بتحديث جاي الساعة 18:30.

يعني إذا ملف المتطلبات عندك فيه litellm بلا رقم نسخة، أو بـ >=، أي تثبيت أو <span dir="ltr">build</span> صار بين 11:39 و13:23 تقريباً ممكن يكون أخد النسخة الخبيثة. ونفس الشي بعد هالوقت إذا التثبيت إجا من <span dir="ltr">mirror</span>: <span dir="ltr">StepSecurity</span> بتقول إنو في <span dir="ltr">mirrors</span> ضلّت تعطي 1.107.0 بعد ما <span dir="ltr">PyPI</span> شالتها. شوف بالـ <span dir="ltr">lockfile</span> أو بسجل الـ <span dir="ltr">build</span> شو انتصب فعلاً. وإذا عندك <span dir="ltr">mirror</span> أو <span dir="ltr">cache</span> داخلي للحزم، <span dir="ltr">StepSecurity</span> بتنصح تلاقي فيه ملفات 1.107.0 بالـ <span dir="ltr">hashes</span> المنشورة وتمسحها.

وبـ <span dir="ltr">Docker</span>، أي <span dir="ltr">container</span> سحب واحد من الـ <span dir="ltr">tags</span> المتحركة، أو رجع اشتغل وسحبه من جديد، بين 11:48 و14:32 تقريباً أخد الصورة المصابة. <span dir="ltr">Wiz</span> شافت الصور انشالت حوالي 13:53، وفريق <span dir="ltr">LiteLLM</span> أكّد الحذف 14:32، و<span dir="ltr">StepSecurity</span> بتعتبر كل سحب أو إعادة تشغيل لحد 14:32 مصاب. والـ <span dir="ltr">container</span> يلي اشتغل من الصورة بيضل مصاب حتى بعد ما انشالت من الـ <span dir="ltr">registry</span>.

المكتبة نزلت 22,778,449 مرة بآخر أسبوع حسب <span dir="ltr">pypistats</span> يوم 21 تشرين الأول، والرقم عدد تنزيلات مش عدد مستخدمين.

تقرير <span dir="ltr">Upwind</span> فحص ملفات الـ <span dir="ltr">wheel</span> تبع نسخ 1.106.0 و1.106.1 و1.106.2 و<span dir="ltr">1.107.0rc1</span> و<span dir="ltr">1.107.0rc2</span>، وست نسخ من خط 1.103 لـ 1.105 (1.103.6 و1.103.7 و1.104.4 و1.104.5 و1.105.2 و1.105.3)، ولقاها نضيفة. وفريق <span dir="ltr">LiteLLM</span> كتب إنو الـ <span dir="ltr">registry</span> الخاص بزبائن <span dir="ltr">Enterprise</span> ما تأثر.

ليش هالحادثة خطيرة على بوابات الـ <span dir="ltr">AI</span> بالذات؟

بوابة <span dir="ltr">LiteLLM</span> بتخزّن مفاتيح كل المزوّدين يلي بتحكي معهن، ونسخة <span dir="ltr">LiteLLM 1.107.0</span> فيها جزء بيسحب هالمفاتيح كلها من قاعدة البيانات دفعة وحدة إذا لقى DATABASE_URL. وفوق هيك، الكود الخبيث بيشتغل مع كل تشغيلة <span dir="ltr">Python</span> بالبيئة، حتى لو مشروعك ما عمل import لـ litellm.

الـ <span dir="ltr">wheel</span> الخبيث بيحط تلات ملفات بأول مجلد site-packages: cook.pth وcook.py وsitecustomize.py. ملف الـ <span dir="ltr">.pth</span> ملف نصي بهالمجلد، و<span dir="ltr">Python</span> بتنفّذ أي سطر فيه بيبلّش بـ import وقت الإقلاع، حتى لو ولا ملف بمشروعك استعمل المكتبة. هيك بيقول توثيق <span dir="ltr">Python</span> لوحدة <span dir="ltr">site</span>. وcook.pth فيه سطر واحد: import cook. أما sitecustomize.py فـ <span dir="ltr">Python</span> بتحاول تستورده لحالها بعد ما تجهّز المسارات. فسيرفر الـ <span dir="ltr">API</span> تبعك و<span dir="ltr">pip</span> نفسه وأي <span dir="ltr">job</span> بالـ <span dir="ltr">CI</span> بنفس البيئة بيشغّلوا الكود الخبيث.

cook.py بيشغّل برنامج سرقة اسمه <span dir="ltr">privcollect</span> بالخلفية. أول ما ينجح الإرسال بيكتب ملف <span dir="ltr">marker</span> بـ /tmp وما بيرجع يشتغل، وطالما الإرسال عم يفشل بيرجع يحاول مع كل تشغيلة <span dir="ltr">Python</span>. حسب تحليل <span dir="ltr">JFrog</span> وتقرير <span dir="ltr">Upwind</span>، بيجمع:

  • مفاتيح <span dir="ltr">AWS</span> و<span dir="ltr">Azure</span> و<span dir="ltr">Google Cloud</span>، والمفاتيح المؤقتة من الـ <span dir="ltr">metadata</span> تبع السيرفر، وبيجرّب مفاتيح <span dir="ltr">AWS</span> بـ GetCallerIdentity ليعرف إذا شغّالة

  • مفاتيح <span dir="ltr">SSH</span> و<span dir="ltr">GPG</span> و<span dir="ltr">TLS</span>، وملفات .env، وتاريخ الـ <span dir="ltr">shell</span>

  • توكنات <span dir="ltr">GitHub</span> و<span dir="ltr">npm</span> و<span dir="ltr">PyPI</span>، وأسرار <span dir="ltr">Jenkins</span> و<span dir="ltr">Vault</span> و<span dir="ltr">Terraform</span>

  • كلمات السر والكوكيز من <span dir="ltr">Chrome</span> وباقي متصفحات <span dir="ltr">Chromium</span> (<span dir="ltr">Edge</span> و<span dir="ltr">Brave</span> وغيرهن)، وملفات كلمات السر والتاريخ من <span dir="ltr">Firefox</span>

  • إعدادات وتوكنات أدوات الـ <span dir="ltr">AI</span>: <span dir="ltr">Claude</span> و<span dir="ltr">Codex</span> و<span dir="ltr">Gemini</span> و<span dir="ltr">Cursor</span> و<span dir="ltr">Copilot</span> و<span dir="ltr">Hugging Face</span>

  • متغيرات البيئة لكل عملية بيقدر يقراها على الجهاز (على <span dir="ltr">Linux</span>)

  • وإذا لقى DATABASE_URL، بيسحب جدولي LiteLLM_CredentialsTable وLiteLLM_ProxyModelTable من قاعدة بيانات البوابة، يعني كل مفتاح مزوّد مخزّن فيها

البيانات بتتشفّر بـ <span dir="ltr">AES-256</span> والمفتاح بـ <span dir="ltr">RSA-4096</span>، وبتنبعت لـ www.litellm[.]dev/healthcheck. هالدومين مش تبع المشروع (موقعه الرسمي litellm.ai)، وانسجّل يوم 13 تشرين الأول. ولأن البيانات مشفّرة، تسجيل الشبكة ما بيورجيك شو طلع بالضبط.

sitecustomize.py بيفتح عملية <span dir="ltr">Python</span> منفصلة بتضل شغّالة بالخلفية، وكل ساعة بتقرا ملف domain.txt من ريبو على <span dir="ltr">GitHub</span>. إذا لقت فيه دومين، بتشغّل برنامج السرقة من جديد، وبتنزّل كود من /codepy على هالدومين وبتنفّذه. الملف كان فاضي من 20 تشرين الأول، و<span dir="ltr">GitHub</span> شالت الريبو الساعة 13:30، بس العملية بتضل شغّالة على كل جهاز مصاب لحد ما تقتلها. على <span dir="ltr">Windows</span> هالجزء بيفشل بصمت، وcook.py بيسرق عادي.

كيف بتعرف إذا جهازك أو الـ <span dir="ltr">container</span> فيه الملفات؟

لحتى تعرف إذا <span dir="ltr">LiteLLM 1.107.0</span> صابت جهازك، دوّر على cook.pth وcook.py وsitecustomize.py بمجلدات site-packages أو dist-packages (على <span dir="ltr">Debian</span> و<span dir="ltr">Ubuntu</span>) بأدوات النظام متل find، بدون <span dir="ltr">pip</span> وبدون أي أمر <span dir="ltr">Python</span>. أي تشغيلة <span dir="ltr">Python</span> بالبيئة المصابة بترجّع تشغّل الكود الخبيث.

<span dir="ltr">JFrog</span> كتبتها صريحة بقسم التنظيف:

«<span dir="ltr">Do not begin remediation by running pip inside an affected environment.</span>»

على <span dir="ltr">Debian</span> و<span dir="ltr">Ubuntu</span>، الحزم يلي بتنتصب برّا نظام حزم <span dir="ltr">Debian</span> (متل sudo pip) بتروح على /usr/local/lib/pythonX.Y/dist-packages، وهاد المجلد على sys.path حسب ويكي <span dir="ltr">Debian</span>، فلازم تدوّر فيه كمان.

على <span dir="ltr">Linux</span> و<span dir="ltr">macOS</span>:

# payload files in any site-packages or dist-packages on this machine
find / \( -path '*site-packages*' -o -path '*dist-packages*' \) \( -name 'cook.pth' -o -name 'cook.py' -o -name 'sitecustomize.py' \) 2>/dev/null

# compare each hit with the published hashes (sha256sum on Linux)
shasum -a 256 /path/to/site-packages/cook.pth /path/to/site-packages/sitecustomize.py

# marker, lock, and the process holding the lock
ls -la /tmp/.pc_once_72129118c59f5636c0bb /tmp/remote_code_loader.lock 2>/dev/null
lsof /tmp/remote_code_loader.lock 2>/dev/null

# where 1.107.0 is pinned in your repo (check the litellm lines)
grep -rn '1\.107\.0' --include='requirements*.txt' --include='*.lock' --include='pyproject.toml' .

وعلى <span dir="ltr">Windows</span> بـ <span dir="ltr">PowerShell</span>:

Get-ChildItem -Path C:\ -Recurse -Filter cook.pth -ErrorAction SilentlyContinue

الـ <span dir="ltr">hashes</span> يلي نشرتها <span dir="ltr">Wiz</span> لنسخ <span dir="ltr">Linux</span> و<span dir="ltr">macOS</span> (نسخ <span dir="ltr">Windows</span> إلها <span dir="ltr">hashes</span> تانية بنفس الصفحة):

الملف

<span dir="ltr">sha256</span>

cook.pth

7f191632e7320705d154b85204f1ae546b543acbd7e8861229b76f5042b92bdb

cook.py

9dd0a3926f96a37eb86cf1ee2310d9be93139cc4ebef3ef9e2efe9531390be25

sitecustomize.py

34bef04fe88ac9d0aae0475630b1738681d15b94f233ac8aa46eacf5968305fa

ملف sitecustomize.py ممكن يكون شرعي ببعض البيئات، و<span dir="ltr">Socket</span> بتنبّه إنو اسمه لحاله ما بيكفي دليل، فقارن الـ <span dir="ltr">hash</span>. وجود cook.pth جنبه هو العلامة الواضحة. وإذا لقيت ملف /tmp/.pc_once_72129118c59f5636c0bb، فالبيانات وصلت للمهاجم أكيد: برنامج السرقة بيكتبه بس بعد ما ينجح الإرسال. غيابه ما بيثبت شي، وعلى <span dir="ltr">Windows</span> هالفحص ما بيفيد لأن الملف غالباً ما بينكتب أصلاً.

صور <span dir="ltr">Docker</span> و<span dir="ltr">Kubernetes</span>

الـ <span dir="ltr">digest</span> بصمة <span dir="ltr">sha256</span> لمحتوى الصورة، والـ <span dir="ltr">tag</span> اسم بيأشّر على وحدة منها وبيقدر يتحرّك. هاي بدايات الـ <span dir="ltr">digests</span> يلي نشرها تقرير <span dir="ltr">Upwind</span> الساعة 13:23:

الصورة

المصابة (v1.107.0 والـ <span dir="ltr">tags</span> المتحركة)

النضيفة (v1.106.2)

ghcr.io/berriai/litellm

sha256:1bbcb1443bc9…

sha256:7294b90f868c…

ghcr.io/berriai/litellm-database

sha256:c00f9d92c427…

sha256:35f2cec3a14b…

ghcr.io/berriai/litellm-non_root

sha256:7b00e91cd2fe…

sha256:07fabea33dfc…

docker.io/litellm/litellm

sha256:1bbcb1443bc9…

sha256:7294b90f868c…

docker images --digests | grep -E 'berriai/litellm|litellm/litellm'
docker exec <container> ls -la /app/.venv/lib/python3.13/site-packages/cook.pth
kubectl get pods -A -o jsonpath='{range .items[*]}{.status.containerStatuses[*].imageID}{"\n"}{end}' | grep -i litellm

شو بتعمل إذا لقيت الملفات؟

إذا لقيت ملفات <span dir="ltr">LiteLLM 1.107.0</span> الخبيثة، اعزل الجهاز واحذفها من الـ <span dir="ltr">shell</span> واقتل عملية <span dir="ltr">Python</span> المنفصلة واحظر الدومين المزيّف، وبعدها غيّر المفاتيح وابني البيئة من جديد. هاد الترتيب يلي بتمشي عليه <span dir="ltr">JFrog</span>.

  1. افصل الجهاز أو الـ <span dir="ltr">container</span> عن الشبكة، وخلي سجلات الـ <span dir="ltr">proxy</span> والـ <span dir="ltr">DNS</span> والسحابة متل ما هي. منها بتعرف شو طلع ولوين.

  2. قبل ما تحذف شي، سجّل شغلتين: هل ملف /tmp/.pc_once_… موجود، وشو رقم العملية (<span dir="ltr">PID</span>) يلي ماسكة ملف القفل حسب lsof.

  3. احذف cook.pth وcook.py من كل site-packages أو dist-packages مصاب، ومعهن ملفاتهن المترجمة بـ __pycache__ وملفات /tmp. واحذف sitecustomize.py بس إذا طابق الـ <span dir="ltr">hash</span> المنشور.

  4. اقتل العملية بـ kill، ودوّر على أي عملية python تانية شغّالة لحالها ومجلدها /. هيك بتبيّن عملية الـ <span dir="ltr">loader</span> حسب <span dir="ltr">Upwind</span>.

  5. احظر litellm[.]dev وكل شي تحته بالـ <span dir="ltr">DNS</span> أو الجدار الناري (شيل الأقواس وقت تكتبه)، ودوّر بالسجلات على الدومين وعلى raw.githubusercontent.com/letters9813/ وعلى أي طلب لـ /codepy.

  6. غيّر المفاتيح من جهاز تاني نضيف، حسب القسم الجاي.

  7. ابني البيئة أو الصورة من الصفر على litellm==1.106.2، وامسح صور v1.107.0 من الـ <span dir="ltr">cache</span> عندك.

أوامر الخطوة 3، بعد ما تحط المسار المصاب مكان /path/to/site-packages:

SP=/path/to/site-packages
rm -f "$SP/cook.pth" "$SP/cook.py" "$SP"/__pycache__/cook*.pyc
# sitecustomize.py only if it matches the malicious hash (sha256sum on Linux)
[ "$(shasum -a 256 "$SP/sitecustomize.py" | cut -d' ' -f1)" = 34bef04fe88ac9d0aae0475630b1738681d15b94f233ac8aa46eacf5968305fa ] && rm -f "$SP/sitecustomize.py" "$SP"/__pycache__/sitecustomize*.pyc
rm -f /tmp/.pc_once_72129118c59f5636c0bb /tmp/remote_code_loader.lock

إذا ما لقيت ولا ملف، بس النسخة انتصبت عندك بأي وقت على جهاز عنده إنترنت، <span dir="ltr">Upwind</span> بتقول اعتبر إنو البيانات طلعت. والخطوات 5 و6 و7 إلك كمان.

أي مفاتيح لازم تغيّر بعد <span dir="ltr">LiteLLM 1.107.0</span>؟

بعد <span dir="ltr">LiteLLM 1.107.0</span> لازم تغيّر كل مفتاح كان الجهاز أو الـ <span dir="ltr">container</span> بيوصله، وأولها مفاتيح المزوّدين المخزّنة بقاعدة بيانات البوابة. برنامج السرقة بيسحبها كلها إذا لقى DATABASE_URL.

القائمة من تقرير <span dir="ltr">Upwind</span> وتحليل <span dir="ltr">StepSecurity</span> و<span dir="ltr">JFrog</span>:

  • مفاتيح المزوّدين بجدول LiteLLM_CredentialsTable وبإعدادات الموديلات (litellm_params). ألغي القديمة واعمل جديدة من لوحة كل مزوّد أول، بعدين حط الجديدة بالبوابة.

  • الـ <span dir="ltr">master key</span> والـ <span dir="ltr">virtual keys</span> ومفتاح الـ <span dir="ltr">salt</span> تبع البوابة، وكلمة سر قاعدة البيانات يلي بـ DATABASE_URL.

  • دور الـ <span dir="ltr">IAM</span> تبع السيرفر أو الـ <span dir="ltr">task</span>، وأي مفاتيح سحابة على الجهاز. وبـ <span dir="ltr">CloudTrail</span> دوّر على GetCallerIdentity من دور السيرفر حوالي وقت التثبيت، وعلى أي استعمال لنفس المفاتيح من برّا بنيتك.

  • أي سر كان بمتغيرات البيئة لأي عملية على الجهاز، مش بس عملية البوابة.

  • مفاتيح <span dir="ltr">SSH</span> و<span dir="ltr">GPG</span> وشهادات <span dir="ltr">TLS</span>، وتوكنات <span dir="ltr">GitHub</span> و<span dir="ltr">npm</span> و<span dir="ltr">PyPI</span>.

  • على جهاز مطوّر: كلمات السر المحفوظة بالمتصفح، وتوكنات وكلاء البرمجة.

انتبه لمفتاح الـ <span dir="ltr">salt</span> قبل ما تغيّره: حسب توثيق <span dir="ltr">LiteLLM</span>، هو يلي بيشفّر المفاتيح المخزّنة بقاعدة البيانات، وتغييره بيخليها ما بتنقرا، وما في طريقة تنقلها عالمفتاح الجديد. فغيّره مع إعادة إدخال كل مفاتيح المزوّدين الجديدة من الأول، وخود نسخة احتياطية من القاعدة قبل. وإذا ما عندك <span dir="ltr">salt key</span>، الـ <span dir="ltr">master key</span> هو مفتاح التشفير، وتغييره بدّه خطوات إعادة التشفير يلي بنفس الصفحة.

برنامج السرقة بيدوّر على إعدادات <span dir="ltr">Claude</span> و<span dir="ltr">Codex</span> و<span dir="ltr">Cursor</span> و<span dir="ltr">OpenCode</span> وغيرهن. إذا بتشغّل <span dir="ltr">Claude Code</span> أو <span dir="ltr">OpenCode</span> على نفس الجهاز (وهني البيئات يلي ببني إلها مهارات <span dir="ltr">AI</span>)، ألغي جلسة <span dir="ltr">Claude Code</span> وأي مفتاح <span dir="ltr">API</span> كان مستعمل فيها، وبـ <span dir="ltr">OpenCode</span> غيّر مفاتيح المزوّدين يلي بملف auth.json تبعه، وبعدين سجّل دخول من جديد.

بعد ما تغيّر مفاتيح المزوّدين، حط سقف صرف وتنبيه على كل حساب. <span dir="ltr">Wiz</span> نشرت يوم 20 تشرين الأول عن حملة تانية مختلفة بتورجي قديش بتوصل الفاتورة لما حدا يشغّل <span dir="ltr">Gemini</span> على حسابك: المهاجمين تصيّدوا حسابات <span dir="ltr">Google Cloud</span> بصلاحيات عالية وربطوا مشاريعهن بحساب الفوترة تبع الضحية، والفواتير وصلت لعشرات ومئات آلاف الدولارات. و<span dir="ltr">Wiz</span> نصحت تراقب أي قفزة غريبة بالاستهلاك وتحط سقف للصرف.

كيف وصل الكود الخبيث لنسخة رسمية من <span dir="ltr">LiteLLM</span>؟

نسخة <span dir="ltr">LiteLLM 1.107.0</span> انبنت من ريبو شبيه اسمه Berri-AI/litellm، مش من ريبو المشروع BerriAI/litellm، والـ <span dir="ltr">tag</span> الرسمي v1.107.0 نضيف. وفريق <span dir="ltr">LiteLLM</span> كتب الساعة 16:32 إنو المهاجم شغّل أداة الإصدار من حسابات <span dir="ltr">GitHub</span> تبع مهندسين بالفريق، والظاهر بتوكنات مسروقة.

سجل البناء (<span dir="ltr">provenance</span>) المرفق مع صور <span dir="ltr">Docker</span> بيسمّي مصدر الكود github.com/Berri-AI/litellm، ونفس أداة الإصدار بنت 1.106.1 و1.106.2 و<span dir="ltr">1.107.0-rc.2</span> من BerriAI/litellm، حسب تقرير <span dir="ltr">Upwind</span>. المهاجم حط 10 <span dir="ltr">commits</span> فوق <span dir="ltr">commit</span> شرعي من الفرع الرئيسي، وأول تسعة عليهن شارة <span dir="ltr">Verified</span>. <span dir="ltr">GitHub</span> بتوقّع أي <span dir="ltr">commit</span> بينعمل من محرر الويب تبعها، فالشارة هون بتقول بس إنو الـ <span dir="ltr">commit</span> انعمل من محرر الويب على <span dir="ltr">github.com</span> بحساب Berri-AI، وما بتقول إنو الحساب تبع فريق المشروع.

نفس التحديث بيقول إنو الحسابات تلاتة، والتوكنات الظاهر إنها توكنات <span dir="ltr">OAuth</span> تبع <span dir="ltr">GitHub CLI</span>: بحساب شغّل المهاجم أداة الإصدار project-releaser، وبحساب تاني وافق على التشغيلة. الفريق ألغى كل التوكنات يلي انستعملت، وشال مؤقتاً كل الأعضاء من منظمته على <span dir="ltr">GitHub</span> إلا واحد ما تأثر، وشال من سجلات الحزم العامة أي ربط موثوق بمنظمته لحتى ما تنرفع نسخة خبيثة تانية. بس لسا ما عرف كيف وصلت التوكنات للمهاجم، ولا الطريق الأصلي للهجوم، فما بيقدر يأكد إنو المهاجم ما عاد عنده وصول لهالحسابات.

وهاي تاني مرة هالسنة: بآذار 2026 انرفعت نسختين خبيثتين، 1.82.7 و1.82.8، ببيانات نشر مسروقة. <span dir="ltr">JFrog</span> ما لقت دليل بيربط الحادثتين، وبتعاملهن كحملتين منفصلتين. ولا وحدة من <span dir="ltr">Upwind</span> و<span dir="ltr">Wiz</span> و<span dir="ltr">JFrog</span> و<span dir="ltr">StepSecurity</span> و<span dir="ltr">Socket</span> سمّت فاعل لحد 21 تشرين الأول.

لأن الـ <span dir="ltr">tag</span> نضيف والملف المنشور خبيث، مراجعة الكود بالريبو ما كانت رح تكشف شي. <span dir="ltr">JFrog</span> بتنصح تفحص الملف يلي عم تنزّله نفسه: قائمة ملفاته (RECORD) وأي ملف بيشتغل وقت الإقلاع.

كيف بتحمي مشروعك من النسخة الخبيثة الجاية؟

لحتى ما تاخد نسخة خبيثة متل <span dir="ltr">LiteLLM 1.107.0</span> بلا ما تنتبه، ثبّت كل مكتبة على نسخة محددة ومعها الـ <span dir="ltr">hash</span> تبعها، وثبّت صور <span dir="ltr">Docker</span> بالـ <span dir="ltr">digest</span> مش بالـ <span dir="ltr">tag</span>. وما تحدّث <span dir="ltr">LiteLLM</span> لأحدث من <span dir="ltr">1.106.2</span> لحد ما الفريق يعلن إنو سكّر الطريق.

بـ <span dir="ltr">pip</span> اسمها <span dir="ltr">hash-checking mode</span>، وهي بتحمي من إنو حدا يبدّل الملف يلي بتنزّله، حسب توثيق <span dir="ltr">pip</span>. كل مكتبة لازم تكون مثبّتة بـ ==، والـ <span dir="ltr">hashes</span> لازمة لكل التبعيات مش بس المباشرة. و<span dir="ltr">LiteLLM 1.106.2</span> على <span dir="ltr">PyPI</span> سبع ملفات <span dir="ltr">wheel</span> وملف مصدر، فحط <span dir="ltr">hash</span> لكل <span dir="ltr">wheel</span> بتستعمله (<span dir="ltr">macOS</span> و<span dir="ltr">Linux</span> و<span dir="ltr">Windows</span>). عملياً بتحتاج أداة بتولّد الملف كامل وبتعمل هالشي عنك، بدل ما تكتبه بإيدك:

litellm==1.106.2 \
    --hash=sha256:<hash-of-the-linux-wheel> \
    --hash=sha256:<hash-of-the-macos-wheel>
pip install --require-hashes -r requirements.txt

<span dir="ltr">Docker</span> بتقول بتوثيقها إنو الـ <span dir="ltr">tags</span> بتتغيّر، والناشر بيقدر يخلي الـ <span dir="ltr">tag</span> يأشّر على صورة جديدة، وهاد يلي صار مع latest وmain-stable. خود الـ <span dir="ltr">digest</span> وثبّت الصورة عليه:

docker buildx imagetools inspect ghcr.io/berriai/litellm:v1.106.2
services:
  litellm:
    image: ghcr.io/berriai/litellm:v1.106.2@sha256:<digest-from-inspect>

المقابل إنو تحديثات الأمان ما رح توصلك لحالها، و<span dir="ltr">Docker</span> بتقترح أداة متل <span dir="ltr">Dependabot</span> تحدّث الـ <span dir="ltr">digest</span> المثبّت. راجع كل تحديث قبل ما تدمجه.

وعن <span dir="ltr">LiteLLM</span> نفسها: الفريق طلب الساعة 14:32 تثبيت <span dir="ltr">1.106.2</span> أو أي نسخة محددة كانت منشورة قبل هالوقت (غير 1.107.0). و<span dir="ltr">Upwind</span> طلبت من الفريق يعامل الإصدار الجاي كمشكوك فيه لحد ما يغيّر بيانات النشر ويراجع بيئة البناء، فاستنى إعلانهم قبل ما تحدّث.

وإذا إنت بتنشر حزم <span dir="ltr">Python</span> بنفسك، متل أداة <span dir="ltr">Nexus-REC</span> يلي نشرتها على <span dir="ltr">PyPI</span> وموجودة بالمشاريع، خود اقتراح <span dir="ltr">Upwind</span> لـ <span dir="ltr">LiteLLM</span>: انشر بـ <span dir="ltr">Trusted Publishing</span> ومع <span dir="ltr">attestations</span>. المشروع ما نشر <span dir="ltr">attestations</span> على <span dir="ltr">PyPI</span> ولا مرة، فمستخدم <span dir="ltr">pip</span> ما كان عنده طريقة يفرّق فيها بين ملف شرعي وملف معدّل. صور <span dir="ltr">Docker</span> كان معها <span dir="ltr">provenance</span>، ومنه انكشف الريبو الشبيه. الـ <span dir="ltr">attestation</span> حسب توثيق <span dir="ltr">PyPI</span> توقيع بيربط كل ملف بالنسخة بهوية يلي نشره، متل <span dir="ltr">workflow</span> محددة على <span dir="ltr">GitHub Actions</span>.

وإذا منتجك الـ <span dir="ltr">AI</span> عالإنتاج وبدك حدا يفحص منصتك ويسلّمك خطة إصلاح، هاد شغل مُحَصَّن. هلق افتح ملف المتطلبات: شو مكتوب جنب litellm، رقم نسخة ولا بس الاسم؟

أسئلة شائعة

إذا مشروعي ما بيعمل import لـ litellm، بكون بأمان؟

لأ. ملف cook.pth بيشتغل مع أي تشغيلة Python بنفس البيئة، حتى pip نفسه، لأن Python بتنفّذ أسطر import بملفات .pth وقت الإقلاع حتى لو ولا ملف بمشروعك استعمل المكتبة.

هل نسخ 1.107.0rc1 و1.107.0rc2 متأثرة؟

لأ. تقرير Upwind فحص كل ملفات الـ wheel تبعهن ولقاهن نضيفين، ومعهن 1.106.0 و1.106.1 و1.106.2. أما نسخ 1.107.0.dev1 لـ dev3 فلسا موجودة على PyPI وما انفحصت حسب StepSecurity، فابعد عنها.

ما لقيت ملف /tmp/.pc_once، يعني ما انسرق شي؟

لأ. الملف بينكتب بس بعد ما توصل البيانات للمهاجم، والـ containers وتنظيف /tmp بيمسحوه، وعلى Windows غالباً ما بينكتب أصلاً. إذا 1.107.0 انتصبت على جهاز عنده إنترنت، اعتبر إنو البيانات طلعت.

هل Windows متأثر متل Linux وmacOS؟

إي. الجزء تبع sitecustomize.py بيفشل على Windows، بس cook.py بيسرق هونيك كمان. وغالباً ما بيقدر يكتب ملف الـ marker لأن /tmp مش موجود، فبيرجع يسرق مع كل تشغيلة Python، وفحص /tmp ما بيفيدك.

أنا زبون Enterprise وبسحب من الـ registry الخاص تبع LiteLLM، بتأثر؟

لأ. فريق LiteLLM كتب يوم 21 تشرين الأول 2026 إنو الـ registry الخاص بزبائن Enterprise ما تأثر.

إمتى بقدر حدّث LiteLLM لنسخة أحدث من 1.106.2؟

لما فريق LiteLLM يعلن إنو عرف كيف انرفعت النسخة الخبيثة وسكّر الطريق. لحد تحديثهم الساعة 16:32 بتوقيت UTC يوم 21 تشرين الأول، لسا ما عرفوا الطريق الأصلي للهجوم. والساعة 14:32 طلبوا تثبيت 1.106.2 أو أي نسخة محددة كانت منشورة قبل هالوقت، غير 1.107.0.

مقالات أخرى