מי שטוען מודלים מ-Hugging Face עם הספרייה diffusers והקפיד להשאיר את trust_remote_code כבוי, הניח מן הסתם שהוא מוגן מהרצת קוד של מישהו אחר. בגרסאות שקודמות ל-0.38.0 ההנחה הזאת לא החזיקה, ולא במקרה אחד אלא בשלושה. הציון הוא 8.8 והתיקון נמצא בגרסה 0.38.0.
מה החולשה?
כדי להבין את הבאג צריך לדעת איפה בדיוק יושבת ההגנה. ב-diffusers, הבדיקה שמחליטה אם מותר להריץ קוד שהגיע ממאגר חיצוני מומשה בתוך הפונקציה שמורידה את המודל. זה נשמע סביר, כי משם הקוד מגיע. אלא שהפונקציה שמורידה אינה הפונקציה שמריצה, ולא כל מסלול טעינה עובר דרכה.
זה כל שורש העניין: כשהמנעול מותקן על שלב ההורדה במקום על שלב הטעינה, כל דרך שמדלגת על ההורדה מדלגת גם על המנעול. הרשומה מונה שלוש דרכים כאלה.
בראשונה, המשתמש טוען מודל ממאגר אחד ומציין במפורש צנרת מותאמת ממאגר שני, של התוקף. הבדיקה מסתכלת על רשימת הקבצים של המאגר הראשון, זה שממנו נטען המודל, ומאשרת. הקוד שנטען בסוף הוא של המאגר השני.
בשנייה, המודל נטען מתיקייה מקומית במקום מהרשת, ולצדה מצוינת צנרת מותאמת ממאגר של תוקף. מסלול הטעינה המקומי אינו קורא לפונקציית ההורדה בכלל, ולכן הבדיקה לא מגיעה לרוץ.
בשלישית כבר אין שום פרמטר חשוד. המודל נטען מתיקייה מקומית שמכילה קובצי רכיב מותאמים, למשל unet/my_unet_model.py, שקובץ ההגדרות model_index.json מפנה אליהם. אותו מסלול מקומי, אותו דילוג, והקוד רץ.
הווריאציה השלישית היא המטרידה שבהן, מפני שתיקייה מקומית לא נשמעת כמו קלט של תוקף. בפועל היא בדיוק זה: תמונת מצב של מאגר שירדה פעם אחת מהרשת ויושבת עכשיו על הדיסק. בכל שלוש הדרכים המשתמש העביר trust_remote_code=False, או לא העביר כלום, שזאת ברירת המחדל.
מי מושפע?
כל גרסה של diffusers שקודמת ל-0.38.0, לפי הרשומה.
הקהל כאן הוא מי שכותב קוד, לא מי שמשתמש במוצר מוגמר. בישראל אלה צוותי דאטה, חוקרים ומפתחי מוצר שמושכים מודלים מוכנים ומריצים אותם מקומית. מה שמייחד את החולשה הזאת הוא שהיא אינה דורשת מהמשתמש לעשות שום דבר חריג: בווריאציה השלישית מספיקה טעינה של תיקייה שכבר נמצאת אצלו.
הרשומה מקושרת גם למעקב של Red Hat אחרי החולשה, שמנטרת אותה עבור החבילות שהיא מפיצה.
האם מנוצלת בפועל?
החולשה אינה מופיעה בקטלוג ה-KEV, הרשימה שבה סוכנות הסייבר האמריקאית CISA מרכזת חולשות עם ראיות לניצול בשטח, ולא פורסם דיווח על ניצול שלה.
שווה בכל זאת לשים לב לרמת הפירוט. הרשומה מתארת את שלושת המסלולים ברמת הפרמטר והקריאה, כך שמי שקורא אותה יודע בדיוק מה לנסות.
מה עושים?
עברו ל-diffusers בגרסה 0.38.0 ומעלה. זאת הגרסה שבה הבדיקה הועברה למקום הנכון, ושום הגדרה בגרסה ישנה אינה מחליפה אותה.
זאת הנקודה החשובה ביותר כאן: אל תסתמכו על trust_remote_code=False כהגנה זמנית עד שתספיקו לשדרג. הפרמטר הזה הוא בדיוק מה שנשבר, ומי שמשאיר גרסה ישנה בהנחה שהדגל מגן עליו מחזיק הגנה שלא פועלת.
בדקו מה כבר יושב אצלכם במטמון המקומי. מכיוון שהמסלול המקומי הוא אחד מווקטורי התקיפה, תיקיית מודל שירדה בעבר ומכילה קובצי .py ראויה למבט, ו-model_index.json הוא הקובץ שבו מופיעות ההפניות אליהם.
התיאור המלא של שלוש הווריאציות נמצא בהודעת האבטחה של הפרויקט.