ארגז חול ואבטחה
למה בידוד חשוב כאן
קטע בשם “למה בידוד חשוב כאן”סוכן קורא קבצים, מריץ פקודות מעטפת וקורא ל-API-ים חיצוניים בשמכם. התקלה שמעסיקה אתכם היא לעתים רחוקות זדון — היא סוכן שמפענח שגוי נתיב ומשכתב את הצ׳קאאוט העובד שלכם, או כזה שדוחף ענף שעוד לא סיימתם לסקור. לכן השאלה שהמוצר חייב לענות עליה אינה “האם הסוכן מהימן” אלא “מהו היקף הנזק כשהוא טועה”.
Control Center עונה על כך בשכבות, והשכבות עצמאיות במכוון. אם שכבה אחת חסרה, האחרות מחזיקות בכל זאת. זה חשוב, משום שהשכבה החיצונית ביותר — ארגז החול של מערכת ההפעלה — היא היחידה שהיא מותנית: היא תלויה בכך שהמארח מציע בקאנד, וב-Windows אף מארח לא עושה זאת.
מה באמת מגביל סוכן
קטע בשם “מה באמת מגביל סוכן”חמישה דברים מגבילים הרצת סוכן בכל מארח, עם ארגז חול או בלעדיו. אף אחד מהם אינו גבול של הקרנל; כולם אמיתיים. במקום שבו המארח מציע בקאנד, ארגז החול של מערכת ההפעלה יושב מעליהם, והסעיף “מה ארגז החול מוסיף והיכן הוא עוצר” שלמטה מכסה מה זה משנה.
עץ העבודה הפרטי שלו, בהעתקה בעת כתיבה. כל שיחה מקצה צ׳קאאוט משלה של כל
מאגר מקושר, נשכפל בהעתקה בעת כתיבה דרך ספריית ה-rift המצורפת ולא מועתק
בייט אחר בייט, כך שהבידוד זול מספיק כדי להיות ברירת המחדל. המאגר הרשום
שהוספתם לסביבת העבודה אינו הספרייה שהסוכן עובד בה — שתי שיחות שנוגעות
באותו מאגר לא יכולות לראות את השינויים זו של זו, ואף אחת מהן אינה עורכת את
הצ׳קאאוט שלכם.
כדאי לדייק בגרעיניות: עץ העבודה הוא לכל שיחה, לא לכל סוכן. שני סוכנים
באותה שיחה מקבלים ספריות עבודה נפרדות בשכבת-על ש_חולקות_ את ה-repos/ של
אותה שיחה — וזו בדיוק הכוונה, שכן הם משתפים פעולה על שינוי אחד — בעוד
שספריות הסוכן הפרטיות שלהם נשארות נפרדות. העתקה בעת כתיבה היא הבקאנד היחיד
בכל מקום שבו rift נשלח: מערכת קבצים שאינה תומכת ב-reflink, או ספריית
נתונים בכרך שונה מזה של המאגר, מכשילה את ההקצאה במקום ליפול חזרה. Windows
היא היוצא מן הכלל — אין שם בקאנד של העתקה בעת כתיבה, ולכן git worktree
הוא הבקאנד, ולא נסיגה שקטה.
ריתוק נתיבים בכלי הקבצים של מנגנון ההרצה המובנה. הכלים read, write,
edit, apply_patch, search, find ו-search_files של מנגנון ההרצה
מפענחים כל נתיב ביחס לספריית העבודה של ההרצה בתוספת שורשים משותפים —
ספריית ה-repos/ של השיחה, שבה יושבים עצי העבודה, וספריית הקבצים המצורפים
של המרחב כשהיא קיימת — ומסרבים לכל דבר שנופל מחוצה להם. נתיבים מוחלטים
מתקבלים רק אם כבר היו בפנים. גם קישור סימבולי בתוך עץ העבודה שמצביע החוצה
ממנו מפוענח ונדחה. זו הסיבה שסוכן אינו יכול לכתוב ב-write אל ~/.ssh
אפילו בלי ארגז חול בתמונה.
משטח הכלים של המצב. המצב של השיחה
קובע אילו כלים ממומשים להרצה בכלל. במצבי הקריאה בלבד (plan, review,
orchestrate) כלי השינוי פשוט אינם נמצאים במרשם, ומדיניות פקודות המעטפת של
אותם מצבים דוחה כל פקודה משנת-מצב באופן גורף — git commit, git push,
npm install, docker והשאר — במקום לבקש אישור עבורה. כלי שאינו נוכח אינו
יכול להיקרא, וזו הבטחה חזקה יותר מכלי שנוכח ומגודר.
מעקות הבטיחות המאוחדות של הפעולות. כל כלי משנה-מצב מצהיר על מחלקות
ההשפעה שהוא יכול להפיק, ומנוע המדיניות מכריע לכל אחת מהן — לאשר, לשאול או
לדחות — לפני שהקריאה רצה. prompt בלי מאשר מחובר מוכרע כ_דחייה_ — שאלה
שאיש אינו יכול לענות עליה לעולם אינה “כן”. ראו
מעקות בטיחות עבור מודל ההכרעה.
פרטי גישה מתווכים וסביבה מחוטאת. פרטי הגישה מונפקים בכל הפעלה ומבוטלים
כשההרצה מסתיימת; אסימון ה-GitHub שבידי ההרצה יכול לקרוא אבל לא לדחוף — ראו
“דחיפות עוברות דרך Control Center” בהמשך. ACP, bash של מנגנון ההרצה
ו-Claude Code תחת העטיפה המקורית מקבלים סביבה שמנוטרלים ממנה וקטורי ההזרקה
של המקשר הדינמי והמפרש (LD_PRELOAD, DYLD_INSERT_LIBRARIES, NODE_OPTIONS,
GIT_SSH_COMMAND וכדומה) לפני שהתהליך מתחיל. Claude Code דרך
NoSandboxAdapter יורש את סביבת המארח.
היכן הגבולות האלה נחלשים
קטע בשם “היכן הגבולות האלה נחלשים”כלי הקבצים של מנגנון ההרצה רצים בתוך תהליך השרת, ולא בתהליך בן, כך שאף
פרופיל של ארגז חול לא היה יכול להגביל אותם גם אילו צורף — רק bash עובר
דרך מריץ הפקודות העטוף בארגז החול. הריתוק שלהם הוא בדיקת הנתיב שתוארה לעיל,
ולכן הבדיקה הזו נושאת בנטל ולא מהווה קו הגנה שני.
כלי ה-bash הוא המקום הנוסף שבו כדאי לדייק. הפקודות שלו מוערכות מול מדיניות
הפקודות של המצב ואז נולדות עם סביבה מחוטאת ועץ העבודה כספריית העבודה שלהן.
במקום שבו קיים בקאנד הלידה הזו עטופה, כך שארגז החול הוא מה שמונע מפקודת
מעטפת לכתוב מחוץ לעץ העבודה; במקום שבו אין — Windows, או Linux בלי bwrap
ו-socat — מדיניות הפקודות היא הדבר היחיד שבין הפקודה לשאר הדיסק. במצב
chat המדיניות דוחה באופן גורף רשימה קבועה (הסלמת הרשאות, השמדת מערכת
ודיסק, בריחה ממכולה וממרחב שמות) ומבקשת אישור על שינויי מצב מרוחקים
(git push, gh pr create, פרסום והתקנה של חבילות). כל דבר שאינו באף אחת
מהרשימות רץ. צינורות, שרשראות ותת-מעטפות מנותחים, וכל תת-פקודה מוערכת
בנפרד, כשההכרעה המגבילה ביותר מנצחת.
Claude Code, כשהוא משמש כמתאם, הוא המקרה שבו ארגז החול נושא את המשקל הרב
ביותר. Control Center מפעיל אותו עם --dangerously-skip-permissions, משום
ש-claude -p לא אינטראקטיבי היה אחרת נתקע לנצח בבקשת האישור של עצמו.
קריאות הקריאה, הכתיבה והעריכה שלו מתרחשות בתוך התהליך של עצמו,
ו-Control Center לעולם אינו רואה אותן. קריאות ה-Bash שלו מגיעות לפני
הביצוע ל-hook בשרת, שמסווג את שורת הפקודה ושואל את הכלל המתאים; כלי
ה-mcp__* ש-Control Center עצמו מגיש עוברים בשער כרגיל. במקום שבו קיים
בקאנד, הקריאות הבלתי-נראות האלה עדיין מתרחשות בתוך עטיפת ארגז החול, כך
שמערכת ההפעלה היא הגבול סביבן. במקום שבו אין — שום דבר אינו. כל מתאם מצהיר
על כך במטריצת האכיפה שלו — ראו מטריצת היושר של
המתאמים.
דחיפות עוברות דרך Control Center
קטע בשם “דחיפות עוברות דרך Control Center”אין דגלי הרשאה לכל סוכן. האם סוכן רשאי ליצור קומיט, לדחוף, לפתוח בקשת משיכה, לכתוב למערכת מעקב או לגשת לרשת — את זה מכריעים מעקות הבטיחות: אפשר, שאל קודם או חסום, ואותם כללים חלים בלי קשר למתאם שמריץ את הסוכן.
דחיפה היא הפעולה שחייבת להחזיק גם מול סוכן שמנסה לעקוף את הכלל, ולכן היא
נאכפת לפי מה שהסוכן מחזיק, לא לפי מה שהוא מריץ. כש-GitHub App מוגדר, הרצה
בעץ עבודה של GitHub מקבלת אסימון התקנה מוגבל למאגר אחד, שיכול לקרוא תוכן
ולעבוד עם בקשות משיכה אבל לא לדחוף. תצורת ה-git של ההרצה משכתבת כל כתובת
דחיפה של GitHub (https://github.com/, git@github.com:,
ssh://git@github.com/) אל שער הרצת הסוכן — נקודת קצה של loopback
ב-cc_server. השער קורא אילו refs הדחיפה מעדכנת, שואל את הכלל דחיפה למאגר
מרוחק — כך שגם כללים מוגבלי-ענף כמו “חסום דחיפות ל-main” חלים — ורק אז
מעביר את הדחיפה ל-GitHub עם אסימון כתיבה שהוא מנפיק לשם כך ולעולם אינו מוסר
לסוכן. דחיפה שנדחתה מופיעה בפלט של git עצמו:
! [remote rejected] main -> main (Control Center policy: …)השער מעביר דחיפות רק למאגר של עץ העבודה עצמו או למאגר GitHub שמקושר לסביבת העבודה. משיכות (fetch) מגיעות ל-GitHub ישירות עם אסימון הקריאה בלבד.
שאר פקודות המעטפת פוגשות שער רך יותר. כלי ה-bash של מנגנון ההרצה וכלי
ה-Bash של Claude Code דרך ה-hook מסווגים כל שורת פקודה ושואלים את הכלל
שהיא שייכת לו: git commit, merge, rebase, cherry-pick, revert
ו-am שייכות ליצירת קומיט; gh pr create לפתיחת בקשת משיכה;
gh pr merge, review, comment ו-close לפרסום סקירה או מיזוג;
gh issue create, edit, comment ו-close לכתיבה למערכת מעקב
חיצונית; התקנות חבילות להתקנת חבילה; ו-curl ו-wget לגישה לרשת.
זה תופס את הצורות הנפוצות של פעולה, וסוכן שנחוש להסתיר אותה (eval, קובץ
סקריפט, קריאת API ישירה) יכול לעשות זאת. הדחיפה אינה נשענת על זה.
שום מפתח API של כרטוס אינו מוכנס לארגז החול. סוכנים כותבים כרטיסים דרך כלי ה-MCP של Control Center, ששואלים את הכלל כתיבה למערכת מעקב חיצונית.
הכלל גישה לרשת נקרא פעם אחת, בתחילת ההרצה. הרשת של ארגז החול יכולה להיות
רק דלוקה או כבויה, ולכן חסימה מכבה אותה, ואילו אפשר ושאל קודם משאירים אותה
דלוקה; הכלים web_fetch ו-web_search של מנגנון ההרצה עדיין שואלים בכל
קריאה. פרטי הגישה מבוטלים כשההרצה מתפרקת, יחד עם כל אסימון כתיבה שהשער
הנפיק, כך שאחיזה אינה שורדת את ההרצה.
מה ארגז החול מוסיף והיכן הוא עוצר
קטע בשם “מה ארגז החול מוסיף והיכן הוא עוצר”ל-enum SandboxBackend יש שלושה ערכים — native (Seatbelt ב-macOS,
bubblewrap ב-Linux וב-WSL2), none ו-microvm. עטיפת פקודות הסוכן משתמשת
רק בשני הראשונים: microvm הוא בקאנד ה-VM המסוגר עבור מסופים אינטראקטיביים
ותחנות, ולא שדרוג שקט של עטיפת bash. הבנת הצורה המקורית מסבירה מה אתם
מרוויחים במקום שהוא מחובר, ומה הוא מעולם לא נועד לתת לכם.
cc_server בודק את המארח פעם אחת באתחול, ובמקום שבקאנד עונה הוא מזין את
שני התפרים שיש למסלול השיגור, משום שהתעבורות אינן חולקות תפר אחד. הראשון
(SandboxPort) עוטף את ה-CLI של Claude Code. השני (SandboxManager) עוטף
מתאמי ACP ואת כלי ה-bash של מנגנון ההרצה המובנה. הזנת אחד בלבד הייתה
מותירה את האחרים נולדים בלי עטיפה, וזה מה שהיה קורה קודם. במארח בלי בקאנד,
או תחת --sandbox off, כולם נולדים בלי עטיפה, והשרת אומר באיזה מן המקרים
אתם נמצאים בשורת האתחול שלו. ACP ו-bash של מנגנון ההרצה עדיין מחטאים את
הסביבה; Claude Code דרך NoSandboxAdapter יורש את סביבת המארח.
משטח אחד בוחר במכוון שלא להשתתף: המסוף המתארח בשרת מקבל ארגומנט בקאנד לכל
מושב, ו-cc_server בונה אותו כברירת מחדל עם מעטפת המארח, כך שמסוף שתפתחו
מהאפליקציה רץ בלי ארגז חול אלא אם לקוח מציין native במפורש. מדובר במעטפת
אמיתית על מארח השרת, ולא בהרצת סוכן.
ב-Linux, bubblewrap בונה מרחב שמות של עיגון, כך שהסוכן אכן רואה רק את מה
שעוגן לתוכו. ב-macOS, sandbox-exec מחיל פרופיל Seatbelt שהוא מתירני
כברירת מחדל — פרופיל שדוחה הכול כברירת מחדל הופך מעטפת אינטראקטיבית
לבלתי שמישה, משום שמספר קריאות ה-dyld, ה-XPC וה-Mach שיש למנות אינו מעשי.
לכן פרופיל ה-macOS מתחיל מ-(allow default) ומגלף ממנו דחיות: קריאות של
נתיבי סודות, מדיניות כתיבה שמאופסת לדחייה עם היתרים מפורשים מעליה, חסימת
unlink בכל נתיב נדחה ובאבותיו כך ששינוי שם אינו יכול לעקוף דחיית כתיבה,
דחיות exec לקובצי הרצה מסוכנים תמיד ולכל דבר שהועתק לתוך ספרייה ניתנת
לכתיבה, ורשת שמוגבלת לפורטי ה-proxy של ה-loopback בתוספת DNS.
המשמעות המעשית: ב-Linux השקפת הסוכן על מערכת הקבצים מצטמצמת; ב-macOS הסוכן עדיין יכול לקרוא את רוב המארח, והצ׳קאאוטים הרשומים שלכם מוגנים בדחיות כתיבה ושינוי-שם מפורשות ולא בהיעדר נראות. שניהם בידוד ברמת מרחב שמות, ולא גבול אבטחה של הקרנל — הבקאנדים מצהירים על כך בהערות היכולת שלהם.
קבוצת עיגוני ה-bind היא המקום שבו נמתח הגבול בין סוכנים. שיגור ה-Overlay
(Claude Code ו-ACP) מעגן עד ארבעה נתיבים, הנפתרים לכל הרצה: ספריית העבודה
בשכבת-העל של הסוכן לקריאה-כתיבה, ספריית התצורה של הסוכן לקריאה בלבד,
ספריית ה-repos/ המשותפת של השיחה לקריאה-כתיבה כשהיא קיימת, וספריית
הקבצים המצורפים של המרחב לקריאה בלבד כשהיא קיימת. הספרייה של סוכן אחים
לעולם אינה מעוגנת. עטיפת ה-bash של מנגנון ההרצה צרה יותר: היא מעגנת רק
את ספריית העבודה של ההרצה. זו אותה צורה שבדיקת הנתיבים בתהליך של מנגנון
ההרצה אוכפת בתוכנה, כך ששניהם מסכימים — אבל רק בדיקת הנתיבים מכסה את כלי
הקבצים של מנגנון ההרצה עצמו, שאינם מגיעים כלל למרחב שמות של עיגון.
לצ׳קאאוטים הרשומים שלכם נוספים מעל לכך עיגוני דחיית כתיבה, בכל מצב ובכל
שלושת הנתיבים העטופים (Claude Code, ACP, bash של מנגנון ההרצה), וכל כלל
נפלט גם בצורתו המילולית וגם בצורתו המפוענחת-סימבולית. הצורה השנייה אינה
קישוט: הקרנל מתאים כלל דחייה לנתיב המפוענח, ו-macOS הופך את הפענוח למקרה
השכיח ולא לחריג — /tmp הוא באמת /private/tmp, ו-/var/folders/… הוא
באמת /private/var/folders/… — כך שצ׳קאאוט שאליו מגיעים דרך מי מהם היה
ניתן לכתיבה בעוד הפרופיל נראה כאוסר אותה.
הרשת, תחת ארגז חול, היא רשימת היתר של דומיינים לכל מושב, הנאכפת בידי
proxy-ים של loopback בתוך התהליך. יציאה היא דחייה כברירת מחדל: כשהרשת
כבויה, ה-proxy-ים עדיין עולים אבל רשימת ההיתר שלהם ריקה, כך שכל חיבור
יוצא נדחה. כשהיא דלוקה, הפותר בונה את רשימת ההיתר מקו בסיס נבחר — ספקי API
של מודלים, אחסון git, מרשמי חבילות, קטלוג המודלים — בתוספת דומייני GitHub,
ומתאים את מארח היעד של כל חיבור אליה. תווים כלליים עובדים (*.example.com
מתאים לתת-דומיינים, לא לשורש). רשימה נפרדת שנדחית תמיד גוברת על רשימת ההיתר
ומכסה נקודות קצה של מטא-נתוני ענן ומשקעי טלמטריה. מה ש_אינו_ ניתן להגדרה
הוא הרשימה עצמה: המפרט נושא שדה egressAllowlist לדומיינים נוספים, אבל שום
דבר במסלול השיגור אינו מאכלס אותו, כך שבפועל כל הרצה מקבלת את קו הבסיס
בתוספת GitHub ותו לא.
דחיות, ב-macOS, ניתנות לצפייה: מוניטור מציץ ביומן המערכת לאיתור דחיות
Sandbox, מסנן רעש מוכר, מחסל סערות ניסיון-חוזר ומציף כל אחת מהן כאירוע
SandboxViolation שמציין מה ניסו לעשות ומה נחסם. ב-Linux
מסלול העטיפה מנתח את stderr לאיתור EPERM, Operation not permitted
ו-Permission denied ופולט את אותו סוג אירוע — אין הצצה ביומן המערכת. אלה
מגיעים בזרם האירועים של ההרצה עצמה, כך שקריאת מערכת נדחית מופיעה בתמלול
ולא רק ביומן. הטלמטריה קיימת רק כשפרופיל ארגז חול מקורי באמת עוטף את
התהליך — במארח בלי בקאנד אין מה לצפות. היא גם אינה קשורה למעקות הבטיחות:
הפרה נובעת מקריאת מערכת נדחית, ולעולם לא מחיפוש כלל.
אישורים מגיעים ממעקות הבטיחות, לא מארגז החול
קטע בשם “אישורים מגיעים ממעקות הבטיחות, לא מארגז החול”לארגז החול אין מסלול אישור. הוא עולה, מריץ, פולט אירועים ומתפרק; אין בו מקום שאדם יכול לענות בו על שאלה. כשאתם רואים אישור במרחב — אשרו את הדחיפה הזו, אשרו את המחיקה הזו — הוא הועלה בידי מנוע מעקות הבטיחות (או מדיניות הפקודות של מנגנון ההרצה) לפני שהפעולה הגיעה לריצה בכלל.
הסדר הזה מכוון. אישור שקרה אחרי קריאת המערכת היה רשומת ביקורת, לא שער. זו גם הסיבה שכלל הכשל-הסגור חי במעקות הבטיחות: בלי מאשר מחובר, ההכרעה מתקבלת לפני שמשהו רץ והיא דחייה.
אבחון
קטע בשם “אבחון”הרצת אבחון סוכן הוא המקום היחיד שמפרט מה ניתן לבדוק ביד.
מושגים קשורים
קטע בשם “מושגים קשורים”- תחנות ומתחמים מבודדים: הצעד שמעל ארגז החול — כשהעבודה צריכה מכונה חד-פעמית שלמה עם גבול קרנל, ולא תהליך עטוף
- מעקות בטיחות: שכבת המדיניות שמעל רצפת מערכת ההפעלה ומהיכן מגיעים האישורים באמת
- מחזור חיי שליחת סוכן: היכן הבידוד משתלב בזרימת השיגור
- מצבים: איך מצב מצמצם את משטח הכלים ואת מדיניות הפקודות
- עזר למנועי ארגז חול: הבקאנדים והתצורה שלהם
מדריכים קשורים
קטע בשם “מדריכים קשורים”- הגדרת מדיניות ארגז חול: כללי פעולה, אכיפת דחיפות ותנוחת מערכת הקבצים
- הרצת אבחון סוכן: מה מכסות בדיקות האבחון