عصر ۱۰ اوت ۲۰۲۶ یک حساب گیتهاب در ۷۴ دقیقه ۲۳ pull request روی پروژههای بیربط هوش مصنوعی و ابزارهای توسعه باز کرد. هر کدام یک MCP server به اسم productivity-suite به تنظیمات پروژه اضافه میکرد. این سرور ابزار قالببندی متن و خلاصهسازی ارائه میداد و در سه فراخوانی اول واقعاً همین کار را میکرد. بعد از فراخوانی سوم، دستورهایی که به ایجنت هوش مصنوعی برمیگرداند عوض میشد: دنبال کلیدهای SSH، اطلاعات ورود AWS، تاریخچهٔ shell و تنظیمات Kubernetes بگرد و به کاربر چیزی نگو. شرکت Pillar Security جزئیات را ۱۲ اوت منتشر کرد و اسم این کارزار را Deadbugz گذاشت.
ما هر روز با ایجنتهای کدنویسی و چندین MCP server کار میکنیم، پس کار بدیهی را کردیم و تنظیمات خودمان را بررسی کردیم. قبول نشدیم. این نوشته توضیح میدهد چرا این نوع حمله با حملههای npm و PyPI که بیشتر تیمها برایشان آمادهاند فرق دارد، بررسی ما چه چیزهایی پیدا کرد، و چکلیستی که حالا داریم اجرا میکنیم.
چرا MCP server یک وابستگی از جنس دیگر است
یک کتابخانهٔ معمولی همان کاری را میکند که کدش میگوید. میشود خواندش، نسخهاش را ثابت کرد و اسکنش کرد. MCP server دو کار میکند: روی ماشین شما یا سرور کس دیگری کد اجرا میکند، و به ایجنت شما متنی میدهد که ایجنت آن را دستور حساب میکند. اسم ابزارها، توضیح ابزارها و قالبهای prompt همه از سرور میآیند و مدل آنها را همانطور میخواند که درخواست شما را.
Deadbugz از همین کانال دوم سوءاستفاده کرد. طبق گزارش Pillar، سرور برای هر کلاینت یک شمارنده نگه میداشت. وقتی کلاینت سه درخواست tools/call میفرستاد، پاسخهای بعدی tools/list و prompts/get دستورهای جدید را با خود میآوردند. ابزار تازهای ظاهر نمیشد و موقع نصب هیچ چیز مشکوکی در فهرست ابزارها دیده نمیشد. کسی که یک دقیقه سرور را امتحان میکرد فقط یک ابزار بیخطر قالببندی متن میدید. محموله از راه metadataای میرسید که ایجنت از قبل به آن اعتماد داشت.
توصیهٔ Pillar به سازندگان کلاینتهای MCP ارزش تکرار دارد: اگر تعریف ابزارهای سروری که قبلاً تأیید کردهاید عوض شد، این را یک رخداد امنیتی بدانید و دوباره تأیید بگیرید. بیشتر کلاینتهای امروز این کار را نمیکنند. یک بار سرور را تأیید میکنید و هر چه بعداً بگوید مستقیم وارد context مدل میشود.
بقیه چقدر در معرض خطرند؟
مشکل فقط روی لپتاپ برنامهنویسها نیست. Censys در ۲۸ آوریل ۲۰۲۶ تعداد ۱۲٬۵۲۰ سرویس MCP در دسترس از اینترنت شمرد که روی ۸٬۷۵۸ آدرس IP پخش بودند، و تا ۶ مه این عدد از ۲۱٬۰۰۰ گذشت. سرورهای گزارش آنها بدون احراز هویت در دسترس بودند. بزرگترین گروهها ابزارهای داده و دانش (۱٬۷۷۶ مورد، که خیلیهایشان مستقیم به پایگاه داده کوئری میزنند) و ابزارهای زیرساخت (۱٬۵۴۹ مورد) بودند. Censys ابزارها را فراخوانی نکرد، پس این اعداد میزان در معرض بودن را نشان میدهند، نه نفوذ تأییدشده را.
فروشندهها هم واکنش نشان دادهاند. Cloudflare در ۱۴ اوت تشخیص ترافیک MCP را به Gateway خود اضافه کرد که بر اساس هدر MCP-Protocol-Version کار میکند، تا یک سازمان دستکم ببیند کدام ماشینها MCP صحبت میکنند و اتصالهای مستقیمی را که از پورتال تأییدشده رد نمیشوند ببندد. صفحهٔ بهترین شیوههای امنیتی خود پروتکل دربارهٔ سرورهای محلی صریح است: این سرورها با همان سطح دسترسی کلاینت اجرا میشوند، و کلاینتی که نصب یککلیکی دارد باید قبل از اجرا دستور کامل را بدون کوتاهسازی نشان دهد. همان صفحه توصیه میکند سرورها در sandbox و با کمترین دسترسی پیشفرض به فایلسیستم و شبکه اجرا شوند.
دید شبکهای به تیم امنیت کمک میکند، ولی به سؤالی که برنامهنویس اول باید بپرسد جواب نمیدهد: دقیقاً چه نصب کردهام و به چه چیزهایی دسترسی دارد؟
در تنظیمات خودمان چه پیدا کردیم
روی میزبان توسعهٔ ما Claude Code با هفت MCP server سراسری و دو سرور دیگر محدود به پروژههای خاص اجرا میشود. در نوشتهٔ گردش کار RPI توضیح دادیم کار را چطور بین ایجنتها تقسیم میکنیم؛ این بررسی دربارهٔ لولهکشی زیر همان گردش کار بود. چهار یافته مهم بود.
سه سرور نسخهٔ ثابت نداشتند. یکی با npx -y و اسم خالی بسته اجرا میشد، یکی با @latest، و یکی مستقیم از شاخهٔ پیشفرض یک مخزن گیت از طریق uvx. هر سه در شروع هر نشست جدیدترین نسخه را دانلود و اجرا میکنند. برای اینکه تغییری شبیه Deadbugz به ما برسد لازم نبود کسی به ما pull request بدهد. کافی بود بستهٔ بالادستی عوض شود، مثلاً با حساب نگهدارندهٔ هکشده مثل حملهٔ فیشینگ npm در سپتامبر ۲۰۲۵، یا با نگهدارندهای که نظرش عوض شده.
چهار سرور endpoint راه دور HTTP بودند. تعریف ابزارهایشان روی سرور کس دیگری است و هر لحظه ممکن است بدون هیچ بهروزرسانی در سمت ما عوض شود. ثابت کردن نسخه اینجا کمکی نمیکند. تنها دفاع این است که تغییر تعریفها را متوجه شویم، و ما هیچ راهی برای متوجه شدن نداشتیم.
بزرگترین دامنهٔ آسیب shell نبود. سرور خودکارسازی مرورگر ما از طریق Chrome DevTools Protocol به یک پروفایل مرورگر همیشهروشن وصل است که در چند حساب کاری ما وارد مانده. هر چیزی که بتواند این سرور را هدایت کند میتواند در همهٔ آنها به جای ما عمل کند. ما به کلیدهای SSH فکر میکردیم، ولی نشست مرورگر هدف باارزشتری بود.
قبلاً از تداخل اسم ابزارها ضربه خورده بودیم. اوایل همین ماه دو MCP server مربوط به Playwright همزمان فعال بودند و اسم ابزارهایشان همپوشانی داشت؛ یکی به همان مرورگر مشترک وصل بود و دیگری Chromium جداگانهٔ خودش را در sandbox بالا میآورد. ایجنت مدام سرور اشتباه را انتخاب میکرد و ما مدت زیادی دیباگ کردیم به خیال اینکه مرورگر از کار افتاده. اتفاق مخربی نیفتاد، ولی نشان داد مدل ابزار را بر اساس اسم و توضیح انتخاب میکند و کلاینت هیچ هشداری نداد که دو سرور مدعی یک اسم هستند. یک سرور مخرب میتواند همین کار را عمداً بکند.
چکلیست عملی بررسی MCP
این چکلیستی است که حالا روی هر ماشینی که ایجنتش MCP server دارد اجرا میکنیم. تنظیمات خود ما در اولین بررسی در مورد ۲ و ۳ رد شد.
- همه چیز را فهرست کنید. تنظیمات سراسری، فایلهای تنظیمات هر پروژه، سرورهایی که پلاگینها اضافه میکنند، و هر چیزی که همتیمیها در pull request اضافه کردهاند. دستور و آرگومانهای کامل هر کدام را ببینید. اگر نمیدانید سروری چرا آنجاست، حذفش کنید.
- نسخهٔ هر سرور محلی را ثابت کنید. برای بستههای npm شمارهٔ نسخهٔ دقیق (مثلاً
1.4.2، هرگز@latest) و برای منابع گیت هش commit. بهروزرسانی را آگاهانه و بعد از خواندن changelog انجام دهید. - از تعریف ابزارها snapshot بگیرید. خروجی
tools/listوprompts/listهر سرور را ذخیره کنید و بهطور منظم مقایسه کنید، از جمله بعد از چند فراخوانی در یک نشست، چون Deadbugz فقط بعد از فراخوانی سوم تغییر میکرد. هر تفاوت در توضیح ابزار را یک آدم باید بخواند. - سرورهای راه دور را شخص ثالث حساب کنید. فقط به سرورهایی وصل شوید که فروشندهشان کسی است که همین داده را مستقیم هم به او میدادید، و ببینید توکنی که میگیرند واقعاً چه دسترسیهایی دارد.
- رازها را دور از دسترس نگه دارید. ایجنت را با کاربری اجرا کنید که به
~/.ssh، فایلهای اطلاعات ورود ابری و kubeconfigهای پروداکشن دسترسی نداشته باشد. اگر ایجنت مرورگر واردشده لازم دارد، یک پروفایل جدا فقط با حسابهای لازم برای همان کار به آن بدهید. - سرورها را به پروژه محدود کنید. سرور پایگاه دادهای که فقط یک پروژه لازم دارد نباید در همهٔ نشستهای آن ماشین بارگذاری شود.
- هر جا ممکن است ترافیک خروجی را محدود کنید. یک proxy خروجی با فهرست مجاز، نشت بیصدا را به یک درخواست مسدودشده تبدیل میکند که در لاگ دیده میشود.
- شاخصهای منتشرشده را چک کنید. Pillar آدرس
productivity-suite-mcp.onrender.comو یک فایل محلی مخفی در~/.config/.cache/.sys/.deadbug-mcp.pyرا اعلام کرده. یکgrepروی فایلهای تنظیمات MCP و یکfindبرای آن مسیر چند ثانیه وقت میگیرد.
برای دور اول، یک خط اجراهای بدون نسخهٔ ثابت را در تنظیمات Claude Code پیدا میکند: grep -nE '@latest|"npx"|git\+https' ~/.claude.json .mcp.json. چند مورد بیخطر را هم نشان میدهد، که اشکالی ندارد؛ هدف این است که تکتکشان را نگاه کنید.
همین قاعده برای قابلیتهای هوش مصنوعی که خودتان میسازید
Deadbugz داستان زنجیرهٔ تأمین است، ولی درس زیرش قدیمیتر است: هر چیزی که وارد context مدل شود میتواند مثل دستور عمل کند، پس مدل هرگز نباید قدرتی بیشتر از آدمی که برایش کار میکند داشته باشد. به همین دلیل دستیارهای داخلی را طوری طراحی میکنیم که بخوانند و ارجاع بدهند، نه اینکه اقدام کنند، و کنترل دسترسی را در لایهٔ بازیابی میگذاریم نه در prompt. بخش دسترسی را در محدود کردن دستیار هوش مصنوعی داخلی به همان کسی که میپرسد و بخش تأیید را در حاکمیت هوش مصنوعی ایجنتی در helpdesk نوشتهایم.
در FanMind، دستیار اسناد ما، همهٔ تماسهای خروجی از یک تونل با فهرست مجاز رد میشوند، جستوجوی وب به دامنههایی که ادمین تأیید کرده محدود است، و اسناد محرمانه بهطور پیشفرض از نمایهسازی هوش مصنوعی کنار گذاشته میشوند. هیچکدام prompt injection را غیرممکن نمیکند. فقط محدود میکند که یک تزریق موفق به چه چیزهایی برسد، و بعد از بررسیای مثل بررسی ما، همین مهمترین سؤال است.
اگر این هفته فقط یک کار میکنید، فایل تنظیمات MCP خود را باز کنید و تکتک دستورهایش را بخوانید. بررسی ما چهار مشکل پیدا کرد که به فکرمان نرسیده بود.