تصور کنید کلید خانه شما در دست کسی باشد که هر لحظه میتواند وارد شود، اما شما تا ۲۴ ساعت متوجه این نشت نشوید. این دقیقاً همان وضعیتی است که اکثر توسعهدهندگان با اعتبارنامههای عاملهای هوش مصنوعی خود تجربه میکنند.
در حال حاضر، ۲۴ ساعت بازهٔ پیشفرض برای مهاجمی است که به یک توکن نشتکرده دست یافته و دسترسی کامل به API را به دست آورده است. این آسیبپذیری به این دلیل رخ میدهد که اکثر سیستمهای شناسایی، توکنهای ماشین-به-ماشین (M2M) — شبیه به یک کارت تردد دائمی برای کارکنان شرکت که تاریخ انقضای ندارد — را مانند رمزهای عبور انسانی میبینند. این سیستمها فراموش میکنند که کلیدهای ماشین بهراحتی از طریق فایلهای Log، تیکتهای پشتیبانی یا کپی کردن متغیرهای محیطی (Environment Variables) از حافظه خارج میشوند. از آنجایی که هیچکس انتظار ندارد یک انسان هر چند دقیقه یک بار رمز عبور را تایپ کند، سیستمهای شناسایی برای اعتبارنامههایی که با این سرعت منقضی شوند، ساخته نشدهاند.
همانطور که در تحلیلهای قبلی ما دربارهی امنیت مدلهای بازمتن اشاره کردیم، مدیریت هویت در سیستمهای خودکار همواره نقطه ضعف بوده است. به گزارش VentureBeat در سپتامبر ۲۰۲۶، عاملهای هوش مصنوعی با استفاده از اعتبارنامههای افشا شده، به ۳۹۵ سازمان نفوذ کردند. این شکست سیستماتیک در مورد مشابهی در Hugging Face نیز مشاهده شد؛ جایی که یک عامل، اعتبارنامهای در اختیار داشت که حتی پس از اتمام وظیفه خاصی که برای آن صادر شده بود، همچنان معتبر باقی مانده بود. مشکل اصلی در شکاف مرزهای اعتماد است؛ اکثر عاملهای هوش مصنوعی در لحظه شروع (Start-up) یک توکن دسترسی M2M دریافت میکنند و آن را برای تمام طول عمر فرآیند (Process) نگه میدارند. اگر این توکن در یک فایل Log قرار بگیرد، تا زمانی که صادرکننده آن تعیین کرده است معتبر میماند—که برای اکثر ارائهدهندگان هویت، بین یک ساعت تا یک روز است.
برای اثبات راهکار رفع این مشکل، یک ساختار فنی با استفاده از Kinde (یک ارائهدهنده هویت که توکنهای دسترسی M2M صادر کرده و هر فراخوانی را بر اساس آنها تأیید میکند) طراحی شد. در این آزمایش، دو پیکربندی مقایسه شدند: یک عامل با توکن استاتیک با طول عمر ۲۴ ساعت و عاملی با توکن چرخان با طول عمر ۱۲۰ ثانیه. هر دو عامل به یک API مبتنی بر Convex متصل شدند که امضاها را از طریق JSON Web Key Sets (JWKS) تأیید میکرد. این رویکرد در راستای بهینهسازی زیرساختهای مدیریت عاملهاست، مشابه آنچه در تجربه Solo.io برای کاهش زمان استقرار Agent Gateway مشاهده شد تا پیچیدگیهای عملیاتی کاهش یابد.
مکانیسم نشت
یک اعتبارنامه M2M در Kinde از دو بخش تشکیل شده است: Client ID و Client Secret. وقتی این دو به نقطه انتهایی (Endpoint) توکن Kinde از طریق یک grant از نوع client_credentials ارسال میشوند، Kinde یک توکن دسترسی امضا شده صادر میکند. این جریان استاندارد OAuth برای تماسهای سرویس-به-سرویس است که در آن هیچ انسان یا مرورگری دخالت ندارد. نکته مهم این است که خودِ این grant تصمیم نمیگیرد توکن چه زمانی منقضی شود؛ بلکه این موضوع توسط تنظیمات اپلیکیشن در داشبورد Kinde تعیین میشود.
آسیبپذیری در نحوه مدیریت توکن توسط کد عامل پس از دریافت نهفته است:
- عاملهای استاتیک: این عاملها یک توکن را در هنگام شروع فرآیند دریافت میکنند، آن را در حافظه ذخیره میکنند و برای هر فراخوانی تا زمان ریاستارت شدن فرآیند، از همان استفاده میکنند. اگر فرآیند برای ساعتها یا روزها اجرا شود، توکن معتبر میماند. اگر کسی در این بازه توکن را کپی کند، در واقع یک کلید فعال در دست دارد.
- عاملهای چرخان: این عاملها با توکن به عنوان داراییای با تاریخ انقضای کوتاه برخورد میکنند. آنها قبل از هر فراخوانی، سن توکن را بررسی میکنند. پیش از آنکه توکن به زمان انقضا نزدیک شود، عامل آن را دور ریخته و توکن جدیدی از Kinde درخواست میکند. در این حالت، یک کپی از این توکن ظرف چند دقیقه بیاثر میشود.


