בסביבות 09:00 לפי UTC ב-4 באוגוסט, התוקפים קיבלו שליטה על חשבון GitHub של Wray. באמצעות הגישה הזו הם הזריקו קוד זדוני ישירות לענף main של מאגר keyv, ולאחר מכן פרסמו גרסאות חדשות לאורך משפחת החבילות keyv ו-cacheable .
גל ההדבקה הראשוני כלל 11 חבילות בשני מרחבי השמות, ובהן keyv, cacheable-request, cache-manager, @cacheable/utils, flat-cache ו-file-entry-cache . חוקרים מ-Aikido Security, StepSecurity, Socket ו-Chainguard אישרו את הפגיעה באופן בלתי תלוי בשעות הראשונות .
בכל חבילה נגועה הופיעו שני קבצים חדשים — setup.mjs ו-Math_Symbol.js — וכן שינוי ב-package.json שהוסיף את וו ההתקנה הבא:
"preinstall": "node setup.mjs"
המשמעות היא שכל מפתח או מערכת CI שהריצו npm install על גרסה נגועה הפעילו את setup.mjs באופן אוטומטי, עוד לפני שההתקנה הושלמה .
setup.mjs שימש כטוען ראשוני (dropper): הוא הוריד מ-GitHub בינארי לגיטימי של סביבת הריצה Bun, ולאחר מכן הפעיל באמצעותו את השלב השני — קובץ JavaScript מעורפל ומוצפן-למחצה בשם Math_Symbol.js, בגודל של כ-710–728 ק״ב .
Microsoft Threat Intelligence אישרה שמדובר בגרסה של Mini Shai-Hulud . המטען נועד לאסוף מגוון רחב של סודות והרשאות מסביבות פיתוח, תחנות עבודה ושרתי CI/CD, ובהם :
הסיבה שהאירוע התרחב במהירות הייתה היכולת של התולעת להתרבות בעצמה. לאחר שגנבה אסימוני פרסום של npm ואסימוני GitHub מהסביבה הנגועה, היא השתמשה בהם כדי לפרסם גרסאות זדוניות של חבילות נוספות — גם כאלה שהיו בבעלות מתחזקים וארגונים אחרים .
המספרים השתנו במהירות במהלך אותו יום:
התולעת לא נשארה בתוך משפחת keyv ו-cacheable. היא חצתה גבולות של מרחבי שמות והגיעה לחבילות הקשורות, בין היתר, ל-Deliveroo, Ornikar, OneReach, Picsart, Qlik ו-ServiceTitan .
ההרשאות שנאספו הועברו למאגר GitHub שהיה בשליטת התוקפים. לפי החוקרים, התולעת יצרה מאגר ייעודי להוצאת המידע או השתמשה במאגר שהוכן לכך מראש . המטען כלל גם כמה ערוצי הוצאה חלופיים, כך שהפעילות יכלה להימשך גם אם ערוץ יחיד הוסר .
חוקרי אבטחה ממספר חברות המליצו להתייחס לכל מחשב או שרת שהריץ גרסה נגועה כאל מערכת שנפרצה במלואה. מחיקת הקבצים הזדוניים בלבד אינה מספיקה .
יש לבדוק את עצי התלויות ואת קובצי הנעילה — package-lock.json, yarn.lock ו-pnpm-lock.yaml — ולוודא שגם תלויות עקיפות אינן כוללות גרסה נגועה .
כדאי להצמיד את החבילות לגרסאות שנבדקו כנקיות או לחזור לגרסה שקדמה לאירוע. אפשר להשתמש ב-overrides של npm, או במנגנונים המקבילים ב-yarn וב-pnpm, כדי למנוע התקנה חוזרת של גרסאות מורעלות .
אין להסתפק בהסרת הקבצים מ-node_modules. כל סוד שהיה זמין בסביבה בזמן הרצת npm install על גרסה נגועה עלול להיחשף, כולל סודות שהוזרקו למשתני סביבה או נשמרו בכלי CI/CD .
יש לבטל ולהחליף את כל ההרשאות שעלולות היו להיות זמינות למטען, ובהן :
זהו פרט קריטי בסדר הפעולות: בחלק מהמקרים הנוזקה התקינה מאזיני GitHub Actions או מנגנוני מעקב שיכלו לחשוף מחדש אסימון מיד לאחר יצירתו. לכן יש להשבית או להסיר תחילה את מנגנון המעקב החשוד, ורק לאחר מכן לבצע את החלפת ההרשאות .
יש לנקות את מטמוני npm, pnpm ו-yarn, וכן את מטמוני בניית Docker, הן במחשבי מפתחים והן ב-runners של CI/CD . לאחר מכן מומלץ לבנות את כל הארטיפקטים מחדש מאפס, כדי למנוע מחבילות נגועות להישאר במטמון הבנייה או בשכבות Docker .
יש לחפש מאגרים חדשים, workflows לא מורשים, קומיטים חשודים ואפליקציות OAuth שלא אושרו . החוקרים המליצו לבדוק גם קובצי התמדה שהנוזקה עלולה ליצור, כגון .claude/settings.json או .vscode/tasks.json .
המתקפה המחישה כיצד חשבון מתחזק יחיד יכול להפוך לנקודת מוצא לפגיעה רחבת היקף: מרגע שהושגו הרשאות פרסום ואסימוני גישה, התולעת יכלה לנוע בין חבילות של מתחזקים שונים ולהפיץ את עצמה במהירות.
השימוש ב-Bun לגיטימי להפעלת המטען, ההתרבות באמצעות אסימונים שנגנבו וערוצי ההוצאה העודפים הפכו את הקמפיין למורכב יותר ממתקפות שרשרת אספקה קודמות . עבור צוותי פיתוח ואבטחה, הלקח המרכזי הוא לא להסתמך רק על חתימות או על מוניטין של חבילה: יש לנעול תלויות, לבחון סקריפטים מסוג preinstall ו-postinstall, לנטר פעילות חריגה ב-GitHub ולהחזיק נוהל תגובה מוכן לאירועי פגיעה בתלויות תוכנה.