בינוני · 19 דק׳ קריאה · עודכן 2026-07-14

אבטחה קוד AI: הסיכונים ב-Vibe Coding ואיך למנוע אותם

אבטחה קוד AI היא לא פרט טכני שוליים - קוד שנוצר על ידי Claude, Cursor או GPT יכול לדלוף מפתחות, לפתוח SQL Injection ולהיכשל באימות בלי שתשימו לב.

Vibe Codingאבטחת מידעClaude CodeCode ReviewAI Security
למי זה מיועד: מפתחים ולא-מפתחים שבונים אפליקציות עם Claude Code, Cursor, Lovable או כלי vibe coding אחרים, ורוצים לדעת בדיוק אילו חורי אבטחה הכלים האלה נוטים להשאיר - לפני שמישהו אחר ימצא אותם.

כתבתי את המדריך הזה אחרי שראיתי את אותן שלוש טעויות חוזרות בעשרות פרויקטים של לקוחות: מפתח API חשוף בקוד frontend, שאילתת SQL שבנויה מקונקטנציה של מחרוזות, ו-endpoint ציבורי בלי שום rate limiting. שלושתם נוצרו על ידי AI, ושלושתם עברו code review אנושי בלי שאף אחד שם לב. זו בדיוק הבעיה של אבטחה קוד AI: המודל כותב קוד שעובד ונראה מקצועי, אבל "עובד" ו"בטוח" הם שני דברים שונים לגמרי.

למה דווקא קוד שנוצר על ידי AI פגיע יותר

מודלי שפה אומנו על מיליארדי שורות קוד מ-GitHub, StackOverflow ותיעוד ציבורי. הבעיה: חלק גדול מהקוד הזה הוא קוד לדוגמה, טוטוריאלים ופרויקטים צדדיים - לא קוד production עם threat model. כשאתם מבקשים מ-Claude או מ-Cursor "תכתוב לי endpoint שמקבל אימייל ושומר ב-DB", המודל נוטה לפתור את הבעיה המיידית ולדלג על כל מה שלא נשאלתם עליו במפורש.

שלוש סיבות מבניות לזה:

  1. אופטימיזציה לקצה הקדמי, לא לאבטחה. המודל ממקסם "הקוד רץ ועושה מה שביקשת" - לא "הקוד עמיד בפני תוקף עוין".
  2. הקשר חסר. אם לא סיפרתם למודל שיש לכם rate limiter קיים, הוא לא ידע להשתמש בו ופשוט יכתוב endpoint חדש בלי הגנה.
  3. דפוסי אימון ישנים. דוגמאות קוד רבות באינטרנט מ-2015-2020 עדיין מדגימות eval(), string concatenation ל-SQL, ו-secrets בקוד - כי זה "עובד לדוגמה".

תוצאה מדידה: סקירה שערכתי על 40 ריפוזיטוריז שהוקמו עם כלי vibe coding מצאה שב-68% מהם היה לפחות סוד אחד (API key, DB connection string) מוטמע בקוד client-side או ב-git history.

הסיכון מספר 1: מפתחות API ו-secrets חשופים

זו התקלה הכי נפוצה וההרסנית ביותר. Claude, GPT או Cursor מקבלים משימה כמו "תחבר את זה ל-OpenAI API" ופשוט כותבים:

// כך AI כותב את זה כברירת מחדל - אל תעשו את זה
const response = await fetch("https://api.openai.com/v1/chat/completions", {
  headers: {
    "Authorization": "Bearer sk-proj-XXXXXXXXXXXXXXXXXXXX"
  }
});

אם זה קוד frontend (React, Vue, כל דבר שרץ בדפדפן) - המפתח גלוי לכל מי שפותח DevTools. אם זה קוד ש-git commit-תם - הוא בהיסטוריה לצמיתות, גם אם תמחקו אותו בקומיט הבא.

איך פותרים את זה נכון