لایهٔ اجرا و تأیید
API مورد استفاده در این پروژه، یک تابع Convex است که توکن Bearer را از درخواست میخواند و بدون هیچ منطق شرطی بر اساس نوع عامل، بررسی را انجام میدهد. فرآیند دقیقاً به این ترتیب است:
۱. عامل توکن را با استفاده از grant client_credentials از Kinde درخواست میکند.
۲. Kinde یک access_token با انقضای ۲۴ ساعت یا ۱۲۰ ثانیه برمیگرداند.
۳. عامل درخواست GET /api/records?action=... را ارسال میکند و توکن را به عنوان Bearer Token قرار میدهد.
۴. API امضا را از طریق JWKS تأیید میکند.
۵. API در صورت صحت، پاسخ 200 OK را به همراه دادهها برمیگرداند، یا در صورت انقضا یا نامعتبر بودن توکن، خطای 401 صادر میکند.
برای پیادهسازی این مورد، API از تابع jwtVerify در کتابخانه jose استفاده میکند. این تابع امضا را با مجموعه کلیدهای عمومی Kinde چک کرده و ادعای exp (تاریخ انقضا) را تأیید میکند. همچنین کد تضمین میکند که توکن برای یک کلاینت عامل شناختهشده صادر شده باشد؛ این کار با بررسی ادعای azp (طرف مجاز) در Payload انجام میشود.
به طور مشخص، کد از requiredEnv("KINDE_ISSUER") و requiredEnv("KINDE_M2M_AUDIENCE") برای اعتبارسنجی منشأ توکن و مخاطب مورد نظر استفاده میکند. اگر امضا اشتباه باشد یا زمان exp گذشته باشد، کتابخانه بلافاصله خطا میدهد. این بررسی تکمرحلهای است که باعث میشود انقضای تنظیم شده در Kinde به یک رد درخواست واقعی تبدیل شود. این تابع هیچ اطلاعی از اینکه کدام عامل درخواست را ارسال کرده ندارد و با تمام توکنها یکسان برخورد میکند.
اثبات مفهوم (PoC)
در این آزمایش، توکنهای هر دو عامل در یک لحظه دقیق شکار شدند تا سناریوی یک اسکرپرِ Log یا اسکرینشات از تیکتهای پشتیبانی شبیهسازی شود. سپس اسکریپت منتظر ماند تا پنجره ۱۲۰ ثانیهای عامل چرخان بسته شود و سپس هر دو توکن را مستقیماً روی API تست کرد (بدون استفاده از کد خود عاملها).
- نتیجه عامل استاتیک: توکن که برای مقدار پیشفرض ۸۶,۴۰۰ ثانیه (۲۴ ساعت) تنظیم شده بود، با موفقیت تأیید شد (پاسخ 200 OK) و تأخیر (Latency) آن ۱۳۵۳ میلیثانیه بود. این توکن تا پایان عمر ۲۴ ساعته خود به کار خود ادامه میدهد، زیرا تأیید JWT در Kinde فقط امضا و انقضا را چک میکند و نمیتواند تشخیص دهد که توکن یک کپی است.
- نتیجه عامل چرخان: توکن که برای ۱۲۰ ثانیه تنظیم شده بود، با خطای 401 Unauthorized و تأخیر ۹۳۸ میلیثانیه رد شد. مهاجم حداکثر دو دقیقه فرصت داشت تا از توکن شکار شده استفاده کند، پیش از آنکه بیفایده شود.

