
קריסת CrowdStrike התמצתה בספירת שדות: 21 שדות במקום 20 שהליבה ציפתה להם. אף שכבה עצמאית לא בדקה.
ב-19 ביולי 2024, עדכון יחיד מספק תוכנה הפיל מיליוני מחשבי Windows בפחות מ-90 דקות, והסיבה לכך הייתה מספר בודד. קובץ ערוץ "Rapid Response Content" של CrowdStrike הצהיר על 21 שדות במקום שבו מפרש הליבה (kernel interpreter) שנפרס ציפה ל-20 שדות בלבד. השדה הנוסף יצר קריאה מחוץ לגבולות (out-of-bounds read), מסך כחול מיידי, ומכיוון שהקריסה התרחשה בשלב כה מוקדם של תהליך האתחול, הסוכן שקרס לא יכול היה לעלות שוב כדי לקבל פקודת שחזור (rollback). ההתאוששות חייבה לגשת פיזית לכל מכונה ולתקן אותה ידנית במצב בטוח (Safe Mode).
קראתי את ניתוח סיבת השורש שפרסמה CrowdStrike עצמה באותו חודש אוגוסט יותר מפעם אחת לפני שהתחדד בי הדבר שהטריד אותי באמת. זו לא הייתה פריצה. זה לא היה מודל בינה מלאכותית לקוי. זו הייתה עובדה אריתמטית ניתנת להכרעה, 21 מול 20, שישבה במטען נתונים (payload) שאף שכבה עצמאית מעולם לא בדקה לפני שהגיע לסביבת הייצור. המאמת של הספק אישר אותו. הארגונים שהושבתו לא החזיקו באותו מאמת. הם נשאו בתוצאות לבדם.
הקדשתי את התקופה האחרונה לבניית הדגמה סביב הפער הזה: קונסולה שכיניתי בשם Kestrel, הניצבת בין ספק התוכנה לבין צי הייצור ומכריעה, בקוד, מה הספק מורשה להפיץ. תוכלו לראות כיצד היא פועלת בכתובת veriprajna.com/demos/software-update-integrity. מה שהפתיע אותי במהלך הבנייה היה המקום שבו התברר שהפתרון נמצא. ניגשתי לפרויקט מתוך ביטחון שאזדקק למודל חכם יותר, אך כמה שורות פייתון פשוטות לכדו את הקריסה ראשונות.
שחזרתי את הקריסה ואז נתתי לקוד להכריע
שחזרתי את חתימת הכשל של 19 ביולי כמקרה מבחן (fixture) וכיוונתי את המערכת שלי אליה, כמעט מתוך ציפייה להתאכזב מהשחזור של עצמי. החבילה היא C-00000291, קובץ ערוץ Rapid Response Content מספק בדיוני שכיניתי SentinelEdge, שנדחף לצי סינתטי של 8,500 נקודות קצה בשם Acme Financial. אף אחת מאלו אינה חברה אמיתית. אך חתימת הכשל אמיתית לחלוטין: סכמה מוצהרת של 20 שדות שתפחה ל-21, ונדחפה ל-100% מכלל הצי בגל יחיד, ללא תוכנית פריסה מדורגת (canary).
השער מופעל על ארבע בדיקות בו-זמנית, וכל אחת מהן היא אריתמטיקה טהורה או בדיקה פשוטה בטבלה, לעולם לא שיקול דעת סובייקטיבי. השוואת הסכמה מזהה 21 שדות במקום שבו המפרש מצפה ל-20 ומסמנת את הקריאה מחוץ לגבולות. סביבת ארגז חול (sandbox) מדומה, שהיא מודל תוצאות דטרמיניסטי לכל פרופיל ולא חוות מכונות וירטואליות אמיתיות של Windows, מכניסה 5 מתוך 6 פרופילי הצי ללולאת אתחול לאורך מחזורי אתחול מחדש. היא מסיקה זאת מאות תאימות מנהלי התקנים שאינו תלוי בבדיקת הסכמה, כך ששני הממצאים מאששים זה את זה ולא רק מהדהדים כפילות. גלאי הסוכן המת מסמן את לולאת השחזור כ-true, מכיוון שהסוכן הקורס הוא בעצמו הישות שאמורה לקבל את פקודת השחזור, והוא מושבת עוד לפני סיום תהליך האתחול. רדיוס הפגיעה עומד על 100% מול מדיניות קנרית של 5%. פסק דין: BLOCK. על המסך נכתב: נחסם לפני שנקודת קצה כלשהי בייצור אותחלה מחדש.

