ב-4 באוגוסט 2026 נדחף קומיט זדוני לענף הראשי של מאגר keyv, ותוך פחות מארבע שעות הפיצה נוזקה גרסאות נגועות של מאות חבילות npm נוספות. אופן השגת הגישה לא אומת עד היום. השאלה המעניינת אינה "האם השתמשנו בחבילה שנפגעה", אלא למה ההגנות שספקי תוכנה ביטחוניים הטמיעו בשנתיים האחרונות — נעילת גרסאות, רשימת רכיבי תוכנה (SBOM — Software Bill of Materials) וחתימות מקור (provenance) — לא עצרו את זה.
מה קרה, ואיך קוראים לזה באמת
השם שרץ בתקשורת המקצועית הוא ChainDrop. אין זה שם רשמי של npm, של GitHub או של רשות ממשלתית — חוקרי אבטחה הצמידו אותו לקמפיין, וחלק מהספקים אימצו אותו. Elastic Security Labs, שזיהתה את האירוע ב-4 באוגוסט 2026, מתייחסת אליו כאל "קמפיין Shai-Hulud חדש". Chainguard מכנה אותו "Mini Shai-Hulud" — כינוי ששימש קודם לכן גם לגל אחר באותה שושלת — ומגדירה אותו כ"הגל השלישי המתועד של אותה ערכת כלים ב-2026". רשות הסייבר של סינגפור פרסמה התרעה שכותרתה נוקבת בשם Shai-Hulud ובגופה מזכירה את הכינוי ChainDrop.
המשמעות המעשית: אירוע אחד, שלושה שמות
מערכת ניהול סיכונים שמחפשת "ChainDrop" בלבד תפספס חלק מהדיווחים; מערכת שמחפשת "Shai-Hulud" בלבד עלולה לערבב בין גל אוגוסט 2026 לגלים הקודמים באותה שושלת — התרעת CISA "פגיעה נרחבת בשרשרת האספקה של מערכת npm" מ-23 בספטמבר 2025, והנחיות Microsoft לגל Shai-Hulud 2.0, שהופיע בנובמבר 2025 ושההנחיות לגביו פורסמו ב-9 בדצמבר 2025 — אירועים נפרדים, עם רשימות חבילות שונות.
הרצף עצמו מתועד היטב. StepSecurity ו-Datadog Security Labs מתעדות דחיפת קומיט זדוני לענף הראשי של מאגר keyv סביב 09:02 UTC, ופרסום הגרסה הנגועה keyv 6.0.0 ל-npm ב-09:35 UTC. תשע חבילות נוספות מאותה מערכת אקולוגית פורסמו בין 10:09 ל-10:14, ואחת-עשרה חבילות נפגעו ישירות (הרשימה המלאה בהמשך). הגל השני — הרפליקציה האוטומטית — התפרס עד 13:20 UTC.
המנגנון שהופך פריצה לתולעת
השתלטות על זהות מתחזק היא סיפור ישן. מה שהופך את האירוע הזה לקטגוריה אחרת הוא שהמטען עצמו יודע לפרסם את עצמו הלאה.
ההרצה נעשית דרך וו preinstall בקובץ ההגדרות של החבילה — יכולת לגיטימית של npm שמריצה פקודות לפני התקנה. כפי שמנסחת זאת Snyk: אין צורך לייבא את keyv, להפעיל אפליקציה או לקרוא לפונקציה פגיעה; עצם ההתקנה מספיקה. הטוען הראשוני, בגודל 29,918 בתים, בודק אם סביבת הריצה Bun מותקנת במערכת, מוריד אותה מהמקור הרשמי אם לא, ומריץ מטען שני מעורפל בגודל 727,680 בתים.
המטען אוסף פרטי גישה לפי מעל 300 תבניות שונות, לפי Unit 42 של Palo Alto Networks — אסימוני GitHub ו-npm, פרטי גישה לענן של AWS, Azure ו-GCP, מפתחות SSH, מחרוזות התחברות למסדי נתונים, אסימוני HashiCorp Vault ואסימוני שירות של Kubernetes. עוזר Python מוטמע סורק את זיכרון התהליכים החי של רץ GitHub Actions כדי לחלץ אסימוני OIDC וסודות של ה-workflow.
ואז מגיע החלק שהופך את זה לתולעת. Microsoft מתארת את הלולאה כך: הנוזקה מורידה את קובץ ה-tarball האחרון של חבילה שאליה יש הרשאת פרסום, מעתיקה לתוכה את חבילת הנוזקה, מוסיפה טוען, מחליפה את סקריפטי מחזור החיים, מעלה את מספר הגרסה ומפרסמת מחדש. Datadog מוסיפה פרט קריטי: המסלול דורש אסימון גישה מפורט של npm המוגדר עם עקיפת אימות דו-שלבי והרשאת כתיבה. ההתפשטות נשענה אפוא על סוג אסימון ספציפי, שנמצא במסלול הוצאה משימוש שטרם הושלם.
הפצת פרטי הגישה הגנובים נעשתה בשני ערוצים: העלאה מוצפנת ב-AES-256-GCM לשרת שליטה, ובמקביל יצירת מאגרי GitHub ציבוריים תחת זהות הקורבן. Wiz מתעדת שהמאגרים האלה נוצרו עם תיאור ברירת מחדל אחיד — "Shai-Hulud: Here We Go Again". Unit 42 מתעדת שכתובות שרתי השליטה נשלפו מחוזה חכם על רשת Ethereum, מנגנון שמנטרל חסימת דומיין בודד.
לבסוף, שכבה שלא הייתה בגלים הקודמים: הנוזקה שתלה ווי הרצה בקבצי תצורה של סביבת הפיתוח עצמה — משימה שרצה בפתיחת תיקייה בקובץ המשימות של VS Code, ווי הרצה מסוג SessionStart בקובץ ההגדרות של Claude Code. The Register מצטט את Abby Kearns, מנכ"לית ActiveState: זהו "הקמפיין הראשון ששם לב לפער הזה ומשתמש בו בקנה מידה — והוא לא יהיה האחרון".
המספרים — ולמה הם לא מסתדרים
כאן צריך זהירות, וגם דיוק בייחוס — חלק מהפער בין הדיווחים הוא הבדל בין ספירת שמות חבילות לספירת גרסאות, וחלק ממנו הוא מקורות שונים שספרו דברים שונים.
המספר 444 מופיע אצל שני מקורות בלבד: StepSecurity ו-Aikido. Elastic נוקטת "מעל 400 חבילות npm ייחודיות", Microsoft "יותר מ-400 חבילות", ו-Datadog אינה נוקבת במספר כולל אלא ב"מאות חבילות". אין כאן התכנסות של השוק על 444, אלא שני מקורות שנוקבים במספר מדויק ואחרים שנוקבים בסדר גודל.
מספר הגרסאות שנוי במחלוקת ממש. Aikido, בעדכון מ-5 באוגוסט 2026, נוקבת ב-444 חבילות על פני 1,381 גרסאות; רשות הסייבר של סינגפור ב"מעל 1,300 גרסאות חבילה"; StepSecurity ב-444 חבילות ו-2,212 גרסאות. Chainguard, בזמן אמת ב-4 באוגוסט, כתבה ש"הנתונים המדווחים נעים בין כ-400 לכ-2,200" — ניסוח שממחיש בעצמו את הבלבול בין חבילות לגרסאות.
מה שאפשר לומר בלי לחרוג מהמקורות: שמות החבילות הם בסדר גודל של 400 עד 450, ומספר הגרסאות נע בין 1,300 ל-2,212 לפי המקור ומועד הספירה, ואין ספירה רשמית של המרשם שמכריעה ביניהם. סך ההורדות החודשי של החבילות שנפגעו מדווח כמעל שני מיליארד בידי רשות הסייבר של סינגפור ו-Aikido, ו-Aikido מדווחת על כ-127 מיליון הורדות שבועיות ל-keyv לבדה.
תגובת המרשם הייתה מהירה: StepSecurity מתעדת שהסרות הגרסאות החלו ב-10:39 UTC, ו-keyv 6.0.0 הוחזרה לגרסה תקינה סביב 11:15 UTC — חלון חשיפה של פחות משעתיים לחבילה הראשונה, וארוך יותר לחבילות הגל השני.
למה נעילת גרסאות, SBOM ו-provenance הן תשובות חלקיות
זו הנקודה המרכזית לספק שמשלב שרשרת בנייה מבוססת Node.js במוצר.
provenance מאמת בנייה, לא מקור
הגרסאות הזדוניות לא עקפו את מנגנון הפרסום המהימן של npm — הן השתמשו בו. התוקף דחף קומיט לענף הראשי והפעיל את תהליך השחרור הקיים, כך שהמטען פורסם דרך OIDC עם אסמכתה חתומה ותקפה של GitHub Actions. Socket מנסחת את זה בחדות: "provenance מאשר שלמות בנייה, לא שלמות מקור. הצינור של npm ו-sigstore עשה בדיוק את מה שהוא נועד לעשות, ועדיין הפיק אישור חתום ובר-אימות לנוזקה, כי המקור שממנו נבנתה כבר היה נגוע." אם בקרת האימות שלכם מסמנת "provenance תקין" כירוק — היא הייתה ירוקה גם כאן.
קובץ הנעילה מגן חלקית, ולעיתים פועל נגדכם
StepSecurity מציינת שמשימת בנייה שמתקינה תלויות מאפס — מצבן של חלק ניכר ממשימות הבדיקה — נפתרת מול המרשם לפי הגרסה האחרונה הזמינה, לא לפי נעילה קיימת. בכיוון ההפוך, Snyk מזהירה שגרסה נגועה יכולה להישאר נעולה בקובץ גם אחרי ש-npm החליפה את תגית ההפצה — הנעילה משמרת את הגרסה הרעה.
SBOM עונה על השאלה רק אם הוא מוצמד לבנייה הנכונה
SBOM כולל שם רכיב ומספר גרסה, ולכן SBOM שהופק מהבנייה עצמה כן יכול לזהות שגרסה נגועה נכללה בארטיפקט. המגבלה אינה מהותית אלא תפעולית: SBOM שנוצר לפני 4 באוגוסט 2026 מתעד את הגרסאות הנקיות ולא יגיד מה נמשך בפועל לתוך ה-CI באותו בוקר. SBOM ישן, חלקי או כזה שאינו משקף את הבנייה שבוצעה — עונה על "האם החבילה הזאת בכלל אצלנו", לא על "האם הותקנה גרסה נגועה".
סריקת תלויות לא הסתכלה במקום הנכון
The Register מדגיש שההתפשטות נעשתה ברמת ה-tarball ולא ברמת המאגר, כך שסקירת קוד המקור אינה מגלה דבר; וווי ההרצה בקבצי התצורה של VS Code ושל Claude Code נמצאים מחוץ לתחום שכלי סריקת תלויות בוחנים.
מה כן עוצר התפשטות
ארבע בקרות מתועדות כיעילות מול משפחת המתקפות הזאת:
חסימת סקריפטי התקנה
StepSecurity קובעת שהרצת CI ללא סקריפטי מחזור חיים "מנטרלת לחלוטין את מחלקת הטוענים הזאת — קבצי המטען היו נשארים מונחים על הדיסק ללא הרצה". זו הבקרה בעלת ההשפעה הגדולה ביותר מול נתיב ה-preinstall שנצפה כאן, אך עלותה אינה אפס: היא חוסמת גם בניות node-gyp מרומזות, ולכן חבילות שדורשות שלב בנייה מקומי מחייבות מיפוי, אישור פרטני ותחזוקת רשימת היתר.
npm בגרסה 12
גרסה זו שוחררה ב-8 ביולי 2026 — פחות מחודש לפני האירוע — והפכה את חסימת הסקריפטים לברירת מחדל, לצד חסימת תלויות Git ותלויות מכתובות URL מרוחקות. אלא שלפי Socket, צוות npm "מקווה להטמיע את גרסה 12 לאחור לתוך Node 24 ו-Node 26", והחלטה זו תלויה בצוות השחרור של Node. כלומר בסביבות בנייה שרצות על גרסת LTS של Node, ההגנה הזאת לא הייתה פעילה כברירת מחדל בזמן האירוע — וזה, להערכתי, חלק מההסבר לקנה המידה. ברירת המחדל היא גם דילוג רך עם אזהרה ולא כשל קשה; להתנהגות נוקשה נדרשת אכיפה מפורשת ב-CI.
אסימונים קצרי-חיים ומדיניות פרסום
GitHub ביטלה לצמיתות את כל אסימוני npm הישנים ב-9 בדצמבר 2025 והחליפה אותם באסימוני התחברות לשעתיים ובאסימוני כתיבה מוגבלים ל-90 יום. במקביל, לפי הודעת השינויים מ-8 ביולי 2026, אסימוני גישה מפורטים המוגדרים לעקיפת אימות דו-שלבי מאבדים יכולות ניהול חשבון וחבילה בתחילת אוגוסט 2026, ואת יכולת הפרסום הישירה רק סביב ינואר 2027. מכיוון שזהו בדיוק סוג האסימון שהתולעת חיפשה, הערוץ העיקרי שלה נסגר סופית רק בינואר 2027.
בקרת יציאה מרשת הבנייה
StepSecurity מציינת שרשימת היתר ליציאה חוסמת את הורדת סביבת הריצה Bun, אך מסייגת שסינון מבוסס דומיין לבדו אינו מספיק — השליטה נשענת על עשרות נקודות קצה ציבוריות של רשת Ethereum.
מה ספק צריך לבדוק עכשיו
רשימה מצומצמת וישימה, לפי ההנחיות של רשות הסייבר של סינגפור, Wiz ו-Snyk:
- חפשו את 11 החבילות שנפגעו ישירות — לפי שם ומספר גרסה — בקובצי הנעילה, במטמון של npm ובתמונות מכולה שנבנו אחרי 4 באוגוסט 2026 בשעה 09:35 UTC. הרשימה המלאה לפי StepSecurity: keyv 6.0.0, flat-cache 6.1.24, file-entry-cache 11.1.6, cacheable-request 13.0.20, cacheable 2.5.1, cache-manager 7.2.10, ecto 5.0.1, @cacheable/utils 2.5.1, @cacheable/memory 2.2.1, @cacheable/node-cache 3.1.2 ו-@cacheable/net 2.1.1. חפשו בקובצי הנעילה, לא רק בתלויות המוצהרות — ואל תסתפקו בגל הראשון: מאות חבילות הגל השני מחייבות בדיקה מול רשימת ה-IOC העדכנית.
- חפשו בכל המאגרים קובצי תצורה של סביבת פיתוח שהשתנו — משימות VS Code שרצות בפתיחת תיקייה, וווי הרצה מסוג SessionStart בהגדרות Claude Code. אלה לא ייתפסו בסריקת תלויות.
- אם נמצאה גרסה נגועה, החליפו פרטי גישה מתוך מערכת נקייה בלבד — אסימוני npm ו-GitHub, פרטי גישה לענן, מפתחות SSH, אסימוני Vault ו-Kubernetes. Snyk מדגישה את הסדר: החלפת פרטי הגישה לפני התקנה מחדש.
- בדקו אם נוצרו מאגרי GitHub ציבוריים חדשים תחת חשבונות הארגון עם תיאורי ברירת מחדל חריגים.
- הפעילו חסימת סקריפטי התקנה ב-CI כברירת מחדל, באכיפה נוקשה. זו הפעולה היחידה ברשימה שמונעת גם את הגל הבא.
- בדקו אילו אסימוני npm בארגון מוגדרים לעקיפת אימות דו-שלבי ובטלו אותם.
מה זה אומר בפועל
לספק ישראלי שמוסר מוצר עם שרשרת בנייה מבוססת Node.js ללקוח ביטחוני או תעשייתי, שלוש מסקנות:
ראשית, הצהרות על עמידות בשרשרת אספקה שנשענות על SBOM ועל חתימות provenance צריכות ניסוח מדויק יותר — שתי הבקרות עברו כאן את המבחן הפורמלי ולא מנעו את האירוע. אם בטופס ההערכה של הלקוח כתוב "אנו מאמתים provenance", הוסיפו מה זה כן מוכיח ומה לא.
שנית, הבקרה בעלת יחס העלות-תועלת הטוב ביותר כאן אינה כלי אלא הגדרה: חסימת סקריפטי התקנה בסביבות הבנייה ובקרת יציאה מרשת רצי הבנייה, שתיהן ניתנות ליישום בימים ולא ברבעונים.
שלישית, סביבות הפיתוח והסוכנים עצמם הפכו למשטח תקיפה. קובצי תצורה מקומיים במאגר שמריצים פקודות בפתיחה נמצאים מחוץ לרוב תוכניות הבקרה — נקודה שכדאי להוסיף לנהלי הקליטה של קוד חיצוני, לרבות קוד מקבלני משנה.
מה עדיין לא ידוע
וקטור הגישה הראשוני לא אומת. Chainguard כתבה ב-4 באוגוסט 2026 ש"וקטור הגישה הראשוני עדיין לא ידוע, ולא המתחזק, לא npm ולא GitHub פרסמו הצהרה פומבית". Microsoft ניסחה זאת כ"ראיות מצביעות על אישורי מתחזק גנובים כווקטור לחדירה הראשונית" — ניסוח הסתברותי, לא קביעה. StepSecurity מסיקה מהיעדר חתימה על הקומיטים שמדובר בדחיפה דרך ה-API עם אסימון גנוב או הפעלה חטופה, אך אינה קובעת אם המקור היה דיוג. עד כה לא אותרה הצהרת סיכום פומבית מטעם המתחזק.
לא נמצאה הודעת שינויים של GitHub או npm מאוגוסט 2026 המתארת שינוי מבני שננקט בתגובה לאירוע. השינויים שאני מצטט — ביטול האסימונים הישנים, חסימת הסקריפטים בגרסה 12 וסריקת נוזקות בזמן פרסום מ-28 ביולי 2026 — כולם קדמו לו. האם תיגזר ממנו מדיניות נוספת טרם פורסם.
מספר הגרסאות הסופי לא נסגר, ולא ראיתי ספירה מאומתת ממקור ראשוני של המרשם שמכריעה בין 1,300, 1,381 ו-2,212.
ולבסוף, לא ניתן לקבוע כרגע כמה מפרטי הגישה שנגנבו נוצלו בפועל לתנועה רוחבית מעבר לפרסום חבילות. Unit 42 מדווחת על 453 מאגרים ציבוריים עם סימני הדלפה, אך המרחק בין "הודלף" לבין "נוצל" לא כומת באף אחד מהדיווחים שבדקתי.
מקורות
- Elastic Security Labs
- Chainguard
- Cyber Security Agency of Singapore
- StepSecurity
- Unit 42, Palo Alto Networks
- Microsoft Security Blog
- Datadog Security Labs
- Socket
- Snyk
- Wiz
- Aikido Security
- The Register
- GitHub Changelog
- Socket
- GitHub Changelog
- GitHub Changelog
- GitHub Changelog (index)
- CISA
- Microsoft Security Blog
- CycloneDX 1.6 specification (וכן SPDX 2.3, שדה PackageVersion)