یک کوتیشن اشتباه یا یک خط جدید پنهان در دستوراتی که هوش مصنوعی تولید میکند، میتواند یک عامل مفید را به یک فاجعه امنیتی تبدیل کند. باید بدانید که اعتماد به رشتههای متنی در محیطهای اجرایی، بزرگترین حفره امنیتی عاملهای هوش مصنوعی است. در واقع، یک کاراکتر جابهجا شده در دستورات تولید شده توسط AI میتواند دسترسیهای سیستمی را باز کند.
به نقل از راهنمای فنی منتشر شده در dev.to در ۲۳ سپتامبر ۲۰۲۶، معماری جدیدی پیشنهاد شده که فراخوانی ابزارها را نه به شکل گفتگو با شل (Shell)، بلکه به صورت نگاشت اشیاء JSON روی بردارهای ثابت argv مدیریت میکند. در واقع، اکثر توسعهدهندگان فعلاً با مدلها طوری تعامل میکنند که انگار مدل دارد «با بش (bash) حرف میزند». این رویکرد بر پایه درونیسازی رشتهها (string interpolation) است؛ یعنی میزبان، آرگومانهای مدل را به یک رشته متنی میچسباند و آن را به شلی مثل bash -lc میسپارد.
این روش یک سطح حمله گسترده ایجاد میکند؛ جایی که مدل میتواند خط لولههای (pipelines) جدید اختراع کند، متغیرهای محیطی مثل $HOME را گسترش دهد یا اسکریپتهای کمکی بررسینشدهای را اجرا کند. نویسنده این راهنما هشدار میدهد که «کوتیشنها و خطهای جدید دروغ میگویند» و آن «کمکهای کوچک» که مدل ممکن است اختراع کند، اغلب خط لولههایی هستند که توسعهدهنده هرگز آنها را بررسی نکرده است. همانطور که در تحلیلهای پیشین ما دربارهی امنیت مدلهای بازمتن اشاره کردیم، مدلها تمایل دارند برای حل مسئله، مسیرهای میانبری پیدا کنند که لزوماً امن نیستند.
برای حل این مشکل، معماری پیشنهادی مالکیت کامل اجرا را به میزبان برمیگرداند. در این سیستم، مدل فقط یک فراخوانی ساختاریافته را پیشنهاد میدهد؛ میزبان آن را با یک کاتالوگ ثابت اعتبارسنجی کرده و با استفاده از فراخوانیهای زیرپروسه (subprocess) مبتنی بر لیست اجرا میکند. این یعنی هیچ شلی برای تفسیر دستورات به کار گرفته نمیشود و امکان سوءاستفاده از متاکاراکترهای شل کاملاً از بین میرود.
چرخه مدیریت میزبان از یک توالی سختگیرانه پیروی میکند: مدل خروجی {"tool": "...", "args": { ... }} را برمیگرداند، میزبان نام ابزار را در کاتالوگ ثابت چک میکند، آرگومانها را با JSON Schema — که مثل یک فرم ثبتنام دقیق است و اجازه نمیدهد هیچ فیلد اضافهای پر شود — اعتبارسنجی میکند و در نهایت آرگومانها را روی یک بردار argv مینشاند، نه یک رشته متنی. این فرآیند تضمین میکند که ورودی مدل هرگز مستقیماً به مفسر دستورات ارسال نشود.
کاتالوگ ابزارهای ثابت
بنیاد این سیستم فایلی به نام tools.json است که به عنوان یک قرارداد سخت عمل میکند. برخلاف توصیفات متنی در پرامپت که نویسنده آنها را «غیرقراردادی» میداند، این فایل تحت کنترل نسخه (version-controlled) و برای مدل تغییرناپذیر است. اگر این کاتالوگ در سیستم کنترل نسخه نباشد، نویسنده آن را صرفاً یک «شایعه» مینامد و توصیه میکند عامل را اجرا نکنید.
- اسکیماهای سختگیرانه: هر ابزار یک JSON Schema دارد که
additionalPropertiesرا ممنوع میکند. اگر مدل یک کلید اضافی اضافه کند — که رفتاری رایج در مدلهاست — عملیات فوراً شکست میخورد. برای مثال، ابزارpytest_oneنیازمند یک رشتهnodeidبین ۱ تا ۲۰۰ کاراکتر است که با الگوی^[A-Za-z0-9_./:\[\]-]+$مطابقت داشته باشد. - قالبهای argv: به جای رشتههای آزاد، ابزارها از قالبهایی مثل
["python", "-m", "pytest", "-q", "{nodeid}"]یا برای ابزارgit_statusاز["git", "status", "--porcelain=v1"]استفاده میکنند. این قالبها اجازه نمیدهند مدل ساختار دستور را تغییر دهد. - ممنوعیت باینریهای شل: کاتالوگ صراحتاً ابزارهایی مثل
bashیاshیاnpm runبا اسکریپتهای آزاد، یاcurlبا URLهای اختراعی مدل را حذف میکند. اگر تسکی نتواند در قالب یک ابزار نامگذاری شده با اسکیمای تنگ تعریف شود، اجرا نخواهد شد.
برای تایید این مرحله، راهنما پیشنهاد میکند یک چک پایتونی برای موفقیت json.loads روی کاتالوگ و یک چک گیت برای اطمینان از عدم نادیده گرفته شدن tools.json توسط .gitignore اجرا شود تا از صحت فایل قرارداد اطمینان حاصل گردد.
دروازه اعتبارسنجی
اعتبارسنجی در دو مرحله مجزا رخ میدهد پیش از آنکه هرگونه اجرایی صورت گیرد. ابتدا میزبان نام ابزار را با کاتالوگ چک کرده و آرگومانها را با JSON Schema اعتبارسنجی میکند. این همان «دروازه» است؛ هر کلید اضافی یا نوع داده اشتباه منجر به شکست فوری میشود.
در مرحله دوم، میزبان یک بررسی دستی برای متاکاراکترهای شل انجام میدهد. حتی اگر اسکیما اجازه استفاده از رشته را بدهد، اجراکننده هر مقداری که شامل کاراکترهایی مثل \t ،\n ،\r ،" ،' ،` ،$ ،| ،& ،; ،< ،> ،( یا ) باشد را رد میکند. این کار برای جلوگیری از هرگونه تلاش برای تزریق دستور (Command Injection) است.
این دفاع دو لایه مانع از آن میشود که یک الگوی اسکیما که به اشتباه شل شده است، حفره امنیتی ایجاد کند. نویسنده استدلال میکند که اسکیما لازم است اما کافی نیست، زیرا توسعهدهندگان ممکن است در نهایت یک الگو را «فقط برای این یک بار» شل کنند و همین یک بار کافی است تا سیستم به خطر بیفتد.
اجرا از طریق زیرپروسه مبتنی بر لیست
اجرا توسط یک اجراکننده پایتونی (مثلاً runner.py) مدیریت میشود که بهشدت از پرچم shell=True در subprocess.run دوری میکند. با پاس دادن یک لیست (argv) به جای رشته، سیستمعامل هر المان را به عنوان یک آرگومان لیتِرال میبیند، نه دستوری که باید توسط شل تجزیه شود.
- ایزولاسیون محیطی: اجراکننده از یک لیست سفید برای متغیرهای محیطی — بهطور خاص
PATH،LANG،LC_ALLوTERM— استفاده میکند تا مدل نتواند وضعیت حساس سیستم را لو دهد یا تغییر دهد. هر متغیر محیطی خارج از این لیست حذف میشود. - رد باینریهای شل: سیستم شامل یک بررسی سختافزاری (hard-coded) است تا هر اجرایی که اولین آرگومان آن یک باینری شل شناخته شده (مثل
bash،sh،zsh،fish،cmdیاpowershell) باشد را رد کند. نویسنده میگوید: «به فایل اعتماد کن، اما باز هم به آن بیاعتماد باش». - محدودیت خروجی: برای جلوگیری از غرق شدن مدل در داده یا کرش کردن میزبان، اجراکننده تنها ۲۰۴۸ کاراکتر اول stdout و stderr را کپچر میکند. این کار از حملات Denial of Service از طریق خروجیهای حجیم جلوگیری میکند.
- محدودیتهای زمانی: یک تایماوت
TIMEOUT_S۳۰ ثانیهای و تثبیت دایرکتوری کاری باcwd=Path.cwd()اعمال شده است تا پروسهها برای همیشه باز نمانند.
شمارنده گامهای تحت مالکیت میزبان
برای جلوگیری از حلقههای بینهایت — که برای مدلها ارزان اما برای میزبان گران هستند — یک شمارنده یکنواخت در فایل .agent_step روی دیسک ذخیره میشود.
چون مدل ابزاری برای نوشتن در این فایل خاص ندارد، نمیتواند شمارنده گامهای خود را ریست کند. به محض رسیدن به حد MAX_STEPS (که در مثال ۸ گام است)، میزبان عملیات را متوقف میکند. راهنما تاکید میکند که نباید به مدل فرصت تلاش مجدد برای «اصلاح» دستور داده شود، زیرا تلاشهای دوم اغلب حاوی رشتههای «مکارانهتر» هستند. تلاشهای مجدد به عنوان راه اصلی تبدیل باگهای درونیسازی به گزارشهای حادثه امنیتی دیده میشوند.
مدیریت شعاع انفجار
برای کسانی که روی این کاتالوگها کار میکنند، توصیه میشود از یک ماشین یکبارمصرف یا سرور اختصاصی استفاده کنند. این کار تضمین میکند که یک قالب argv بد نتواند به کلیدهای SSH محلی یا دادههای حساس لپتاپ دسترسی پیدا کند. هدف این است که «شعاع انفجار» تنها یک دایرکتوری باشد که بتوان آن را به سادگی حذف کرد.
در این راستا، MonkeyCode به عنوان منبعی برای دسترسی رایگان به مدلها و سرورهای ایزوله جهت تست این اجراکنندهها معرفی شده است تا حلقه اجرا روی لپتاپ شخصی قرار نگیرد. با این حال، نویسنده هشدار میدهد که سرور فقط یک جعبه است و کاتالوگ همچنان باید توسط توسعهدهنده تعریف و مدیریت شود.
جدول تصمیمگیری برای افزودن ابزار
توسعهدهندگان پیش از افزودن هر ابزار جدید به کاتالوگ، باید یک تست پنجمرحلهای را پاس کنند. اگر هر یک از پاسخها «شکست» باشد، ابزار منتشر نمیشود:
| پرسش | پاس | شکست |
|---|---|---|
| آیا میتوانم باینری را بدون حدس زدن $PATH نام ببرم؟ | argv[0] یک فایل اجرایی واقعی است | «هر چه در ایمیج هست» |
| آیا آرگومانها یک شیء بسته هستند؟ | additionalProperties: false و کلیدهای الزامی لیست شدهاند |
دستورات باقیمانده، فلگها، موارد اضافی |
| آیا هر بخش برای معنا پیدا کردن به شل نیاز دارد؟ | بدون لوله، glob، $(...) یا && | نیاز به تفسیر شل دارد |
| آیا میتوانم stdout را بدون بازگرداندن بایتهای خام محدود کنم؟ | استفاده از head + cap و سپس اسکیما برای نوبت بعد | «فقط دامپ کن» |
| در صورت وجود کلیدهای ناشناخته چه اتفاقی میافتد؟ | عملیات شکست میخورد | مدل تلاش مجدد میکند |
این جدول باید در Pull Requestها کپی شود. اگر بازبین نتواند برای هر ردیف تیک «پاس» بزند، ابزار — حتی ابزارهای دیباگ — حذف میشود.
محدودیتها و دامنه
این اجراکننده یک سندباکس امنیتی کامل نیست و جایگزین seccomp ،کانتینرها یا پالیسیهای شبکه نمیشود. برای مثال، python -m pytest همچنان میتواند ماژولهای غیرمنتظرهای را ایمپورت کند اگر محیط کثیف باشد، و git status اگرچه خواندنی است اما تضمینی برای بیضرر بودن مطلق نیست.
همچنین JSON Schema نجاتدهنده توسعهدهندهای نیست که اسکیمایی بنویسد که یک دستور را به صورت رشته آزاد میپذیرد؛ این فقط همان درونیسازی است با چند مرحله اضافه. بنابراین، این رویکرد برای کسانی که عاملهای شل همهمنظوره میسازند مناسب نیست، زیرا این کار «دروغ گفتن به کاربران» است.
این سیستم همچنین جایگزینی برای بازبینی کد (code review) قالبهای argv نیست. فلسفه اصلی ساده است: یک شیء JSON، یک بردار argv و یک شمارنده تحت مالکیت میزبان. همانطور که نویسنده نتیجه میگیرد: «تنگ بودن [قوانین] هدف اصلی است».
گام بعدی شما
- بررسی کنید آیا در عاملهای فعلی خود از
shell=Trueدر پایتون استفاده میکنید و آن را با لیستهای argv جایگزین کنید. - یک فایل
tools.jsonبرای ابزارهای عامل خود تعریف کنید و دسترسی مدل به تغییر این فایل را ببندید. - برای هر ابزار، یک JSON Schema سختگیرانه بنویسید که هیچ ویژگی اضافهای (
additionalProperties: false) را نمیپذیرد.
اما داستان ایزولاسیون سختافزاری این تحول حتی پیچیدهتر است — به تحلیل ما دربارهی کانتینرهای داکر برای مهار عاملهای هوش مصنوعی مراجعه کنید.




گفتگو