ב-14 וב-15 במרץ 2025 הוחלף מה שרץ מאחורי tj-actions/changed-files, רכיב נפוץ ב-GitHub Actions. התגיות שלו, מ-v1 ועד v45.0.7, הופנו אל commit יחיד שמזההו 0e58ed8, ובו קוד שמדפיס סודות אל יומן ההרצה. הציון הוא 8.6 מתוך 10, ו-CISA סימנה את החולשה כמנוצלת בפועל ב-18 במרץ 2025.
מה החולשה?
job ב-GitHub Actions מקבל לעבודה את הסודות שהוגדרו לו, ומריץ בתוך אותה סביבה רכיבים מוכנים שנכתבו בידי אחרים. רכיב כזה אינו מופרד ממה שמסביבו: מה שה-job מחזיק זמין גם לו. הקוד שהושתל כאן ניצל בדיוק את זה, וכתב את הסודות אל יומן ההרצה. יומן הרצה אינו כספת. במאגר פרטי הוא נקרא בידי מי שיש לו גישה למאגר, ובמאגר ציבורי הוא נקרא בידי כל אחד. ברשומה זה מסומן CWE-506, קוד זדוני מושתל.
עד כאן זה נשמע כמו כל השתלטות על רכיב חיצוני. מה שמייחד את המקרה הזה הוא ההיקף של השינוי, וכדאי לעצור עליו רגע. לא תגית אחת הוזזה. כל התגיות של הפרויקט, לאורך כל ההיסטוריה שלו ועד v1, הופנו אל אותו commit. המשמעות המעשית היא שצוות שבחר במכוון להישאר על גרסה ותיקה ויציבה, ולא לרדוף אחרי העדכון האחרון, קיבל בדיוק את אותו קוד כמו מי שהיה על החדשה ביותר. הזהירות לא הועילה כאן, כי מה שהיא נאחזה בו היה שם ולא תוכן.
זה השיעור שנשאר גם אחרי שהאירוע הזה נסגר: תגית היא תווית שמישהו הצמיד ל-commit, ומי ששולט במאגר יכול להזיז אותה. מזהה commit, לעומת זאת, נגזר מהתוכן עצמו ולכן אי אפשר להפנות אותו למקום אחר.
שווה גם לדייק מה הדירוג טוען. הוא מסמן פגיעה גבוהה בסודיות בלבד, ואפס בשלמות ובזמינות. כלומר מה שתועד הוא חשיפה של סודות, לא שינוי של הקוד שלכם ולא השבתה של משהו. מה שאפשר לעשות עם הסודות האלה אחר כך הוא כבר סיפור נפרד, ולא נמדד כאן.
מי מושפע?
הרכיב הוא tj-actions/changed-files בכל גרסה עד 45.0.7 ועד בכלל. הגרסה שסוגרת היא 46.
הקהל כאן אינו מנהלי מערכות אלא צוותי פיתוח. changed-files הוא הרכיב שמזהה אילו קבצים השתנו ב-commit או ב-pull request, וזה מה שמאפשר להריץ בדיקות רק על מה שנגעו בו במקום על כל המאגר. הוא מופיע בעיקר אצל צוותים שהשקיעו בצינור בנייה מסודר, ובישראל GitHub Actions הוא הסביבה הרווחת לכך בחברות תוכנה.
מצד שני, יש כאן שני גורמים שמצמצמים. הראשון הוא הזמן: חלון החשיפה נמשך יומיים, ומי שלא הריץ workflow בתוכם לא נפגע, גם אם הוא משתמש ברכיב הזה שנים. השני הוא הנראות של היומן: במאגר פרטי מעגל הקוראים מצומצם למי שיש לו הרשאה, במאגר ציבורי אין מעגל.
האם מנוצלת בפועל?
כן, ובמקרה הזה הניצול הוא האירוע עצמו. הקוד רץ אצל מי שהריץ workflow בחלון הזה, וכתב את מה שהיה לו. ב-18 במרץ 2025 נוספה החולשה לקטלוג ה-KEV של סוכנות הסייבר האמריקאית CISA, שמרכז חולשות שידוע על שימוש בהן בתקיפות, והמועד שנקבע לגופים הפדרליים האמריקאיים לסיום הטיפול היה 8 באפריל 2025.
מה עושים?
1. בררו קודם אם בכלל הרצתם בחלון. בלשונית Actions של המאגר, סננו לפי 14 וב-15 במרץ 2025 וחפשו הרצה שהשתמשה ב-changed-files. אם אין, אתם מחוץ לאירוע, וההמשך כאן הוא שדרוג רגיל.
2. אם מצאתם הרצה כזאת, החליפו כל סוד שה-job הזה יכול היה לגעת בו. זה הצעד שאין לו תחליף, כי שדרוג הרכיב אינו מוחק סוד שכבר נכתב ליומן. לפני שמחליפים, שווה להסתכל ביומן ההרצה עצמו ולראות מה נמצא שם, וגם לקבוע מי יכול לקרוא אותו: אם המאגר ציבורי, ההנחה צריכה להיות שהסודות פורסמו.
3. עברו ל-changed-files בגרסה 46 ומעלה.
4. הצמידו רכיבים לפי מזהה commit ולא לפי תגית. מול התקיפה הזאת זה היה עובד, כי כל כולה התבססה על הזזת תגיות: מזהה commit שכתוב אצלכם בקובץ ה-workflow לא היה מצביע לשום מקום אחר.