זמן ההשבתה המוערך שנמנע באותו עדכון בודד מצביע על 5,000,000 $, ואני מבקש לדייק לגבי מהותו של נתון זה. זהו המודל הפנימי של ההדגמה: החלק המושפע מוכפל בנתון עלות של 5 מיליון דולר לשעה מוכפל ברף התאוששות מינימלי של שעה אחת, כאשר הנוסחה מוצגת בבירור על גבי המסך. אין מדובר בכסף שלקוח חסך בפועל. ההתאוששות האמיתית ב-19 ביולי נמשכה ימים ולא שעה בודדת, ולכן רף המינימום נקבע במכוון באופן שמרני.
המקרה הירוק הפחיד אותי יותר מהמקרה האדום
הייתי מתוח יותר לגבי המקרה הירוק מאשר לגבי האדום, מכיוון ששכבת ממשל החוסמת את העדכון המסוכן אך בו-זמנית חונקת את העדכון הבטוח אינה אלא השבתה שקבעתם לעצמכם ביומן. אותו ספק בדיוני דוחף את RRC-7741, עדכון שפיר של חתימות זיהוי, עם סכמה מוצהרת של 20 מול 20, ותוכנית קנרית מדורגת של 1.2%. צוות הסוכנים פועל, הסכמה תואמת, 5 מתוך 6 פרופילים עוברים בהצלחה את מחזורי האתחול מחדש, לולאת הסוכן המת היא false, ורדיוס הפגיעה נשאר בתוך גבולות המדיניות. פסק דין: APPROVE ROLLOUT, שוחרר לטבעת קנרית של 102 נקודות קצה. ירוק, מהיר, ונטול דרמות.

לאורך ששת העדכונים השפירים בערכה, השער לא ייצר אף חסימת שווא (zero false blocks). אני אומר זאת תוך ציון המכנה במפורש, כי שש זה שש, ולא אתיר לעגל זאת כלפי מעלה לכדי הבטחה גורפת לצי שלכם. הערך של מקרה ה-ALLOW צר יותר וחשוב בהרבה מסתם אחוזים. שער זוכה לאמינות רק אם הוא בלתי נראה בתעבורה רגילה ובלתי מתפשר באירוע היחיד שעלול למוטט את התשתית שלכם.
מדוע שללתי את סמכות ההכרעה מהמודל
התחלתי את הבנייה מתוך הנחה שהחלק המורכב טמון בהסקה, ושמודל חד יותר או מבקר מתוחכם יותר יהיה זה שילכוד את העדכון הפגום. טעיתי באופן שלקח לי זמן להודות בו. ישנו צוות LLM בתוך Kestrel: מאחד (normalizer), מפרש ארגז חול, ושני מבקרים יריבים — האחד טוען שהעדכון בטוח להפצה והשני טוען שהוא יקרוס. הצמד היריב מרוויח את מקומו בצדק, כיוון שהוא מעביר את פסק הדין בדיקת חדירות ובחינה מחמירה משני הכיוונים בטרם הוחלט דבר. אך אף לא אחד מסוכנים אלה קובע את פסק הדין הסופי.
פסק הדין נקבע על ידי שני קובצי פייתון פשוטים, verifier.py ו-gate.py, שפועלים לחלוטין מחוץ למסגרת הסוכנים. הצוות פועל על גבי Pydantic AI עם מודל ברירת מחדל של claude-opus-4-8, והמערכת כולה פועלת גם במצב לא מקוון ללא מפתח API באמצעות מנגנון ייעוץ חלופי דטרמיניסטי. בכל אחד ממצבים אלה השער זהה לחלוטין ומחזיר את אותה ההחלטה, כיוון שההחלטה היא אריתמטיקה טהורה, ולא היסק הסתברותי. סוכנים מייעצים, הקוד מכריע. סוכן מייעץ הנוטה ל"אשר" אינו יכול למחוק ממצא דטרמיניסטי קריטי, ואין מדובר בעניין של טעם אישי.
שכבה שנבנתה כדי לבקר את הספק אינה יכולה לקבל את הבטחות הספק בנוגע לבטיחות. היא אינה יכולה לקבל גם את הבטחות המודל שלה עצמה.
משפט זה הוא הסיבה המדויקת לכך שהארכיטקטורה בנויה כפי שהיא בנויה. אמון במוצר שתפקידו הבלעדי הוא לנהל את מה שספק מפיץ לעולם אינו יכול לעבור דרך רכיב שניתן לשכנעו לומר כן.
מה שהייתי מגיש למבקר
השארתי את חוק החוסן הקיברנטי האירופי (CRA) פתוח על צג שני בזמן שבניתי את רשומת הראיות, כי אותה רשומה היא התוצר הפיזי שאצטרך להגן עליו בפועל. כל החלטה מייצאת קובץ HTML בלתי ניתן לשינוי וקובץ JSON חתום הנושא גיבוב תוכן מסוג SHA-256, את פסק הדין, ההוכחות הדטרמיניסטיות, תוצאות ארגז החול לכל פרופיל, פסקי הדין של הסוכנים המייעצים עם מזהה המודל שלהם, כללי המדיניות שהופעלו, ועקבות הערכה שלב-אחר-שלב שבהם כל שלב נושא את זמן ההשהיה שלו.

