دستیار مبتنی بر هوش مصنوعی شما ۹۹٪ مواقع از دستورات خود پیروی می‌کند، اما آن ۱٪ باقی‌مانده دقیقاً همان جایی است که مهاجمان ضربه می‌زنند. یک کاربر مخرب می‌تواند با وارد کردن یک دستور (prompt) طراحی‌شده، مدل را وادار کند تا توابعی را فراخوانی کند که نباید، و از این طریق داده‌ها را سرقت کرده یا اقدامات دارای سطح دسترسی بالا را انجام دهد. راه حل، استفاده از کلمات مودبانه‌تر نیست؛ بلکه برخورد با این نقص به عنوان یک مسئله «مجوزدهی» (authorization) و حذف ابزارهای خطرناک از دسترس مدل است.

چرا تزریق دستور (Prompt Injection) صرفاً یک مشکل نگارشی نیست

توسعه‌دهندگان اغلب سعی می‌کنند با استفاده از هشدارهای با حروف بزرگ، قوانین شماره‌گذاری شده یا بندهایی مانند «از توابع ادمین استفاده نکن»، امنیت عامل‌ها (agents) را بالا ببرند. این دفاع‌ها بر این فرض استوارند که مدل از جمله‌ای که می‌گوید «X را انجام نده» پیروی خواهد کرد. در عمل، می‌توان مدل را با بازنویسی درخواست، نقش‌آفرینی با یک شخصیت متفاوت یا صرفاً افزودن بافت (context) اضافی، متقاعد کرد که دستور را نادیده بگیرد. مرزهای زبانی قابل مذاکره هستند؛ اما دستور مهاجم نامحدود است و تست کردن آن هزینه‌ای ندارد.

آسیب‌پذیری واقعی در لیست ابزارهایی نهفته است که عامل دریافت می‌کند. وقتی طرحواره (schema) دستور شامل تابعی باشد که حقوق ادمین را اعطا می‌کند، مدل اکنون نقشه‌ای برای رسیدن به آن قدرت در اختیار دارد. حتی اگر در دستور آمده باشد که «از آن برای مشتریان استفاده نکن»، باز هم می‌توان مدل را متقاعد کرد که آن را فراخوانی کند، زیرا آن تابع در محیط اجرای مدل وجود دارد. بنابراین، مشکل یک شکاف مجوزدهی است: سیستم در حال نمایش قابلیت‌های ممتاز به فراخوانی‌کننده‌ای است که هیچ حقی برای استفاده از آن‌ها ندارد.

ایمن‌سازی عامل‌ها با محدود کردن دسترسی

ساده‌ترین راه برای بستن این شکاف، جلوگیری از دسترسی مدل به ابزارهایی است که مجاز به استفاده از آن‌ها نیست. لیست ابزارها را مانند یک کلید API در نظر بگیرید: اگر کلید وجود نداشته باشد، فراخوانی نمی‌تواند انجام شود. هیچ عبارت هوشمندانه‌ای نمی‌تواند تابعی را که در بافت فعلی وجود ندارد، احضار کند.

روش اشتباه

Prompt: “You are an assistant. Do not use the adminDeleteUser function for regular customers.”

مدل همچنان adminDeleteUser را در جعبه‌ابزار خود می‌بیند و می‌توان او را برای فراخوانی آن فریب داد.

روش درست

Prompt schema for a regular customer: { “functions”: [ “searchCatalog”, “placeOrder” ] }

adminDeleteUser هرگز ظاهر نمی‌شود، بنابراین مدل هیچ مسیری برای فراخوانی آن ندارد.

سه قانون کاربردی برای توسعه‌دهندگان

۱. ساخت لیست ابزارها بر اساس هر درخواست – کاتالوگ توابع را به صورت پویا و بر اساس مجوزهای فراخوانی‌کننده احراز هویت‌شده تولید کنید. یک مشتری فقط توابعی را می‌بیند که به آن‌ها نیاز دارد؛ یک ادمین مجموعه کامل را مشاهده می‌کند.
۲. شکست در حالت بسته (Fail closed) – اگر هویت کاربر قابل تایید نبود، به جای بازگرداندن یک لیست پیش‌فرض شامل «همه ابزارها در دسترس هستند»، یک لیست خالی برگردانید. این کار تضمین می‌کند که یک درخواست بدون احراز هویت هرگز به قدرت غیرمنتظره دست نمی‌یابد.
۳. اجتناب از وضعیت مشترک (Shared state) – هنگام ذخیره‌سازی (caching) تعاریف ابزارها، هرگز داده‌های مربوط به یک کاربر خاص را روی یک شیء مشترک ننویسید. از روش copy-on-write یا کپی‌های مخصوص هر نشست (session) استفاده کنید تا مجوزهای یک کاربر به درخواست کاربر دیگر نشت نکند.

اگر طرحواره‌ای که به یک کاربر عادی ارائه می‌شود با طرحواره‌ای که به ادمین نشان داده می‌شود یکسان باشد، مرز امنیتی همچنان متن دستور است، و دستورات (prompts) مکانیسم امنیتی قابل اعتمادی نیستند.

چه چیزی ما را به اینجا رساند

