تأمين وكيل ذكاء اصطناعي يعمل على مدار الساعة في المنزل: رحلة عبر طرق مسدودة
TL;DR
أُشغّل وكيل ذكاء اصطناعي يعمل على مدار الساعة وله صلاحية الوصول إلى الـ shell على جهاز mini PC احتياطي في المنزل، والجزء الصعب لم يكن بناءه، بل التأكد من أن أي اختراق لن ينتشر. تطويق الوكيل بجدار حماية في مكانه فشل: فمهمته بأكملها هي إجراء اتصالات صادرة (outbound)، لذا فإن تصفية الـ egress إما تُعطّله أو تتحول إلى قائمة سماح (allowlist) عليك مراقبتها باستمرار. ما نجح فعلاً هو نقل الجهاز إلى موجّه (router) خاص به، بمعزل تام عن شبكتي المنزلية المحلية (LAN)، بحيث يستطيع أي اختراق كامل الوصول إلى الإنترنت لكن ليس إلى أجهزة الكمبيوتر المحمولة أو الـ NAS الخاصين بي. الوصول عن بُعد يتم عبر نفق ngrok إلى SSH يعتمد على المفاتيح فقط (key-only)؛ والباقي هو دفاع متعدد الطبقات (defense-in-depth) على الجهاز نفسه، إضافة إلى قائمة صادقة بما لا يحميه أي من هذا كله.
كيف قمتُ بتأمين Hermes Agent، وهو مساعد ذكاء اصطناعي يعمل على مدار الساعة عبر واجهة سطر الأوامر (CLI) من Nous Research، ويعمل على جهاز mini PC احتياطي في المنزل. هذا ليس منشوراً من نوع "إليكم الإعداد المثالي". إنه السجل الصادق لثلاث محاولات فشلت ومحاولة واحدة نجحت.
الهدف
أردتُ وكيل ذكاء اصطناعي يعمل على مدار الساعة (24/7) في منزلي، بحيث أستطيع الوصول إليه من أي مكان: من هاتفي، من حاسوب محمول على شبكة شخص آخر، من غرفة فندق أثناء السفر. يستطيع Hermes تشغيل أوامر shell، وقراءة الملفات وكتابتها، وتصفح الويب، واستدعاء واجهات برمجة تطبيقات (APIs) خارجية. هذا ما يجعله مفيداً. وهو أيضاً ما يجعله خطيراً. عملية تعمل على مدار الساعة ولها صلاحية وصول إلى الـ shell، وتقبع داخل شبكتك المنزلية، أمر خطير جداً أن تُخطئ فيه.
فتحوّل المشروع إلى: كيف أُشغّل هذا الشيء بحيث (أ) أستطيع الوصول إليه عن بُعد، (ب) لا يستطيع الوصول إلى بقية شبكتي المنزلية، و(ج) إذا تم اختراقه هو أو الجهاز الذي يعمل عليه في أي وقت، تكون دائرة الضرر (blast radius) أصغر ما يمكن أن أجعلها؟
الجهاز المضيف هو Dell OptiPlex 9020M يعمل بنظام Linux: جهاز mini PC رخيص، منخفض استهلاك الطاقة، شبه خالٍ من المروحة. قمتُ بتثبيت النسخة الرسمية الأخيرة (stock) من Hermes في منتصف يونيو 2026.
هناك شيء واحد سأتجاوزه هنا: لماذا Hermes، وليس أحد الوكلاء الأخرى ذاتية الاستضافة (self-hosted). كان ذلك قراراً قائماً بذاته، يتعلق بشكل أساسي بوضعية الأمان وبكون الوكيل صادراً عن مختبر مستقل بدلاً من مزوّد من الصف الأول (frontier vendor). لقد ناقشتُ تلك المقارنة في منشور منفصل، Hermes vs. OpenClaw. يبدأ هذا المنشور من حيث انتهى ذلك: الوكيل تم اختياره وتثبيته، والآن عليّ أن أُشغّله دون أن يتحول إلى أضعف نقطة في شبكتي.
المحاولة الأولى: تحصينه في مكانه، على الشبكة المنزلية المحلية
كان ردّ فعلي الأول هو الحل المتوقع من الكتب: إبقاء الجهاز على شبكتي المنزلية وتحصينه بشكل صارم. قواعد جدار حماية عدوانية، تصفية egress صارمة، خدمات محدودة، كل شيء. تحصين الجهاز إلى أن يصبح آمناً للتعايش مع كل شيء آخر.
فشل هذا، وفشل بطريقة مفيدة. كان التحصين مقيّداً لدرجة أن الوكيل لم يعد قادراً على أداء مهمته. أبسط قدرة، وهي الوصول إلى الويب، تعطّلت. حركة المرور الصادرة التي يحتاجها الوكيل (استدعاءات API لمزوّدي النماذج، البحث على الويب، جلب الصفحات) وقعت في نفس الشبكة التي نصبتُها لإبقاء الحركة السيئة في الخارج. فبدأتُ بفتح ثغرات. كل ثغرة كانت تبدو وكأنها تُلغي الأمان الذي أضفته للتو. كنتُ ألاحق هدفاً متحركاً: كل أداة جديدة يكتسبها الوكيل كانت تحتاج وجهة صادرة جديدة، وكنتُ أُحافظ يدوياً على قائمة سماح (allowlist) ضيقة جداً بحيث تكون غير عملية، ومليئة بالثغرات في الوقت نفسه بحيث لا تمنحني شعوراً بالأمان.
كانت هناك مشكلة ثانية، مستقلة عن الأولى. لم يبقَ التحصين عند مستوى نظام التشغيل. فرضه بشكل صحيح كان يعني تعديلات واسعة على الكود المصدري لـ Hermes نفسه، وهذا جعل عمليات الترقية هشة. Hermes قيد التطوير النشط ويصدر تحديثات متكررة، وكل تحديث كان يمحو تعديلاتي (patches) ويجبرني على إعادة تطبيق كل تخصيص يدوياً. كنتُ فعلياً أُحافظ على نسخة خاصة (fork) من الوكيل فقط لإبقاء قواعدي الأمنية قائمة، وتلك القواعد كانت أصلاً تُثبت أنها هشة جداً لأداء المهمة.
درسان، كلاهما بديهي بأثر رجعي. الوكيل الذي تكمن قيمته بأكملها في اتخاذ إجراءات في العالم يتعارض جوهرياً مع تصفية egress. لا يمكنك فعلياً أن تقول "امنع كل شيء صادر" لعملية مهمتها بأكملها هي إجراء اتصالات صادرة؛ إما أن تُعطّلها أو تُحافظ على قائمة سماح هشة تتأخر دائماً عن الواقع. والتحصين الذي يُفرض عبر تعديل الكود المصدري للوكيل نفسه هو فخ، لأنه يضع أمانك في مواجهة مباشرة مع وتيرة إصدارات المشروع.
بدلاً من الاستمرار في خوض تلك المعركة، غيّرت البنية الطوبولوجية (topology) للشبكة.
المحاولة الثانية: نقل الجهاز خارج الشبكة المنزلية
فتوقفتُ عن محاولة جعل الوكيل آمناً داخل شبكتي، ونقلته إلى خارجها بدلاً من ذلك.
الإنترنت المنزلي لدي يدخل عبر موجّه مزوّد خدمة الإنترنت (ISP router). جهاز OptiPlex متصل مباشرة بذلك الموجّه ولم يلمس شبكتي المنزلية المحلية إطلاقاً. في المرحلة التالية (downstream)، وضعتُ موجّهاً ثانياً يُدير الشبكة المنزلية المحلية، وكل ما يهمني فعلياً (الحواسيب المحمولة، الهواتف، الـ NAS) يعيش خلفه، مفصولاً عن OptiPlex. جهاز OptiPlex موجود على الشبكة الفرعية (subnet) الخاصة بموجّه مزوّد الخدمة، 192.168.2.x؛ بينما الشبكة المنزلية المحلية على شبكتها الفرعية الخاصة، 192.168.100.x.
النتيجة: جهاز الوكيل موجود على جانب الإنترنت من حدود الموجّه، بينما شبكتي المنزلية خلف موجّهها الخاص، معزولة عنه. لا يملك OptiPlex أي مسار (route) إلى الشبكة المنزلية المحلية. حتى لو تم اختراق الوكيل أو الجهاز بالكامل، فإن المهاجم يصل إلى شبكة فرعية تستطيع الوصول إلى الإنترنت الأوسع لكنها لا تستطيع الوصول إلى أجهزتي الشخصية. دائرة الضرر الناتجة عن "اختراق جهاز الوكيل" تنهار من "شبكتي المنزلية بأكملها" إلى "جهاز واحد معزول ومفاتيح API الخاصة به".
┌──────────────────────────────────────┐
Internet ───► │ ISP router │
└───────────────┬──────────────────────┘
│
┌───────────────┴──────────────────────┐
│ │
┌─────────▼──────────┐ ┌────────────▼──────────────┐
│ Second router │ │ OptiPlex (Hermes agent) │
│ (home LAN gateway)│ │ 192.168.2.66 │
└─────────┬──────────┘ │ no route to home LAN │
│ └───────────────────────────┘
┌─────────▼───────────┐
│ Home LAN │
│ 192.168.100.x │
│ (laptops, phones, │
│ NAS, etc.) │
└─────────────────────┘
كان هذا أكبر مكسب أمني في المشروع بأكمله، وكلّف صفر برمجيات. تقسيم الشبكة (network segmentation) تفوّق على أي قاعدة جدار حماية كنت لأكتبها. كما حلّ المشكلتين من المحاولة الأولى دفعة واحدة. يستطيع الوكيل الوصول إلى الإنترنت بحرية، لأن ذلك أصبح مقبولاً الآن: الشيء الذي كنتُ قلقاً من وصوله إليه، أي شبكتي المنزلية، يقع على الجانب الآخر من موجّه لا يستطيع تجاوزه. ولأن العزل يأتي من الشبكة وليس من تعديلات على كود الوكيل، استطعتُ تشغيل النسخة الرسمية (stock) من Hermes مجدداً. لا نسخة خاصة (fork)، ولا تعديلات (patches) يجب إعادة تطبيقها مع كل تحديث.
ملاحظة حول اختيار البنية الطوبولوجية. ما يهم في نموذج الأمان هو حدود الموجّه بين جهاز الوكيل والشبكة المنزلية المحلية، وفي إعدادي هذه الحدود هي جدار حماية WAN الخاص بالموجّه الثاني. كان بإمكاني الحصول على حدود مماثلة دون موجّه ثانٍ، بوضع OptiPlex على VLAN خاص به أو شبكة فرعية منفصلة على موجّه مزوّد الخدمة مع قاعدة جدار حماية بين المناطق (inter-zone) تمنع حركة المرور بين القطاعين. موجّه مزوّد خدمتي قابل للتهيئة بالكامل ويدعم هذا؛ والكثير من الموجّهات شبه الاحترافية (prosumer) والموجّهات من الفئة التجارية تدعمه أيضاً. سيكون العزل متكافئاً في نموذج التهديد الأكثر أهمية (جهاز وكيل مخترق يحاول الوصول إلى أجهزة الشبكة المنزلية): كلا النهجين يضع حدود جدار حماية لا تستطيع حركة مرور الوكيل تجاوزها.
اخترتُ نهج الموجّهين لسبب واحد: العزل بنيوي (structural) وليس معتمداً على التهيئة. مع موجّهين ماديين، لا يوجد وسم VLAN، ولا قاعدة جدار حماية بين المناطق، ولا تخصيص منفذ سويتش (switch) يمكن أن يُهيَّأ بشكل خاطئ عن طريق الخطأ أو يُستبدل بواسطة تحديث firmware ليفتح مساراً صامتاً بين القطاعين. الحدود موجودة بسبب مكان توصيل الكابلات. هذه حجة أضعف مما تبدو عليه (VLAN مُهيَّأ بشكل صحيح على موجّه محافَظ عليه جيداً جدير بالثقة تماماً)، لكنني أحببتُ أن العزل ينجو من أخطاء التهيئة، وتغييرات الـ firmware، ونسياني الشخصي. لو لم يكن لدي أصلاً الموجّه الثاني، أو كنتُ أُعِدّ هذا في مكان به موجّه واحد فقط ولا رغبة لدي في عتاد إضافي، لكان نهج VLAN بموجّه واحد معقولاً تماماً ولم أكن لأتردد في استخدامه.
تحفّظ صادق واحد على ادّعاء "لا مسار إلى الشبكة المنزلية المحلية": الحدود نفسها هي جهاز، وذلك الجهاز يقع في متناول الجهاز الذي أتعامل معه على أنه مخترق. يشترك OptiPlex في الشبكة الفرعية لموجّه مزوّد الخدمة مع جانب WAN للموجّه الثاني، لذا فإن OptiPlex المخترق لا يستطيع التوجيه عبر الموجّه الثاني، لكنه يستطيع مهاجمة الموجّه مباشرة، وإذا نجح في الدخول سيكون قد تجاوز الحدود. أغلقتُ ذلك المسار قدر استطاعتي. واجهة الإدارة للموجّه الثاني معطّلة من جانب WAN ومحمية بكلمة مرور قوية، لذا من الشبكة الفرعية التي يعيش عليها الوكيل لا توجد أي واجهة إدارة يمكن الوصول إليها إطلاقاً. المسار إلى الشبكة المنزلية المحلية غير موجود، والجهاز الوحيد الذي يمكنه إنشاء مثل هذا المسار غير قابل للإدارة من حيث يقع الوكيل.
لكن هذا خلق مشكلة جديدة. إذا كان الجهاز بعيداً في شبكته الفرعية الصغيرة الخاصة به، كيف أصل أنا إليه؟
المحاولة الثالثة: Tailscale، وقتله تعارض مع VPN
للوصول عن بُعد، كان اختياري الأول هو Tailscale. فهو يبني شبكة تراكبية (mesh overlay) من نوع WireGuard: تُثبّته على الجهاز الهدف وعلى جهازك العميل، فيجدان بعضهما البعض عبر خادم التنسيق (coordination server) الخاص بـ Tailscale ويفتحان نفقاً مشفّراً مباشراً. نظيف، ومشفّر من طرف إلى طرف، مع قوائم تحكم بالوصول (ACLs) ووسوم للأجهزة (device tags). قمتُ بتشغيله على OptiPlex بوسم عزل (tag:isolated) وخادم SSH المدمج في Tailscale:
sudo tailscale up --advertise-tags=tag:isolated --ssh
كانت الخطة أن يكون OptiPlex قابلاً للوصول فقط عبر الـ Tailnet، وفقط من أجهزتي المصرّح لها، مع تولّي Tailscale لكل من التشفير والمصادقة. لا منافذ مكشوفة، لا إعادة توجيه منافذ (port forwarding) على الموجّه، لا عنوان IP عام.
أمضيتُ وقتاً في تصحيح الأخطاء (debugging): فحص netmap، والتحقق من سياسة SSH، واستخدام tcpdump على tailscale0 لمراقبة حركة المرور. الإعداد نفسه كان جيداً. ما قتله كان تعارضاً مع VPN الخاص بي.
هذه فئة معروفة ومؤلمة من المشاكل. Tailscale هو نفسه عميل WireGuard، لذا فهو يريد إدارة المسارات (routes) وواجهة افتراضية. عميل VPN تجاري يريد الشيء نفسه تماماً، خصوصاً إذا كان هو أيضاً قائماً على WireGuard أو يُشغّل مفتاح إيقاف (kill switch) يستولي على المسار الافتراضي (default route). على الحاسوب المحمول أو الهاتف الذي كنتُ أتصل منه، تشغيل VPN الشخصي وTailscale معاً في آنٍ واحد كان يعني أن أحدهما يخسر باستمرار. كانت الاتصالات غير مستقرة، أو لا تعمل إطلاقاً.
كان بإمكاني الالتفاف على المشكلة باستخدام توجيه قائم على السياسات (policy-based routing)، أو split tunneling، أو إيقاف تشغيل الـ VPN كلما أردتُ الوصول إلى الوكيل. كل هذه الحلول كانت تُفرغ الفكرة من مضمونها. أردتُ شيئاً "يعمل ببساطة" من أي جهاز، وفي أي حالة شبكة. Tailscale لم يفعل ذلك، في إعدادي. فنزعته:
sudo apt-get remove --purge -y tailscale
sudo apt-get remove -y tailscale-archive-keyring
لا شيء من هذا انتقاد لـ Tailscale. إنه ممتاز، ولو لم أكن أُشغّل VPN استهلاكياً على أجهزتي العميلة لكان هو الإجابة الصحيحة. التعارض كان خاصاً بعاداتي أنا، لا بالأداة نفسها.
المحاولة الرابعة: نفق TCP عبر ngrok (ما أستخدمه الآن)
احتجتُ إلى طريقة وصول عن بُعد لا تهتم بجداول التوجيه (routing tables) أو حالة الـ VPN على جهازي العميل. شيء أتصل فيه بعنوان عام ثابت فيقوم بترحيل (relay) الاتصال إلى الجهاز. استقررتُ على ngrok.
يعمل ngrok كخدمة دائمة على OptiPlex. يتصل خارجاً ببنية الترحيل (relay infrastructure) الخاصة بـ ngrok ويُبقي نفقاً مفتوحاً. يُخصّص ngrok نقطة نهاية TCP عامة تُحوّل إلى منفذ محلي. وجّهته نحو منفذ SSH المحلي:
ngrok tunnel: tcp://<region>.ngrok.io:<port> ──► localhost:22
الآن، من أي مكان، أتصل عبر SSH بـ <region>.ngrok.io على المنفذ <port>، ويُرحّل ngrok الاتصال إلى خدمة SSH daemon الخاصة بـ OptiPlex. لا يوجد على الجهاز أي منفذ وارد (inbound) مفتوح على موجّهي المنزلي. لا إعادة توجيه منافذ، ولا عنوان IP عام مكشوف على اتصالي، ولا Dynamic DNS. جهاز OptiPlex هو من اتصل خارجاً؛ والنفق يُبقى مفتوحاً من الداخل.
(ملاحظة اصطلاحية: كثيراً ما يُطلق الناس على هذا اسم "نفق SSH عكسي" (reverse SSH tunnel)، قياساً على ssh -R، حيث تفتح منفذاً على خادم بعيد يُحوّل الاتصال عائداً إلى جهازك المحلي. يُحقق ngrok نفس تأثير "الوصول من الخارج إلى الداخل"، لكن الترحيل يتم عبر بنية ngrok الخاصة، وليس عبر إعادة توجيه المنفذ العكسي لخادم SSH. نفس المفهوم، "عنوان عام يُنشئ نفقاً إلى خدمة داخلية"؛ لكن بآلية مختلفة.)
للحفاظ على الموثوقية، يعمل ngrok كخدمة systemd على مستوى النظام تُعيد التشغيل تلقائياً عند الفشل، بحيث يعود النفق من تلقاء نفسه بعد إعادة تشغيل الجهاز أو انقطاع مؤقت في الشبكة. خدمة SSH daemon خلفه مقفلة على المصادقة القائمة على المفاتيح فقط: لا كلمات مرور، لا keyboard-interactive. لذا فإن الوصول إلى الوكيل يعني امتلاك المفتاح الخاص الصحيح، ومعرفة عنوان ومنفذ ngrok TCP، والاتصال بخدمة لا تقبل إلا المفتاحين اللذين صرّحتُ بهما.
هذا هو مسار الوصول الحالي، وقد ظلّ مستقراً.
ما أبقيتُ عليه: دفاع متعدد الطبقات على الجهاز نفسه
نقل الجهاز خارج الشبكة المنزلية وجعله قابلاً للوصول حلّ المشاكل على مستوى الشبكة. لكنني ما زلتُ أرغب في تحصين الجهاز نفسه، بحيث حتى أسوأ سيناريو لـ "الشبكة الفرعية المعزولة" يكون محتوىً قدر الإمكان. هذا هو التحصين الذي نجا. على عكس المحاولة الأولى، لا شيء منه يُعطّل قدرة الوكيل على العمل، لأنه يستهدف حركة المرور الواردة (inbound) وسلوك الوكيل نفسه بدلاً من الاتصال الصادر. ولا شيء منه يمسّ الكود المصدري للوكيل: كله عبارة عن تهيئة على مستوى النظام، وتنظيم لنظام الملفات، وميزات مدمجة يتم تفعيلها عبر الإعدادات (config).
جدار حماية المضيف (nftables، رفض افتراضي للحركة الواردة). يُشغّل الجهاز nftables بسياسة DROP افتراضية على حركة المرور الواردة. لا شيء يصل إلى الجهاز ما لم يكن اتصالاً قائماً بالفعل (established)، أو loopback، أو DHCP، أو ICMP. هذا يقع فوق NAT وتقسيم الشبكة، بحيث تكون الحماية من الحركة الواردة مُتراصّة على ثلاث طبقات: موجّه مزوّد الخدمة، وحدود الموجّه الثاني، وجدار حماية المضيف.
SSH بالمفاتيح فقط. المصادقة بكلمة المرور وkeyboard-interactive معطّلة. مفتاحان مصرّح بهما، كلاهما لي. SSH هي الخدمة الوحيدة التي يكشفها نفق ngrok، لذا فهذه هي بوابة بيانات الاعتماد (credential gate) عند نقطة الدخول الواقعية الوحيدة.
دفاعات الوكيل الداخلية الخاصة به. يأتي Hermes مزوّداً بعدة طبقات تركتها مفعّلة:
- ماسح أوامر قبل التنفيذ (Tirith) يفحص كل أمر shell يريد الوكيل تشغيله بحثاً عن تهديدات قائمة على الروابط (URLs)، وهجمات homograph، وأنماط pipe-to-interpreter، وحقن الطرفية (terminal injection)، قبل تنفيذه.
- إخفاء الأسرار (secret redaction) على كل مخرجات الأدوات، بحيث إذا ظهر مفتاح API في ملف أو في stdout لأمر ما، يتم إخفاؤه قبل أن يدخل سياق (context) الوكيل (ولا يمكن تسريبه عبر النموذج). هذا يُلتقط كصورة (snapshot) عند بدء التشغيل ولا يمكن إيقافه خلال الجلسة. هذا مقصود: لا يستطيع الوكيل تعطيل إخفاء أسراره الخاص.
- بوابة موافقة يدوية على الأوامر المدمّرة (
rm -rf، وforce-pushes، إلخ). يجب على الوكيل أن يطلب الإذن قبل تشغيلها. (المهام المجدولة عبر cron تستخدم وضعاً أكثر صرامة تُرفض فيه الأوامر المدمّرة تلقائياً.) - ماسح تهديدات على ملفات سياق المشروع (ملفات
.hermes.md/AGENTS.mdالتي تُحقن في system prompt)، يُحيّد أنماط حقن الأوامر (prompt-injection). - قائمة سماح للمتصلين (caller allowlist) على بوابة Telegram، وهي القناة الوحيدة التي يستمع إليها الوكيل.
فصل البيانات. بيانات الوكيل الكبيرة (الجلسات، السجلات، الذاكرة المؤقتة) تعيش على SSD خارجي مخصص، بينما الملفات الحساسة أمنياً (ملف .env الذي يحتوي مفاتيح API، والإعدادات، وقاعدة بيانات الجلسات) تبقى على قرص النظام بصلاحيات 600.
ملف تعريف ثانوي مقيّد. أحتفظ بملف تعريف (profile) ثانٍ لـ Hermes مع تعطيل معظم مجموعات الأدوات الخطيرة (البرمجة، computer use، إلخ) لمهام البحث حيث لا أحتاج القدرة الكاملة.
أين انتهى بي الأمر: تقييم صادق
إليكم ما تحميه الوضعية النهائية فعلياً، وما لا تحميه.
محمي ضد:
- اختراق جهاز الوكيل واستخدامه لمهاجمة شبكتي المنزلية (لا يستطيع التوجيه إلى هناك).
- الاتصالات الواردة غير المرغوبة من الإنترنت (لا منافذ مفتوحة على موجّهي؛ جدار حماية المضيف يرفض افتراضياً).
- وصول أشخاص غير مصرّح لهم إلى الوكيل عبر Telegram (قائمة السماح).
- تسريب الوكيل لمفاتيح API الخاصة بي داخل سياقه الخاص أو في محادثة (إخفاء الأسرار).
- تشغيل الوكيل لأمر مدمّر عن طريق الخطأ أو عبر حقن أوامر (prompt-injection) ساذج (بوابة الموافقة + ماسح الأوامر).
- هجمات القوة الغاشمة (brute-force) على كلمة مرور SSH (مصادقة بالمفاتيح فقط).
غير محمي ضد (وأنا أعلم ذلك):
- حقن أوامر (prompt-injection) مُصمَّم بإصرار كافٍ يتسلسل وصولاً إلى الـ shell. الواجهة الخلفية للطرفية (terminal backend) الخاصة بالوكيل تعمل محلياً، بصفتي أنا كمستخدم، وبصلاحيات sudo. لو استطاع مهاجم صياغة مُدخل يُقنع الوكيل بتشغيل أوامر shell عشوائية، فلا يوجد صندوق عزل (sandbox) على مستوى نظام التشغيل بين الوكيل والمضيف. الماسحات الداخلية وبوابة الموافقة ترفع السقف، لكنها أساليب استدلالية (heuristics)، لا حدود احتواء فعلية.
- السرقة المادية للجهاز. الأقراص غير مشفّرة. من يملك الجهاز يملك مفاتيح API وسجل الجلسات.
- مهارة (skill) أو إضافة (plugin) خبيثة تعمل داخل عملية الوكيل بصلاحيات كاملة. أُخفف من هذا الخطر بعدم تحميل إضافات من أطراف ثالثة، لكنه حد ثقة (trust boundary)، لا حد تقني.
- نقطة نهاية ngrok نفسها. لو تم اختراق ngrok، أو تسرّبت بيانات اعتمادي الخاصة بـ ngrok، سيُكشف منفذ SSH عبر خدمة الترحيل الخاصة بهم. أنا أثق بـ ngrok كجزء من سلسلة ثقتي، وهي مقايضة واعية مقابل راحة عدم تشغيل خدمة ترحيل خاصة بي.
- تسريب البيانات من الجهاز نفسه. الوصول الصادر الحر هو التصميم نفسه؛ هذا ما يجعل الوكيل مفيداً وما سمح لي بالتوقف عن محاربة تصفية egress. الجانب الآخر من العملة هو أن المضيف المخترق يستطيع قراءة قرصه الخاص (ملف
.env، قاعدة بيانات الجلسات) وإرسالها (POST) إلى أي مكان يريده، ولن يوقفه شيء على الجهاز. إخفاء الأسرار يحمي من تسرّب مفتاح إلى سياق النموذج؛ لكنه لا يفعل شيئاً ضد مضيف مخترق يقرأ الملف مباشرة. أتقبّل هذا الخطر عن قصد: كل مفتاح API يحمله الوكيل مُقيَّد النطاق بخدمة ذات حد إنفاق صارم، لذا فإن أسوأ سيناريو لمفتاح مسرّب هو فاتورة محدودة، لا إساءة استخدام غير محدودة.
الخلاصة الصادقة: قايضتُ عزل الوكيل على مستوى نظام التشغيل مقابل راحة واجهة خلفية (backend) محلية، وعوّضتُ عن ذلك بعزل الجهاز على مستوى الشبكة بحيث تكون دائرة ضرر الوكيل محدودة بموجّه بدلاً من حاوية (container). هذه مقايضة معقولة لوكيل شخصي، أحادي المستخدم، أحادي المستأجر (single-tenant). لن تكون المقايضة الصحيحة لو كان الوكيل يخدم مستخدمين غير موثوقين، أو يستوعب محتوى غير موثوق (كتحليل بريد إلكتروني عشوائي)، أو يعمل في بيئة مشتركة.
الخلاصة العملية
لو كان هناك شيء واحد أقوله لشخص يُعِدّ وكيلاً يعمل على مدار الساعة لأول مرة، فهو هذا: لا تحاول جعل الوكيل آمناً بقواعد جدار الحماية وحدها. مهمة الوكيل بأكملها هي التواصل مع العالم الخارجي، وتصفية egress تُقاوم ذلك في كل خطوة. بدلاً من ذلك، ضع الوكيل على قطاع شبكة (network segment) لا يمكن الوصول منه إلى الأشياء التي قد يضرّها، ودعه يتحدث مع الإنترنت بحرية. تقسيم الشبكة هو إجراء مادي/تهيئي يُنجَز مرة واحدة ولا يتدهور مع تطوّر سلوك الوكيل؛ بينما قائمة سماح egress هي عبء صيانة يتعفّن بمجرد أن تنظر بعيداً عنه.
مبدأ ثانٍ، تعلمته بالطريقة الصعبة: عندما تُحصّن الوكيل نفسه، فضّل التهيئة (configuration) والميزات المدمجة على تعديل كوده المصدري. التخصيص الذي يعيش في كود الوكيل المصدري يموت مع التحديث التالي؛ أما ذلك الذي يعيش في الإعدادات أو في الشبكة فيبقى حياً عبر كل ترقية.
أما الباقي فهو دفاع متعدد الطبقات للأشياء التي لا يلتقطها تقسيم الشبكة: SSH بالمفاتيح فقط، وجدار حماية للمضيف يرفض افتراضياً، وفحص الأوامر وإخفاء الأسرار الخاصان بالوكيل نفسه. لكن تقسيم الشبكة فعل لهذا الإعداد أكثر من كل الإجراءات الأخرى مجتمعة، وهو الجزء الذي كان يجب أن أفعله أولاً.
المضيف: Dell OptiPlex 9020M، Linux. الوكيل: Hermes (Nous Research). الوصول عن بُعد: نفق ngrok TCP إلى SSH بالمفاتيح فقط. كُتب في يوليو 2026.