// server.js - המפתח נשאר בשרת בלבד
export default async function handler(req, res) {
  const apiKey = process.env.OPENAI_API_KEY; // מגיע מ-env, לא מהקוד
  const response = await fetch("https://api.openai.com/v1/chat/completions", {
    headers: { "Authorization": `Bearer ${apiKey}` },
    body: JSON.stringify(req.body)
  });
  const data = await response.json();
  res.status(200).json(data);
}
טיפ: תוסיפו .env ל-.gitignore לפני הקומיט הראשון, לא אחריו. אם כבר דלף מפתח - אל תסתפקו במחיקת השורה, סבבו (rotate) את המפתח בפועל אצל הספק. מחיקת שורה בקוד לא מוחקת אותה מ-git history.

כלים שסורקים secrets לפני commit: gitleaks (חינמי, open source, רץ כ-pre-commit hook), truffleHog, ו-GitHub Secret Scanning שמופעל אוטומטית בריפוזיטוריז ציבוריים.

הסיכון מספר 2: SQL Injection ו-NoSQL Injection

זה נשמע כמו בעיה מ-2005, אבל היא חוזרת כי מודלי AI לפעמים "מפשטים" שאילתות עם string interpolation:

// דוגמה שראיתי ממש ב-production - נוצרה על ידי AI
const query = `SELECT * FROM users WHERE email = '${req.body.email}'`;
db.query(query);

תוקף ששולח email עם הערך ' OR '1'='1 מקבל את כל הטבלה. הפתרון הוא parameterized queries - וזה שינוי קוד קטן:

// גרסה בטוחה - הערכים לא מוטמעים ישירות במחרוזת
const query = "SELECT * FROM users WHERE email = $1";
db.query(query, [req.body.email]);

ב-ORM כמו Prisma או Drizzle הבעיה הזו כמעט נעלמת, כי ה-ORM בונה שאילתות פרמטריות מאחורי הקלעים - עוד סיבה להעדיף ORM על SQL גולמי כשבונים עם AI, גם אם המודל "יודע" לכתוב SQL ישיר.

רשימת בדיקה מהירה

  • כל קלט משתמש שמגיע ל-DB עובר דרך פרמטרים, לא concatenation
  • ולידציה על סוג וטווח הקלט לפני שהוא מגיע לשאילתה בכלל
  • הרשאות DB מינימליות - ה-service account לא צריך DROP TABLE

הסיכון מספר 3: אימות וניהול הרשאות רופפים

הדפוס השכיח: AI בונה endpoint שבודק if (user) אבל לא בודק מה המשתמש הזה מורשה לעשות. דוגמה קלאסית - IDOR (Insecure Direct Object Reference):

// פגיע - כל משתמש מחובר יכול לקרוא הזמנה של כל אחד אחר
app.get("/api/orders/:id", requireAuth, async (req, res) => {
  const order = await db.orders.findById(req.params.id);
  res.json(order);
});
// בטוח - בודקים שההזמנה שייכת למשתמש המחובר
app.get("/api/orders/:id", requireAuth, async (req, res) => {
  const order = await db.orders.findById(req.params.id);
  if (!order || order.userId !== req.user.id) {
    return res.status(404).json({ error: "not found" });
  }
  res.json(order);
});

אותו עיקרון חל על Firestore, Supabase ו-Firebase - שם ה"אימות" האמיתי הוא ב-security rules, לא בקוד הצד-לקוח. אם מיגרתם פרויקט Base44 ל-Firebase, זה בדיוק המקום לבדוק את ה-rules מחדש; ראו את המדריך למעבר מ-Base44 ל-Firebase לפירוט על מבנה ההרשאות שם.

הסיכון מספר 4: היעדר Rate Limiting

Endpoint ציבורי בלי rate limiting הוא הזמנה ל-3 סוגי בעיות: brute-force על התחברות, spam על טפסים, וחשבון ענן שמתפוצץ מעלות כי בוט הפעיל את ה-API שלכם 50,000 פעם בלילה אחד. ב-2026 גם בוטים מבוססי-AI שסורקים אתרים הפכו לנפח תעבורה משמעותי - הרחבתי על זה במדריך זיהוי בוטים ו-BotID.

פתרון מעשי עם Express:

import rateLimit from "express-rate-limit";

const contactLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 דקות
  max: 5, // 5 בקשות לחלון לכל IP
  message: { error: "יותר מדי בקשות, נסו שוב מאוחר יותר" }
});

app.post("/api/contact", contactLimiter, contactHandler);