تزریق دستور زمانی پدیدار شد که توسعه‌دهندگان شروع به متصل کردن مدل‌های زبانی بزرگ (LLMs) به جریان‌های کاری عملیاتی کردند که مستلزم فراخوانی APIهای خارجی، اجرای کد یا تغییر پایگاه‌های داده توسط مدل بود. «استدلال» مدل توسط دستوری هدایت می‌شود که شامل لیستی از ابزارهای موجود نیز هست. نمونه‌های اولیه بر این فرض بودند که مدل از یک قانون زبان طبیعی مانند «رکوردها را برای غیر‌ادمین‌ها حذف نکن» پیروی می‌کند. مهاجمان به سرعت نشان دادند که چند جمله اضافی می‌تواند آن قوانین را دور بزند و مدل را وادار کند که همان تابع حذف را فراخوانی کند.

اولین واکنش جامعه، سخت‌گیرانه‌تر کردن زبان دستور، افزودن بندهای «هرگز X را انجام نده» یا استفاده از فیلترهای regex برای حذف توکن‌های مشکوک بود. این اقدامات سوءاستفاده‌های تصادفی را کاهش داد، اما مانع از مهاجم مصممی که می‌توانست به سادگی درخواست را بازنویسی کند، نشد. علت اصلی — یعنی نمایش توابع ممتاز به یک فراخوانی‌کننده غیرقابل اعتماد — همچنان پابرجا ماند.

چه کسی برنده می‌شود و چه کسی بازنده

سازمان‌هایی که محدودسازی ابزارها را بر اساس هر درخواست (per-request tool scoping) اتخاذ می‌کنند، به یک مرز شفاف و قابل اجرا دست می‌یابند. عامل‌های آن‌ها می‌توانند در مقیاس بزرگ مستقر شوند بدون اینکه نگران باشند یک دستور بدشکل، قابلیت‌های ادمین را باز خواهد کرد. تیم‌های انطباق (compliance) نیز از ردپای حسابرسی (audit trail) استقبال می‌کنند: لیست توابع ارسال شده به مدل، یک اثر ملموس است که می‌تواند ثبت و بازبینی شود.

توسعه‌دهندگانی که تنها به حفاظ‌های مبتنی بر دستور (prompt-only guards) تکیه می‌کنند، همچنان با هدفی متحرک روبرو هستند. عامل‌های آن‌ها ممکن است در مرحله تست عملکردی به نظر برسند، اما در محیط واقعی ممکن است مورد نفوذ قرار گیرند که منجر به نشت داده‌ها، تراکنش‌های غیرمجاز یا نقض قوانین انطباق می‌شود. هزینه یک رخنه بسیار فراتر از تلاش برای ساخت یک لیست ابزار پویا است.

استدلال مخالف: «دستورات بهتر کافی هستند»

برخی استدلال می‌کنند که با مهندسی دستورالعمل کافی — از جمله پرامپت‌های لایه‌بندی‌شده، پیام‌های سیستم و یادگیری تقویتی از بازخورد انسانی — می‌توان مدل را وادار کرد تا از بندهای «انجام نده» پیروی کند. واقعیت این است که مدل‌های زبانی مولدهای احتمالی هستند؛ آن‌ها محتمل‌ترین ادامه متن را وزن‌دهی می‌کنند، نه یک قانون امنیتی سخت‌گیرانه را. حتی با وجود حفاظ‌های (guardrails) تنظیم‌شده، یک عبارت‌بندی جدید می‌تواند از آن‌ها عبور کند، به‌ویژه زمانی که مهاجم می‌تواند با هزینه صفر، بی‌وقفه تکرار و آزمایش کند. حفاظ‌ها برای کاهش نویز مفید هستند اما نباید تنها خط دفاعی باشند.

آنچه باید در ادامه زیر نظر داشت

  • چارچوب‌هایی که محدودسازی ابزار (tool scoping) را به عنوان یک API سطح‌بالا ارائه می‌دهند – انتظار کتابخانه‌های جدیدی را داشته باشید که به شما اجازه می‌دهند قابلیت‌های هر کاربر را تعریف کرده و لیست توابع را پیش از ساخته شدن پرامپت، به‌طور خودکار هرس کنید.
  • «مانیفست‌های تابع» استاندارد شده – گروه‌های صنعتی ممکن است یک طرحواره (schema) JSON تعریف کنند که توابع عمومی را از توابع دارای امتیاز (privileged) جدا می‌کند و تولید مانیفست‌های مخصوص هر درخواست را آسان‌تر می‌سازد.
  • اجرای زمان اجرا (Runtime enforcement) – برخی پلتفرم‌ها در حال آزمایش اجرای محیط ایزوله (sandboxed execution) هستند که توکن فراخواننده را با تابعی که فراخوانی شده تطبیق می‌دهد و لایه دومی فراتر از محدودسازی پرامپت اضافه می‌کند.

نتیجه‌گیری روشن است: با تزریق پرامپت (prompt injection) مانند یک نقص در سطح مجوزدهی (authorization) برخورد کنید. با حذف ابزارهای غیرمجاز از جعبه‌ابزار مدل، سطح حمله‌ای را که یک پرامپت با عبارات هوشمندانه به دنبال بهره‌برداری از آن است، از بین می‌برید. پرامپت‌ها می‌توانند رفتار را هدایت کنند، اما نمی‌توانند جایگزین کنترل دسترسی مناسب شوند.