جزئیات پیادهسازی
تنها تفاوت بین دو عامل در داشبورد Kinde بود و نه در کد API. عامل استاتیک انقضای پیشفرض ۸۶,۴۰۰ ثانیه را حفظ کرد، در حالی که عامل چرخان روی ۱۲۰ ثانیه تنظیم شد. تغییر این یک عدد، بدون نیاز به استقرار مجدد (Redeploy) API، زمانبندی رد درخواستها را تغییر داد.
مدیریت اعتبارنامهها توسط دو مدیر (Manager) متفاوت انجام شد:
- مدیریت استاتیک: این تابع بررسی میکند که آیا
staticTokenدر حافظه وجود دارد یا خیر. اگر وجود داشت، آن را برمیگرداند. در غیر این صورت، با استفاده ازSTATIC_AGENT_CLIENT_IDوSTATIC_AGENT_CLIENT_SECRETیک توکن M2M جدید گرفته و آن را برای همیشه کش میکند. - مدیریت چرخان: این تابع یک حاشیه امن برای چرخش به نام
ROTATION_SAFETY_MARGIN_MSبا مقدار ۱۵,۰۰۰ (۱۵ ثانیه) تعریف میکند. قبل از هر استفاده، مقدارDate.now()را با مقدارexpiresAtتوکن مقایسه میکند. اگر زمان فعلی در فاصله ۱۵ ثانیهای از انقضا باشد، توکن تازهای از Kinde میگیرد.
برای اینکه دمو بر روی طول عمر توکن متمرکز بماند و نه دامنه دسترسی (Authorization Scope)، از یک رجیستری اکشن بسته استفاده شد. این رجیستری هر دو عامل را تنها به سه فراخوانی محدود میکرد:
list_recordsread_recordexport_records
هر اکشن دیگری پیش از آنکه توکن حتی بررسی شود، توسط API رد میشد. این کار تضمین کرد که تست دقیقاً روی طول عمر توکن متمرکز باشد.
سختسازی و محدودیتها
در طول بررسی کد تأیید API، یک باگ کشف شد. وقتی درخواستی بدون توکن یا با توکنی ناشناخته ارسال میشد، کد لاگگذاری به طور پیشفرض ورودی را در حالت mode: "static" قرار میداد. این یعنی درخواستهای ناشناس یا بدشکل طوری به نظر میرسیدند که انگار توسط عامل استاتیک ارسال شدهاند. این مشکل با معرفی مقدار mode: "unknown" برای درخواستهای بدون انتساب اصلاح شد تا یکپارچگی دادههای اثبات حفظ شود.
چند تمایز فنی مهم در مورد این ساختار وجود دارد که باید به آنها اشاره کرد:
- چرخش توکن در برابر چرخش Secret: این پروژه توکن دسترسی (Access Token) را میچرخاند که در هر درخواست
client_credentialsبه صورت تازه صادر میشود. این لایه حیاتی برای سناریوهای نشت توکن است. چرخش Client Secret یک اقدام دستی و مجزا است که از طریق داشبورد Kinde یا Management API انجام میشود و نباید این دو با هم اشتباه شوند. - پنجرههای تولیدی: بازه ۱۲۰ ثانیهای برای سرعت بخشیدن به اثبات مفهوم انتخاب شد. در محیطهای عملیاتی (Production)، بازه ۵ تا ۱۵ دقیقه رایجتر است تا تعادلی بین امنیت و سربارِ فراخوانیهای مکرر Refresh ایجاد شود.
- جزئیات خطاها: API برای تمام شکستها یک خطای کلی 401 برمیگرداند. اگرچه برای یک دمو کافی است، اما در یک سیستم حسابرسی (Audit Trail) واقعی، باید بین توکن منقضی شده و توکن صادر شده از یک اپلیکیشن ناشناخته تفاوت قائل شد.
این تغییر در رویکرد، امنیت هوش مصنوعی را از عادت خطرناک اعتماد به متغیرهای محیطی طولانیمدت دور میکند. توسعهدهندگان در Hacker News این سؤال را مطرح کردند که آیا اصلاً باید به عاملها کلید API داد یا خیر؛ نتیجه کلی این بود که عاملها باید اعتبارنامههای موقت و با دامنه محدود (Narrowly Scoped) دریافت کنند که از طریق سیستمی صادر شده باشد که هر درخواست را لاگ میکند، نه اینکه یک کلید طولانیمدت در یک متغیر محیطی قرار بگیرد. این بحثها در کنار چالشهای دیگر، مانند تأثیر نشانگذاری متنی بر کاهش دقت فراخوانی ابزارها، نشان میدهد که امنیت و کارایی عاملها نیازمند بازنگری در لایههای مختلف است.
معنای این موضوع برای توسعهدهندگان، تغییر در فرض بنیادی هویت عامل است. شما دیگر نباید بپرسید «آیا توکن میتواند دزدیده شود؟»، بلکه باید بپرسید «یک توکن دزدیده شده تا چه زمانی یک تهدید (Liability) باقی میماند؟». ابزار لازم برای اعتبارنامههای کوتاهمدت در اکثر ارائهدهندگان هویت وجود دارد؛ تکه گمشده، منطق سمت کلاینت برای احترام به زمان انقضا است. برای ایمن کردن عاملهای خود، تنظیمات انقضای توکن M2M را بررسی کنید و یک مدیر اعتبارنامه پیاده کنید که توکنها را پیش از انقضا رفرش کند.
گام بعدی شما
- تنظیمات انقضای توکنهای M2M را در ارائهدهنده هویت خود بررسی کنید و آنها را به حداقل زمان ممکن برسانید.
- یک Credential Manager در سمت کلاینت پیاده کنید که توکنها را پیش از انقضا رفرش کند.
- دسترسیهای عاملها را از کلیدهای کلی به توکنهای با دامنه محدود (Scoped Tokens) تغییر دهید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو