AI Sandboxing — הרצת קוד של Agent בצורה מבודדת

מאת צוות מדיה דיל · 09.08.2026 · AI · 8 דק׳

מה קורה כש-Agent כותב ומריץ קוד בעצמו, ולמה זה חייב לרוץ בסביבה מבודדת. מדריך טכני להקמת Sandbox אמיתי להרצת קוד AI - מ-container רגיל ועד microVM, כולל בדיקות עמידות.

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

למה Agent שמריץ קוד הוא בעיה אחרת מקוד רגיל

קוד שכתב מפתח אנושי עובר code review, נבדק ב-CI, ולרוב פועל בתוך גבולות ברורים שהמפתח הציב לעצמו. קוד שנכתב על ידי LLM שונה בשלושה מובנים קריטיים: הוא נוצר בזמן ריצה (runtime), לרוב ללא בדיקה אנושית מראש, ולעיתים בתגובה לקלט חיצוני (Prompt Injection דרך מסמך, קובץ, או תוצאת חיפוש) שהמודל לא יודע להבחין בינו לבין ההוראה המקורית של המשתמש. משמעות הדבר: כל קוד שה-Agent מריץ צריך להיחשב Untrusted Code באופן עקרוני, בדיוק כמו קוד שמגיע ממשתמש אנונימי באינטרנט - גם אם ברוב המקרים הוא לגיטימי לחלוטין.

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

וקטור התקיפה בפועל: מה יכול להשתבש

כדי לבנות הגנה טובה צריך להבין את משטח התקיפה. כמה תרחישים אמיתיים:

  • Container escape - קוד שמנצל חולשה בקרנל או בהגדרות ה-container runtime כדי לצאת מהבידוד ולהגיע להוסט.
  • Resource exhaustion - לולאה אינסופית, fork bomb, או ניצול זיכרון בלתי מוגבל שמפיל את המכונה כולה, כולל workloads אחרים שרצים עליה.
  • Network exfiltration - קוד שיוצר חיבור יוצא (HTTP, DNS tunneling) ומדליף קבצים, משתני סביבה, או Secrets דרכו.
  • Filesystem persistence - קוד שכותב לקבצים מחוץ לתיקיית העבודה שהוקצתה, או משנה קבצי מערכת.
  • Supply chain בתוך ה-Sandbox עצמו - Agent שמתקין חבילה (pip install, npm install) עם קוד זדוני שרץ כבר בזמן ההתקנה.

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

רמות בידוד: ממה שהכי חלש ועד הכי חזק

לא כל Sandbox נולד שווה. שווה למפות את הספקטרום:

  • Process isolation בסיסי (subprocess עם timeout) - כמעט ואינו בידוד. אותו kernel, אותה מערכת קבצים, אותה רשת. מתאים רק לקוד שכבר עבר סינון קפדני מאוד.
  • Container רגיל (Docker/Podman) - בידוד namespace ו-cgroups, אבל חולק kernel עם ההוסט. חולשת kernel אחת יכולה לשבור את הבידוד. דורש seccomp profiles, AppArmor/SELinux, ו-drop של capabilities מיותרות כדי להיות שימושי בפועל.
  • gVisor / user-space kernel - מיירט קריאות מערכת ברמת user-space במקום להעביר אותן ישירות ל-kernel של ההוסט, ומצמצם משמעותית את משטח התקיפה מול container רגיל, במחיר תקורת ביצועים.
  • microVM (Firecracker, Kata Containers) - כל הרצה מקבלת קרנל וירטואלי משלה עם boot מהיר (מילישניות עד שניות בודדות). זו הרמה שבה חברות ענן מריצות workloads של לקוחות לא מהימנים זה לצד זה, וזו הרמה המומלצת להרצת קוד שנוצר על ידי Agent בפרודקשן.
  • VM מלאה - הכי בטוח, הכי איטי. מתאים כשמדובר בקוד עם רמת סיכון גבוהה במיוחד או דרישות רגולטוריות מחמירות.

איך בונים Sandbox אמיתי - עקרונות ארכיטקטורה

מעבר לבחירת טכנולוגיית הבידוד, יש כמה עקרונות שחוזרים בכל ארכיטקטורה טובה:

1. Deny by default ברשת

ברירת המחדל צריכה להיות ללא גישה לרשת בכלל. אם ה-Agent צריך גישה לחבילות (pip, npm) או ל-API ספציפי, פותחים allowlist מדויק של דומיינים - לא "אינטרנט פתוח". זה מונע גם exfiltration וגם הורדת payloads זדוניים נוספים בזמן ריצה.

2. Filesystem אפמרי וממופה

כל הרצה מקבלת filesystem חדש שנמחק בסיומה. תיקיית העבודה היחידה שנגישה היא זו שהוקצתה במפורש למשימה, וגם היא read-only במקומות שלא צריך בהם כתיבה.

3. מגבלות משאבים קשיחות

CPU, זיכרון, מספר processes, ו-timeout מוגדרים מראש ונאכפים ברמת ה-runtime, לא ברמת הקוד עצמו. Agent שמריץ לולאה אינסופית צריך להיעצר אוטומטית אחרי X שניות, לא לחכות שמישהו ישים לב.

4. אין Secrets בתוך ה-Sandbox

אם הקוד שרץ בפנים לא צריך מפתח API כדי לבצע את המשימה, הוא לא מקבל אותו. פרטים נוספים בנושא זה מופיעים בניהול Secrets ל-AI.

{
  "sandbox_profile": "code-exec-default",
  "runtime": "microvm",
  "network": { "egress": "deny", "allowlist": ["pypi.org", "registry.npmjs.org"] },
  "filesystem": { "workdir": "/workspace", "mode": "ephemeral", "readonly_root": true },
  "limits": { "cpu": "1", "memory_mb": 512, "timeout_sec": 30, "max_processes": 32 },
  "secrets_mounted": false
}

ניהול מחזור חיים: pool של Sandboxes חמים

אחת השאלות התפעוליות המרכזיות היא איך שומרים על זמני תגובה סבירים כשכל הרצת קוד דורשת sandbox נקי. הפתרון הנפוץ הוא pool - קבוצת sandboxes שכבר עלו ומוכנים מראש, שממתינים "חמים" ומחכים למשימה. כשמגיעה בקשה, המערכת שולפת sandbox מוכן מה-pool במקום להקים אחד חדש מאפס, ומחזירה אותו למחזור (אחרי ניקוי מלא) או משמידה אותו לגמרי בהתאם למדיניות. הגודל הנכון ל-pool תלוי בעומס הצפוי ובעלות ההחזקה - pool גדול מדי מבזבז משאבים על sandboxes שלא בשימוש, pool קטן מדי גורם לתורים וזמני המתנה בעומס שיא. מערכות בקנה מידה גדול מיישמות autoscaling דינמי ל-pool עצמו, בדומה לאיך שמנהלים Scaling אופקי ל-Agents באופן כללי.

Trade-offs: ביצועים מול בידוד

הבידוד החזק ביותר תמיד עולה במחיר: microVM איטי יותר מ-container רגיל בזמן עלייה (cold start), ומצריך תשתית ייעודית לניהול מחזור החיים שלו (pool של VMs חמים, למשל). ב-Agent שמריץ אלפי הרצות קוד קטנות ביום, זה יכול להפוך לצוואר בקבוק אמיתי. הפתרון הנפוץ הוא שכבתיות - קוד "בטוח" יחסית (בדיקות פשוטות, פורמט) רץ בבידוד קל, וקוד עם משטח סיכון גבוה יותר (גישה לרשת, התקנת חבילות, הרצה על נתוני משתמש אמיתיים) עובר ל-microVM. זו החלטה ארכיטקטונית שצריך לקבל במודע, לא כברירת מחדל טכנית.

שאלה נוספת היא מי מריץ את התשתית. פתרונות SaaS ייעודיים (sandbox-as-a-service) חוסכים בניית תשתית אך מוסיפים תלות בספק חיצוני ולעיתים latency; תשתית עצמאית על תשתית פרודקשן מבוקרת נותנת שליטה מלאה אך דורשת מומחיות DevOps ואבטחה מתמשכת.

דוגמה מהשטח: Agent שמריץ בדיקות אוטומטיות

תרחיש נפוץ הוא Coding Agent אוטונומי שמקבל Pull Request, כותב תיקון, ומריץ את סוויטת הבדיקות כדי לוודא שהתיקון לא שבר כלום. כאן הבידוד לא רק מגן מפני קוד זדוני - הוא גם מגן מפני "תאונות" של הבדיקות עצמן, כמו טסט ששוכח לנקות משאבים או תלוי בסביבה משותפת. כל הרצת בדיקות מקבלת sandbox נקי, וה-Agent מקבל בחזרה רק את הפלט הרלוונטי (exit code, לוגים) - לא גישה לרשת הפנימית של הארגון.

הרחבה טבעית של אותה ארכיטקטורה היא Agent שמריץ תהליכי build מלאים - התקנת תלויות, הידור, ולעיתים פריסה לסביבת בדיקה. כאן משטח הסיכון גדל: תהליך build יכול להריץ סקריפטים (postinstall hooks, למשל) שמגיעים מחבילות צד שלישי, ואלה הם בדיוק אותו סוג קוד לא מהימן שדיברנו עליו - רק שהפעם הוא לא נכתב על ידי המודל אלא הגיע דרכו בעקיפין. ארגונים שמריצים build pipelines כאלה בתוך sandbox של Agent נוהגים להפריד בין שלב ההתקנה (עם גישת רשת מוגבלת ל-registry בלבד) לשלב ההרצה בפועל (ללא גישת רשת כלל), כדי לצמצם את החלון שבו קוד חיצוני יכול "לברוח" עם מידע.