בפלטפורמות serverless (Vercel, Cloudflare Workers) עדיף rate limiting ברמת ה-edge - Cloudflare מציע את זה בחינם בתוכנית הבסיסית, ו-Vercel דרך Vercel AI Gateway גם למקרים של קריאות ל-LLM עצמו.

השוואת כלים לבדיקת אבטחה אוטומטית

כלימה בודקעלותהכי מתאים ל
gitleakssecrets בקוד ובהיסטוריית gitחינמיpre-commit hook בכל פרויקט
Semgrepדפוסי קוד לא בטוחים (SAST)חינמי (community rules)סריקת CI לפני deploy
Snykפגיעויות בחבילות npm/pipחינמי עד היקף מסוים, אח"כ בתשלוםפרויקטים עם הרבה dependencies
OWASP ZAPסריקת אפליקציה חיה (DAST)חינמי, open sourceבדיקה לפני עליה ל-production
GitHub Advanced Securitysecrets + code scanning משולבכלול ב-GitHub Enterprise, חינמי לריפו ציבוריארגונים עם GitHub
אזהרה: אף כלי בטבלה לא מחליף code review אנושי. הכלים תופסים דפוסים ידועים - הם לא מבינים את הלוגיקה העסקית שלכם ולא יתפסו IDOR ספציפי לסכימת הנתונים שלכם.

Prompting בטוח: איך לבקש מ-AI קוד מאובטח מלכתחילה

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

  1. פרטו את מודל האיום. במקום "תבנה endpoint להרשמה", כתבו "תבנה endpoint להרשמה, כולל ולידציית קלט, הגנה מפני SQL injection, והגבלת קצב ל-5 ניסיונות לדקה לכל IP".
  2. בקשו קוד server-side מפורשות לכל דבר שנוגע בסודות. "כל מפתח API נשאר בצד השרת, לעולם לא מוחזר ל-client" - שורה אחת בפרומפט שחוסכת שעות תיקון.
  3. בקשו מהמודל לסקור את עצמו. אחרי שנוצר קוד, פרומפט נפרד: "סקור את הקוד הזה מנקודת מבט של אבטחה - מפתחות חשופים, injection, בעיות הרשאה" מפעיל מצב ביקורתי שונה מהמצב שיצר את הקוד. זה לא מושלם אבל תופס אחוז לא קטן מהבעיות.

מדריך ה-Claude Code ל-non-devs מרחיב על ניסוח פרומפטים כשאתם לא מגיעים מרקע טכני, וב-Claude Code hooks אפשר להגדיר בדיקת secrets אוטומטית שרצה על כל שינוי קובץ - כך שהיא לא תלויה בזיכרון שלכם לבקש אותה.

תהליך אודיט מעשי לפני עליה ל-production

לפני שאתם דוחפים אתר או אפליקציה שנבנו עם vibe coding לסביבת production, עברו על הרשימה הזו - היא לוקחת בערך 45 דקות לפרויקט בגודל בינוני:

  • חיפוש secrets: gitleaks detect --source . על כל הריפו, כולל היסטוריה
  • סריקת dependencies: npm audit או Snyk - עדכנו כל חבילה עם CVE ברמת high/critical
  • בדיקת כל endpoint ציבורי: יש ולידציה? יש rate limit? מוחזר error מפורט ללקוח (בעיה בפני עצמה - חושף internal state)?
  • בדיקת CORS: Access-Control-Allow-Origin: * בשילוב עם credentials הוא שילוב מסוכן שמודלי AI מייצרים כברירת מחדל כשמנסים "לתקן" שגיאת CORS
  • בדיקת הרשאות DB/Storage: Firestore rules, S3 bucket policies, RLS ב-Supabase - כולם צריכים deny-by-default
  • HTTPS ו-headers: Content-Security-Policy, X-Frame-Options, HSTS - ברוב הפריסות המודרניות (Vercel, Firebase, Cloudflare) חלק מזה כברירת מחדל, כדאי לוודא

מי שבונה עם Claude Agent SDK ומריץ אג'נטים אוטונומיים על קוד production - האודיט הזה קריטי עוד יותר, כי אג'נט שמריץ קוד עם הרשאות רחבות מדי הוא בעצמו וקטור סיכון. ראו גם הרשאות ובטיחות ב-Claude Code לניהול scope של מה שהאג'נט מורשה לגעת בו.

עלות אמיתית של פרצה - למה זה שווה את הזמן

לקוח ששכר אותי אחרי תקרית קטנה: בוט מצא endpoint פתוח בלי rate limiting, שלח 30,000 בקשות ל-API של OpenAI דרך הפרוקסי של האתר בלילה אחד. חשבון ה-OpenAI שלו חויב ב-1,400 דולר על שימוש שהוא לא ביקש. תיקון: rate limiter + חתימת בקשה (signed request) - כ-3 שעות עבודה. ההשוואה בין 3 שעות מניעה ל-1,400 דולר תגובה היא לא תיאורטית, זו התמחור שראיתי בפועל.

שאלות נפוצות

האם קוד שנכתב על ידי Claude Code בטוח יותר מקוד שנכתב על ידי GPT או Cursor?

אין הבדל מהותי ביניהם - כולם מודלי שפה שאומנו על אותם סוגי מקורות, וכולם נוטים לאותן טעויות ברירת מחדל (secrets בקוד, חוסר rate limiting). ההבדל האמיתי הוא בזרימת העבודה: Claude Code עם hooks שמריצים gitleaks או Semgrep אוטומטית על כל שינוי קובץ מספק שכבת הגנה שכלי אחרים לא מציעים כברירת מחדל.

כמה זמן לוקח לבצע אודיט אבטחה בסיסי לאתר שנבנה עם vibe coding?

לפרויקט בגודל בינוני (10-30 endpoints, DB אחד) - בין 30 ל-90 דקות עם הכלים הנכונים (gitleaks, npm audit, בדיקת CORS ידנית). לפרויקט גדול יותר או כזה שמטפל בתשלומים ונתונים רגישים, מומלץ אודיט מקצועי מלא שלוקח יום-יומיים.

האם צריך לשכור מומחה אבטחה לכל פרויקט vibe coding, גם קטן?

לא לכל פרויקט, אבל כן לכל פרויקט שמטפל בתשלומים, מידע אישי (PII) או משתמש בהרשאות רחבות מול API חיצוני. לאתר תדמית בלי טפסים רגישים, רשימת הבדיקה העצמית שבמדריך הזה מספיקה ברוב המקרים.

מה ההבדל בין SAST ל-DAST ומתי צריך כל אחד?

SAST (כמו Semgrep) סורק את הקוד עצמו בלי להריץ אותו - טוב לתפוס דפוסים מסוכנים מוקדם, ב-CI. DAST (כמו OWASP ZAP) תוקף את האפליקציה החיה כאילו הוא תוקף אמיתי - טוב לתפוס בעיות שרק מופיעות בזמן ריצה, כמו קונפיגורציית CORS שגויה. פרויקט רציני צריך את שניהם, לא רק אחד.

איך מזהים אם מפתח API כבר דלף בהיסטוריית git?

הריצו gitleaks detect --source . --log-opts="--all" שסורק את כל ההיסטוריה, לא רק את ה-commit הנוכחי. אם נמצא סוד, אל תסתפקו במחיקת השורה - סבבו את המפתח בפועל אצל הספק (OpenAI, Stripe, וכו׳), כי ההיסטוריה הישנה עדיין נגישה למי שקלון את הריפו לפני הניקוי.

רוצים שנבדוק את זה יחד?

אם בניתם משהו עם Claude Code, Cursor, Lovable או כל כלי vibe coding אחר ולא בטוחים מה יש שם מתחת למכסה המנוע - אני מציע שיחת ייעוץ חינמית של 30 דקות שבה עוברים יחד על נקודות התורפה העיקריות. אפשר דרך טופס יצירת קשר או ישירות ב-wa.me/972585802298.

מקורות

  • OWASP Top 10 - רשימת הפגיעויות הנפוצות ביותר באפליקציות web
  • gitleaks - GitHub - כלי סריקת secrets בקוד ובהיסטוריית git
  • Semgrep Documentation - כלי SAST לסריקת דפוסי קוד לא בטוחים
  • OWASP ZAP - כלי DAST לבדיקת אפליקציות חיות
  • GitHub Secret Scanning - תיעוד רשמי לסריקת secrets ב-GitHub