الگوهای امنیتی برای عاملهای خودمختار: درسهایی از پنتاگی

عاملهای هوش مصنوعی خودمختار دیگر محدود به پنجرههای چت نیستند. آنها کد را اجرا میکنند، APIها را فراخوانی میکنند، سیستمهای فایل را تغییر میدهند و گردشهای کاری چند مرحلهای را بدون انتظار برای تأیید انسان در هر مرحله، به هم متصل میکنند - و این اساساً مدل تهدید را تغییر میدهد.
فهرست مطالب
چرا عاملهای خودمختار یک نقطه عطف امنیتی هستند؟
عاملهای هوش مصنوعی خودمختار دیگر محدود به پنجرههای چت نیستند. آنها کد را اجرا میکنند، APIها را فراخوانی میکنند، سیستمهای فایل را تغییر میدهند و گردشهای کاری چند مرحلهای را بدون انتظار برای تأیید انسان در هر مرحله، به هم متصل میکنند. این خودمختاری به عاملها اجازه میدهد تا نوشتنهای سیستم فایل، فراخوانیهای API و دستورات shell را بدون بررسی انسانی در هر مرحله، زنجیره کنند و اساساً مدل تهدید را تغییر میدهد. یک عامل با پیکربندی نادرست و دسترسی shell میتواند امتیازات را افزایش دهد، دادههای حساس را استخراج کند یا در یک تکرار حلقهای عامل، در یک شبکه داخلی بچرخد. زیرساخت عامل محلی نیازمند استراتژیهای مهار است که با قابلیتهای اعطا شده مطابقت داشته باشد.
ده مورد برتر OWASP برای برنامههای LLM (نسخه ۲۰۲۵) خطراتی مانند مدیریت خروجی ناامن، عاملیت بیش از حد و کنترل دسترسی نامناسب را به عنوان آسیبپذیریهای حیاتی در سیستمهای مبتنی بر LLM برجسته میکند. این موارد نظری نیستند. آنها دقیقاً توصیف میکنند که وقتی محیط اجرای یک عامل فاقد مرزهای مناسب باشد، چه اتفاقی میافتد.
پنتاگی، یک عامل تست نفوذ متنباز مبتنی بر هوش مصنوعی از شرکت vxcontrol، مرجع مفیدی است زیرا عاملی است که برای حمله طراحی شده است - الگوهای مهار آن در برابر رفتار خصمانه آزمایش میشوند. این عاملی است که برای هک طراحی شده ، برای بررسی شبکهها و بهرهبرداری از آسیبپذیریها به صورت خودکار ساخته شده است. با این حال، معماری آن، خود-مهار را به عنوان یک نگرانی درجه یک در نظر میگیرد. الگوهایی که برای جعبه شنی، تعیین محدوده مجوز، نظارت انسانی و ثبت گزارش حسابرسی به کار میگیرد، مستقیماً به هر تیمی که عاملهای خودکار را به محیط عملیاتی منتقل میکند، منتقل میشود.
یک عامل با پیکربندی نادرست و دسترسی shell میتواند امتیازات را افزایش دهد، دادههای حساس را استخراج کند یا در یک تکرار حلقهی عامل واحد، در یک شبکهی داخلی بچرخد.
پنتاگی چیست و چرا برای امنیت عامل مهم است؟
پنتاگی (GitHub: vxcontrol/pentagi) یک عامل تست نفوذ کاملاً مستقل است که از هماهنگی LLM برای برنامهریزی و اجرای ارزیابیهای امنیتی استفاده میکند. پشته آن ترکیبی از یک backend زبان Go، یک frontend زبان React برای نظارت، یک لایه برنامهریزی LLM و یک محیط اجرای مبتنی بر Docker است که در آن تمام عملیات تهاجمی اجرا میشوند. معماری عمداً ماژولار است: LLM یک طرح ایجاد میکند، وظایف در یک صف قرار میگیرند، یک مجری sandboxed آنها را اجرا میکند و نتایج به یک لایه گزارشدهی بازخورد میدهد.
خطر آن دقیقاً همان چیزی است که آن را به معماری مرجع ایدهآل برای امنیت عامل تبدیل میکند. یک عامل تست نفوذ باید به ابزارهای اسکن شبکه، چارچوبهای اکسپلویت و اجرای پوسته دسترسی داشته باشد. اگر هر یک از این قابلیتها به خارج از مرزهای تعیینشده خود نشت کنند، عامل به تهدیدی برای میزبان خود تبدیل میشود. طراحی پنتاگی ثابت میکند که حتی خطرناکترین مورد استفاده از عامل را میتوان از طریق معماری مهار کرد، نه اینکه بعداً به آن فکر کرد.
معماری اصلی پنتاگی در یک نگاه
پنتاگی حجم کار خود را بین زیرعاملهای تخصصی تقسیم میکند که هر کدام به مجموعهای محدود از قابلیتها محدود شدهاند. بر اساس معماری منتشر شده پروژه، یک عامل جستجوگر، جستجوهای وب و OSINT را مدیریت میکند. یک عامل کدنویس ، اسکریپتها و ابزارها را مینویسد. یک عامل نصبکننده، وابستگیهای بسته را مدیریت میکند. یک عامل تست نفوذ، عملیات تهاجمی واقعی را اجرا میکند. هر زیرعامل فقط به ابزارهای مورد نیاز برای نقش خود دسترسی دارد و برنامهریز LLM، توالی آنها را بدون اعطای فضای نام ابزار مسطح و نامحدود به هیچ مؤلفهای، هماهنگ میکند. برای تعاریف زیرعامل فعلی و محدودههای ابزار، به مخزن پنتاگی مراجعه کنید، زیرا این موارد ممکن است در طول نسخهها تکامل یابند.
الگوی ۱: سندباکسینگ مبتنی بر کانتینر برای اجرای عامل
پنتاگی تمام عملیات تهاجمی را درون کانتینرهای ایزوله داکر اجرا میکند. این مهمترین مرز مهار است: صرف نظر از کاری که عامل درون کانتینر انجام میدهد (اسکن پورتها، اجرای اکسپلویتها، نوشتن روی دیسک)، فضای نام کانتینر شعاع انفجار را محدود میکند. ایزولهسازی سیستم فایل مانع از دسترسی عامل به منابع میزبان میشود. تقسیمبندی شبکه کنترل میکند که کدام اهداف قابل دسترسی هستند. محدودیتهای منابع مانع از مصرف CPU یا حافظه میزبان توسط یک فرآیند فراری میشود.
برای هر عامل خودمختار، این الگو را به عنوان یک الزام سخت در نظر بگیرید. بدون ایزولهسازی کانتینر، یک عامل تزریقشده با اعلان که به عنوان ریشه میزبان اجرا میشود، میتواند /etc/shadow را بخواند و به سرویسهای مجاور منتقل شود. فقط آنچه را که عامل نیاز دارد، نصب کنید و تمام قابلیتهای لینوکسی را که عامل به آنها نیاز ندارد، حذف کنید. در صورت امکان، یک سیستم فایل ریشه فقط خواندنی را اجرا کنید - این محدودیت واحد، کل دستهای از حملات پایداری را که در آن یک عامل آسیبدیده، درهای پشتی را در لایههای تصویر خود مینویسد، مسدود میکند. دسترسی به شبکه را به حداقل دامنه قابل اجرا محدود کنید.
پیشنیازها: این الگو به Docker Engine 20.10+ و Docker Compose CLI نسخه ۲+ ( docker compose ، نه نسخه قدیمی docker-compose نسخه ۱) نیاز دارد. محدودیتهای منابع تحت کلید deploy توسط نسخه قدیمی Compose نسخه ۱ در حالت غیر Swarm نادیده گرفته میشوند - هیچ خطایی ایجاد نمیشود و هیچ محدودیتی اعمال نمیشود. اگر باید از Compose نسخه ۱ پشتیبانی کنید، به جای آن از کلیدهای mem_limit و cpus سطح بالا استفاده کنید. مفاهیم اعمال اندازه tmpfs و قابلیت لینوکس که در زیر توضیح داده شده است، مختص میزبان لینوکس هستند. Docker Desktop در macOS و Windows ممکن است محدودیتهای اندازه tmpfs نادیده بگیرد و با محدودیتهای قابلیت رفتار متفاوتی داشته باشد.
پیادهسازی یک مجری عامل در محیط سندباکس
پیکربندی Docker Compose زیر، یک کانتینر اجرای قفلشده را نشان میدهد که بر اساس الگوهای موجود در معماری استقرار Pentagi مدلسازی شده است:
services : agent-executor : image : agent - sandbox : 1.0.0 user : "65534:65534" read_only : true tmpfs : - /tmp : size=100M cap_drop : - ALL cap_add : - NET_RAW security_opt : - no - new - privileges : true - seccomp : /etc/docker/seccomp/agent - executor.json networks : - agent - isolated volumes : - ./task - input : /data/input : ro - ./task - output : /data/output restart : on - failure : 3 deploy : resources : limits : cpus : "1.0" memory : 512M environment : - AGENT_ROLE=executor - ALLOWED_TARGETS=10.0.1.0/24
networks : agent-isolated : driver : bridge internal : true تصمیمات کلیدی در اینجا: cap_drop: ALL تمام قابلیتهای لینوکس را حذف میکند، سپس فقط موارد خاص مورد نیاز دوباره اضافه میشوند. حذف قابلیتها، امتیازات سطح بالا را محدود میکند اما فراخوانیهای سیستمی منفرد را محدود نمیکند. گزینه امنیتی seccomp یک پروفایل seccomp سفارشی اعمال میکند که مجموعه فراخوانیهای سیستمی مجاز را محدود میکند - این را با cap_drop: ALL برای دفاع در عمق جفت کنید. بدون پروفایل seccomp، NET_RAW به همراه فیلتر پیشفرض فراخوانی سیستمی مجاز داکر، همچنان تقریباً بیش از ۳۰۰ فراخوانی سیستمی، از جمله مقادیر اولیه مربوط به فرار از کانتینر در هستههای وصله نشده، را مجاز میداند. دستورالعمل user: "65534:65534" تضمین میکند که فرآیند کانتینر به عنوان کاربر nobody به جای root اجرا شود. حتی با no-new-privileges ، اجرا به عنوان root در داخل کانتینر، دسترسی نوشتن در سطح root را به لایههای قابل نوشتن اعطا میکند و تأثیر هرگونه فرار از کانتینر را به حداکثر میرساند. پرچم شبکه internal: true مانع از رسیدن کانتینر به اینترنت عمومی میشود، اما مانع از ارتباط کانتینرها در همان شبکه bridge با یکدیگر نمیشود. برای جداسازی جانبی بین کانتینرها، از شبکههای داکر جداگانه یا سیاستهای شبکه برای هر کانتینر استفاده کنید. سیاست restart: on-failure:3 تضمین میکند که یک مجری خرابشده تا سه بار مجدداً راهاندازی شود و بیصدا ناپدید نشود. محدودیتهای منابع، CPU و حافظه را محدود میکند تا از حملات انکار سرویس علیه میزبان جلوگیری شود؛ این موارد برای اجرا نیاز به Docker Compose CLI نسخه ۲+ دارند.
بدون ایزولهسازی کانتینر، یک عامل تزریقشده توسط prompt که به عنوان ریشه میزبان اجرا میشود، میتواند /etc/shadow را بخواند و به سرویسهای مجاور منتقل شود.
معماری زیرعامل پنتاگی یک اصل سختگیرانه را اجرا میکند: هر نقش عامل فقط ابزارهای مورد نیاز خود را میبیند. عامل جستجوگر میتواند در وب پرسوجو کند و فایلها را بخواند. عامل کدنویس میتواند اسکریپتها را بنویسد و اجرا کند. عامل نفوذسنج میتواند ابزارهای بهرهبرداری را اجرا کند. هیچکدام از آنها یک فضای نام مسطح را به اشتراک نمیگذارند که در آن هر عامل بتواند هر تابعی را فراخوانی کند.
این موضوع اهمیت دارد زیرا فراخوانی تابع LLM اساساً یک مرز امتیاز است. وقتی یک مدل لیستی از ابزارهای موجود را دریافت میکند، از هر آنچه که برای رسیدن به هدفش در دسترس است استفاده میکند. فضای نام ابزار مسطح به این معنی است که یک عامل کدنویسی میتواند به طور تصادفی (یا از طریق تزریق سریع) execute_shell با دستورات مخرب فراخوانی کند. قابلیت مشاهده ابزار بر اساس نقش، این دسته از خطاها را به طور کامل از بین میبرد.
تعریف مرزهای مجوز برای هر نقش عامل
package agentperm
import ( "log/slog" "sync" )
var ( mu sync . RWMutex registry map [ string ] map [ string ] struct { } )
func init ( ) { registry = map [ string ] map [ string ] struct { } { "searcher" : toSet ( "web_search" , "read_file" , "dns_lookup" ) , "coder" : toSet ( "write_file" , "execute_script" , "read_file" ) , "pentester" : toSet ( "nmap_scan" , "run_exploit" , "read_file" ) , } }
func toSet ( tools ... string ) map [ string ] struct { } { s := make ( map [ string ] struct { } , len ( tools ) ) for _ , t := range tools { s [ t ] = struct { } { } } return s }
func GetToolsForRole ( role string ) [ ] string { mu . RLock ( ) defer mu . RUnlock ( ) toolSet , ok := registry [ role ] if ! ok { slog . Warn ( "unknown role requested tools; returning nil (fail-closed)" , "role" , role ) return nil } out := make ( [ ] string , 0 , len ( toolSet ) ) for t := range toolSet { out = append ( out , t ) } return out }
func IsToolAllowed ( role , tool string ) bool { mu . RLock ( ) defer mu . RUnlock ( ) toolSet , ok := registry [ role ] if ! ok { return false } _ , allowed := toolSet [ tool ] return allowed }
func GetAllRoles ( ) [ ] string { mu . RLock ( ) defer mu . RUnlock ( ) roles := make ( [ ] string , 0 , len ( registry ) ) for r := range registry { roles = append ( roles , r ) } return roles } این یک پیادهسازی جزئی است؛ آن را در ساختار بسته و ماژول خود (مثلاً yourmodule/internal/agentperm ) ادغام کنید. نکته مهم: نقشهای ناشناخته nil برمیگردانند، به این معنی که ابزار صفر است. این پیشفرض fail-closed مانع از آن میشود که یک نقش عامل با پیکربندی نادرست یا نقش عامل تازه اضافه شده، دسترسی گسترده را به طور پنهانی به ارث ببرد. گزارش هشدار ساختار یافته، اطمینان حاصل میکند که تیمهای عملیاتی در صورت مواجهه با یک نقش ناشناخته، قابلیت مشاهده دارند. یک sync.RWMutex از رجیستری محافظت میکند تا goroutineهای همزمان بتوانند مجوزهای ابزار را با خیال راحت و بدون رقابت داده بخوانند. هر فراخوانی ابزار باید قبل از اجرا از IsToolAllowed عبور کند و هرگونه تخلف باید ثبت و مسدود شود.
الگوی ۳: دروازههای انسانی در حلقه و گردشهای کاری تأیید
رابط کاربری React پنتاگی شامل یک صفحه نمایش جریان و رابط مانیتورینگ است که به اپراتورها اجازه میدهد اقدامات عامل را در زمان واقعی مشاهده کرده و در صورت لزوم مداخله کنند. این فقط یک ویژگی رفاهی نیست. برای اقدامات برگشتناپذیر (حذف منابع، افزایش امتیازات، برقراری تماسهای شبکه خارجی)، تأیید انسان باید یک دروازه سخت باشد، نه یک بررسی اختیاری.
چالش طراحی، جلوگیری از ایجاد گلوگاه در توان عملیاتی عامل توسط این دروازهها است. گردشهای کاری تأیید ناهمزمان این مشکل را حل میکنند: عامل، اقدام پرخطر را در صف قرار میدهد، به کار روی وظایف مسدود نشده ادامه میدهد و وظیفهٔ مسدود شده را تنها پس از رسیدن تأیید از سر میگیرد.
افزودن یک دروازه تأیید به خط لوله نمایندگی
import asyncio import json import logging import os from typing import Awaitable , Callable
HIGH_RISK_TOOLS : frozenset [ str ] = frozenset ( { "execute_shell" , "run_exploit" , "delete_resource" , "escalate_privileges" , } )
_DEFAULT_TIMEOUT = int ( os . getenv ( "APPROVAL_TIMEOUT_SECONDS" , "300" ) )
async def approval_gate ( agent_id : str , tool_name : str , parameters : dict , log_approval_request : Callable [ [ str , str , dict ] , Awaitable [ str ] ] , check_approval_status : Callable [ [ str ] , Awaitable [ str ] ] , timeout_seconds : int = _DEFAULT_TIMEOUT , ) - > bool : """ Returns True if execution is approved, False if denied or timed out.
Callers must provide two async callables: log_approval_request(agent_id, tool_name, parameters) -> request_id Persist the approval request and return a unique request ID. check_approval_status(request_id) -> 'approved' | 'denied' | 'pending' Query the current decision status for a request.
Non-high-risk tools are auto-approved immediately. Timeout always returns False (fail-closed) — no exception is raised. """ if tool_name not in HIGH_RISK_TOOLS : return True
request_id = await log_approval_request ( agent_id , tool_name , parameters ) safe_params = json . dumps ( parameters ) logging . warning ( "Approval required" , extra = { "agent_id" : agent_id , "tool_name" : tool_name , "request_id" : request_id , "parameters" : safe_params , } , )
loop = asyncio . get_event_loop ( ) deadline = loop . time ( ) + timeout_seconds while loop . time ( ) < deadline : decision = await check_approval_status ( request_id ) if decision == "approved" : logging . info ( "Request approved" , extra = { "request_id" : request_id } ) return True if decision == "denied" : logging . info ( "Request denied" , extra = { "request_id" : request_id } ) return False await asyncio . sleep ( 2 )
logging . error ( "Approval request timed out — denying (fail-closed)" , extra = { "request_id" : request_id , "timeout_seconds" : timeout_seconds } , ) return False این میانافزار هرگونه فراخوانی ابزار در HIGH_RISK_TOOLS را رهگیری میکند، درخواست را با پارامترهای سریالی برای حسابرسی ثبت میکند و اجرا را تا زمان پاسخ انسان یا انقضای زمان انقضا مسدود میکند. فراخوانیهای log_approval_request و check_approval_status به عنوان پارامتر تزریق میشوند تا فراخوانندگان بتوانند backendهای پایداری و پرسوجوی خود (پایگاه داده، صف پیام، REST API و غیره) را ارائه دهند. این تابع async است، بنابراین در طول نظرسنجی به صورت مشارکتی نتیجه میدهد - در چارچوبهای عامل مبتنی بر ناهمگام، حلقه رویداد را مسدود نمیکند. زمان انقضا همیشه False را برمیگرداند و از بسته شدن واقعی دروازه اطمینان حاصل میکند: هر فراخوانندهای که if await approval_gate(...): استفاده میکند، بدون نیاز به مدیریت استثنا، به درستی اجرا را در زمان انقضا رد میکند. پیشفرض زمان انقضا از طریق متغیر محیطی APPROVAL_TIMEOUT_SECONDS برای انعطافپذیری در استقرار و آزمایش قابل تنظیم است. رویکرد نظرسنجی نشان داده شده در اینجا برای نمونهسازی اولیه مناسب است. سیستمهای تولیدی آن را با یک فراخوانی webhook یا اشتراک صف پیام جایگزین میکنند.
الگوی ۴: ثبت وقایع حسابرسی و قابلیت مشاهده برای اقدامات عامل
پنتاگی هر اعلان LLM، فراخوانی ابزار و عملکرد کانتینر را ثبت میکند. این سطح از قابلیت مشاهده ضروری است زیرا ثبت سنتی، سیستمهای عامل را در نظر نمیگیرد. رفتار یک عامل از زنجیرهای از مراحل استدلال LLM، فراخوانی ابزار و نتایج میانی پدیدار میشود. بدون ردیابی زنجیره فکری، نمیتوانید بازسازی کنید که کدام مرحله استدلال LLM باعث یک اقدام مخرب شده است.
طرح ثبت وقایع ساختاریافته برای اقدامات عامل
{ "timestamp" : "2025-01-15T14:32:01Z" , "agent_id" : "pentester-01" , "session_id" : "sess-abc123" , "tool_called" : "nmap_scan" , "parameters" : { "target" : "10.0.1.5" , "flags" : "-sV -p 1-1000" } , "result_summary" : "3 open ports detected" , "risk_score" : 0.4 , "approval_status" : "auto-approved" , "execution_time_ms" : 12340 , "container_id" : "7f3a9b2c1d4e..." } هر فیلد هدفی را دنبال میکند. session_id اقدامات را در یک کار چند مرحلهای پیوند میدهد. risk_score یک عدد اعشاری در محدوده [0.0, 1.0] است که آستانههای هشدار خودکار را فعال میکند - یک روش محاسباتی متناسب با مدل تهدید خود تعریف کنید (مثلاً بر اساس دسته ابزار، حساسیت هدف و تحلیل پارامتر) و قبل از ثبت وقایع، اعتبارسنجی کنید که مقدار در محدوده قرار میگیرد. آستانههای هشدار را بر این اساس پیکربندی کنید (مثلاً مقادیر بالای 0.7 باعث بررسی انسانی میشوند). container_id امکان همبستگی با گزارشهای سطح Docker را فراهم میکند. طرحواره را در لایه میانافزار اجرا کنید تا هیچ اقدام عاملی از ثبت ساختاریافته عبور نکند.
بدون قابلیت ردیابی زنجیره فکری، نمیتوانید بازسازی کنید که کدام مرحله استدلال LLM باعث یک اقدام مخرب شده است.
کنار هم قرار دادن همه چیز: یک چک لیست امنیتی برای عاملهای خودمختار
| الگو | تهدید کاهش یافته است | اولویت اجرا* | مرجع پنتاگی |
|---|---|---|---|
| سندباکس کردن کانتینر | سازش میزبان، حرکت جانبی | بحرانی | مجری مبتنی بر داکر با قابلیتهای از دست رفته |
| مجوزهای ابزار محدود شده | افزایش امتیاز، تزریق سریع | بحرانی | زیرعاملهای نقش-محور با مجموعه ابزارهای مجزا |
| دروازههای انسان-در-حلقه | اقدامات مخرب جبرانناپذیر | بالا | صفحه نمایش جریان با دخالت اپراتور |
| ثبت گزارش حسابرسی ساختاریافته | سوء رفتار کشف نشده، شکافهای قانونی | بالا | ثبت کامل اعلانها و اقدامات |
*بحرانی = باید قبل از هرگونه استقرار در محیط عملیاتی وجود داشته باشد. بالا = باید قبل از مدیریت دادههای حساس یا شبکههای خارجی وجود داشته باشد.
این الگوها از راهنمای OWASP LLM Top 10 (بهویژه LLM09: عاملیت بیش از حد، طبق نسخه ۲۰۲۵)، چارچوب مدیریت ریسک هوش مصنوعی NIST (بهویژه توابع Govern و Map که در NIST AI 100-1، ۲۰۲۳ ذکر شده است) و تأکید آن بر سیستمهای هوش مصنوعی قابل کنترل، و توصیههای منتشر شده توسط Anthropic برای محدود کردن استقلال عامل از طریق کنترلهای لایهای پیروی میکنند.
امنیت به عنوان یک دغدغه معماری درجه یک
سندباکسینگ، محدودهبندی مجوزها، دروازههای تأیید و ثبت گزارشهای حسابرسی، همگی تصمیمات معماری هستند که شعاع انفجار یک عامل را صرف نظر از آنچه LLM در زمان اجرا تصمیم به انجام آن دارد، محدود میکنند. پنتاگی نشان میدهد که حتی عاملی که به طور خاص برای عملیات امنیتی تهاجمی ساخته شده است، میتواند با ایجاد این الگوها از ابتدا مهار شود. با حسابرسی فایل Docker Compose عامل خود در برابر پیکربندی الگوی ۱ شروع کنید، سپس تأیید کنید که رجیستری ابزار شما پیشفرضهای fail-closed را در الگوی ۲ اعمال میکند. سوال این نیست که آیا یک عامل اقدام غیرمنتظرهای انجام خواهد داد یا خیر. سوال این است که آیا معماری، آسیب را در صورت انجام این کار محدود میکند یا خیر.





ارسال نظر