בדיקה ואימות: איך יודעים שה-Sandbox באמת עמיד

הקמת Sandbox היא רק חצי מהעבודה - החצי השני הוא לוודא באופן שיטתי שהוא באמת עוצר את מה שהוא אמור לעצור. שלוש שיטות בדיקה מרכזיות:

  • בדיקות חדירה ייעודיות (Penetration Testing) - הרצת תרחישי תקיפה ידועים (ניסיון escape, ניסיון exfiltration דרך DNS, ניסיון resource exhaustion) כחלק משגרת בדיקות, לא כפעולה חד-פעמית בהשקה.
  • Chaos-style testing לגבולות המשאבים - הרצת קוד שבמכוון מנסה לחרוג ממגבלות ה-CPU, הזיכרון וה-timeout, ווידוא שהאכיפה קורית ברמת ה-runtime ולא רק ברמת בקשה "מנומסת" מהקוד עצמו.
  • ביקורת תצורה תקופתית - קונפיגורציית ה-Sandbox (allowlist רשת, מגבלות משאבים, הרשאות filesystem) נוטה "להתרחב" עם הזמן ככל שמוסיפים יכולות חדשות. סקירה תקופתית שמוודאת שהאללוליסט עדיין תואם למינימום הדרוש היא חלק חיוני מהתחזוקה, לא שלב חד-פעמי.

שווה גם לשלב את הבדיקות האלה כחלק מCI/CD מותאם ל-AI - כל שינוי בקונפיגורציית ה-Sandbox עובר את אותה סוויטת בדיקות אבטחה לפני שהוא מגיע לפרודקשן, בדיוק כמו כל שינוי קוד אחר.

טעויות נפוצות

  • לסמוך על timeout ברמת האפליקציה בלבד - אם ה-timeout רץ בתוך אותו תהליך שיכול להיתקע, הוא לא יופעל. האכיפה חייבת להיות חיצונית לקוד שרץ.
  • לפתוח את כל האינטרנט "כי קשה לדעת אילו דומיינים צריך" - זו בדיוק הסיבה שצריך allowlist, לא סיבה לוותר עליו.
  • לשכוח לנקות בין הרצות - filesystem שלא מתאפס יכול לדלוף מידע בין משימות של משתמשים שונים.
  • להתייחס ל-Sandbox כפתרון חד-פעמי ולא כחלק מארכיטקטורת Zero-Trust רחבה יותר, שבה כל שכבה מניחה שהשכבה הקודמת עלולה להיכשל.

שאלות נפוצות

האם container Docker רגיל מספיק ל-Agent שמריץ קוד?

לרוב לא מספיק בפני עצמו לקוד לא מהימן ברמת ייצור. container רגיל חולק kernel עם ההוסט, כך שחולשה בקרנל עלולה לאפשר escape. כדאי לשלב אותו לפחות עם seccomp, drop capabilities, ורשת מוגבלת, ולשקול gVisor או microVM לקוד עם רמת סיכון גבוהה יותר.

מה ההבדל בין Sandbox לבין Guardrails?

Guardrails בודקים ומסננים את התוכן (מה שהמודל אומר או מבקש לעשות) לפני שהוא מתבצע. Sandbox הוא שכבת ביצוע - היא מגבילה את הנזק גם אם ה-Guardrails פספסו משהו. שתי השכבות משלימות זו את זו ואינן תחליף זו לזו.

איך מודדים אם ה-Sandbox "מספיק חזק"?

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

האם Sandboxing פוגע בזמני תגובה של ה-Agent?

כן, בעיקר ב-cold start. אפשר לצמצם עם pool של sandboxes חמים מוכנים מראש, אך זה מוסיף מורכבות תפעולית שצריך לתכנן מראש כחלק מהארכיטקטורה.

הקמת שכבת Sandboxing נכונה היא אחד הפרויקטים שבהם ההשקעה הראשונית קטנה משמעותית מהעלות של תקרית אחת. בצוות מדיה דיל אנחנו בונים ומטמיעים ארכיטקטורות הרצה מבודדות ל-Agents בפרודקשן - אפשר להתחיל בשיחה קצרה בוואטסאפ.

תגיות: AI Sandboxing · microVM · gVisor · Firecracker · container isolation · code execution security · Agent security

← חזרה לבלוג · צור קשר