עקבות המעקב הם החלק שהערכתי בחסר עד שלחצתי על שלב בודד. אירוע אחד מציג: "נרמול מנשר ספק חתום, הושלם תוך 184 מילי-שניות", והוא נשמר יחד עם פלט ההחלטה לצורכי סקירת ביקורת. כל שלב ניתן לשחזור ולחישוב מחדש. רגולטור אינו נדרש להאמין ללוח הבקרה שלי בעיניים עצומות. הוא יכול להריץ מחדש את האריתמטיקה ולקבל את אותה התוצאה בדיוק.

אני מקפיד מאוד על מה שהחתימה מהווה ומה שאינה מהווה. מדובר בגיבוב SHA-256 מקומי, לא ב-PKI ארגוני כולל. ערוץ עדכוני הספק וכרטיסי ה-ITSM מאחוריו הם רכיבי בדיקה מדומים (stubs), ולא מחברים חיים. הרשומה תוכננה להתיישר עם דרישות דיווח: דיווח התקריות בטווח הזמן הקצר של ה-CRA, חובת הדיווח של ה-SEC תוך ארבעה ימי עסקים על אירוע סייבר מהותי, ושאלות אחריות הספק שהועלו בתביעת Delta נגד CrowdStrike במחוז פולטון בשנת 2025. "תוכננה להתיישר עם". היא אינה מעניקה הסמכה לאיש, אינה מהווה ייעוץ משפטי, וכל מי שמוכר לכם יומן ביקורת בטענה שהוא הופך אתכם לתואמי רגולציה בסך הכל מנסה למכור לכם משהו.
ישנה החלטה נוספת שאני גאה בה, והיא דווקא סירוב. מקרה מבחן XX-0000 הוא מקטע נתונים מוצפן של תוכן קנייני שהשער אינו מסוגל לנתח, ולכן אינו מנחש. הוא מחזיר ABSTAIN (הימנעות) ומפנה זאת לבודק אנושי, כיוון ששער שנותן אור ירוק למה שאינו מסוגל לקרוא גרוע בהרבה מהיעדר שער לחלוטין. שרתי מורשת ישנים שארגז החול אינו מסוגל למדל מסומנים ומוחרגים, לעולם לא מוגדרים כבטוחים כברירת מחדל. אוצר המילים כולל ארבע מילים בלבד: ALLOW, HOLD, BLOCK, ABSTAIN, והאחרונה היא זו שעליה אגן בנחרצות הרבה ביותר.
מה ש-12 מתוך 12 רשאי לסמל
כאן עליי להאט, מכיוון שבדיוק בנקודה זו מייסד מתחיל לעגל מספרים כלפי מעלה. ומאחר שקראתי לחברה Veriprajna, קרי חוכמת אמת, עיגול מספרים כלל אינו בא בחשבון. לאורך ערכה קבועה ומתויגת של שנים-עשר עדכונים, השער מפיק את ההחלטה המדויקת בכל השנים-עשר. שישה מהם שפירים והוא אינו חוסם אף אחד מהם. אחד מהם הוא ה-ABSTAIN הישר. לוח התוצאות מציג: 12/12 החלטות מאומתות, 0/6 חסימות שווא, וזמן השבתה מוערך שנמנע בשווי 13.3M $ לאורך הערכה כולה, שמתוכו 5 מיליון דולר מיוחסים לחסימה הבודדת ברמת CrowdStrike.

וכעת לחלק שאני מסרב לקצר. אלו תוצאות על שנים-עשר פריטים מתויגים בלבד, ולא הבטחה לגבי העדכון הבא שיגיע לצי שלכם. שישה פריטים שפירים הם בסך הכל שישה. אין פירוש הדבר "חוסם 100% מהעדכונים הרעים", זה לעולם לא יהיה כך, ואם תתפסו אותי כותב משפט כזה בעתיד, עליכם לחדול מלקרוא את דבריי. המספר שאני עומד מאחוריו הוא מסוג שונה: אותו קלט, אותה החלטה, בכל הרצה, כיוון שלפסק הדין אין כל טמפרטורת מודל. הריצו את ערכת המבחנים שוב מחר והיא תחזיר תוצאות זהות ברמת הבייט, וזה בדיוק מה שמאפשר לבקר שכבה דטרמיניסטית באופן שלעולם לא יתאפשר בשכבה הסתברותית.
השאלה שנותרה עמי
מה שמלווה אותי מפרויקט הבנייה הזה הוא עד כמה הכשל היה רגיל ובנאלי. עשרים ואחד שדות במקום שבו ציפו לעשרים. מספר שכל מאמת עצמאי יכול היה ללכוד באמצעות אריתמטיקה פשוטה עוד לפני שמכונה בודדת אותחלה מחדש, אילו רק ניצב מאמת עצמאי בין הספק לבין הצי. לא היה שם איש. ועד היום, במרבית המקרים, עדיין אין שם איש.
כל ארגון מפעיל שמונה עד שנים-עשר סוכנים בעלי הרשאות ברמת הליבה מספקים שאינם בשליטתו, וכל אחד מהם יכול לדחוף קובץ ישירות לתוך ring 0. כלי SBOM מנטרים תלויות קוד פתוח. ניהול זהויות מנטר גישה. אך איש אינו קורא את העדכון הקנייני של הספק בכניסה ומוכיח את בטיחותו. Kestrel אינה מערכת EDR ולעולם אינה נוגעת בליבה. היא יושבת מעל אותם סוכנים ומנהלת את מה שהם מורשים להפיץ. זוהי בדיוק השכבה שניסיתי לבנות, והפירוט המלא זמין בכתובת veriprajna.com/demos/software-update-integrity.
ואם אתם מעדיפים לצפות במערכת בפעולה מאשר לקרוא אותי מתאר אותה, הנה המערכת כולה פועלת מקצה לקצה.
אז הנה מה שאני שואל כעת לגבי כל צי מחשבים שאני פוגש: כאשר עדכון הספק הבא יגיע, מה יעמוד בין אותו קובץ לבין סביבת הייצור, והאם הוא מסוגל להוכיח את עבודתו? אם התשובה היא ועדת ייעוץ לשינויים (CAB) שסומכת בעיניים עצומות על הספק, הרי שאותה שגיאה אריתמטית שהפילה מיליוני מחשבים ממשיכה לפעול ללא כל הפרעה. היא לא תודיע על בואה. היא תיראה בדיוק כמו כל עדכון שקדם לה, ממש עד לרגע האתחול מחדש.

