مقالات معمّقة حول التكنولوجيا التي تشكّل المستقبل.

باب Cursor الخلفي في السوق: مشكلة ثقة فروع VS Code

يكشف باب Claude Code الخلفي في سوق Cursor لماذا لا ترث فروع VS Code نموذج ثقة إضافات Microsoft. إليك ما يجب فحصه الآن.

شاشة لابتوب تعرض شبكة من أيقونات الإضافات، وإحداها مكسورة بضوء أحمر وظل يمتد نحو لوحة المفاتيح
شبكة الإضافات تبدو متطابقة سواء كانت البطاقة خلفها نظيفة أو تحمل حمولة خبيثة.

يفتح مطوّر برنامج Cursor صباح الثلاثاء، ويرى تحديثاً لإضافة Claude Code، فيسمح بتثبيته. لا شيء يبدو مختلفاً. الإضافة تعمل، ومساعد الذكاء الاصطناعي يستجيب، وبحلول الغداء يكون الجهاز قد حمل مفتاح Ed25519 يعود للمهاجم داخل ~/.ssh/authorized_keys، ونفق SSH عكسي يرسل إشارات إلى خادم على الإنترنت، وLaunchAgent يتخفى كعملية نظام من آبل ويُبقي كل ذلك حياً عبر إعادة التشغيل. هذا هو باب Cursor الخلفي في السوق الذي كشفت عنه شركة Phorion، وهو أوضح مثال حتى الآن على شيء يتحدث عنه المختصون في الأمن منذ سنوات: فروع VS Code ترث قاعدة الكود من Microsoft، لكنها لا ترث نموذج الثقة الخاص بها.

قضيت جزءاً كبيراً من مسيرتي في الاستجابة للحوادث على أجهزة المطورين، وهذه الحادثة تلامس وتراً حساساً بسبب مدى عادية آلية التوصيل. لا تصيد، ولا ثغرة يوم صفر. مجرد حزمة إضافة معدّلة، النسختان 2.1.312 و2.1.313، نُشرت في سوق يثق به المطورون افتراضياً لأنه يبدو كالشيء الذي يثقون به أصلاً. القنوات الرسمية لشركة Anthropic كانت سليمة، إذ استخدم أحدهم صلاحية الوصول إلى خط نشر Cursor ليرفع نسخة معدّلة من إضافة لم تبنِها Anthropic لذلك السجل. ونطاق الضرر شمل كل مستخدمي Cursor الذين فعّلوا التحديث التلقائي خلال نافذة مدتها إحدى عشرة ساعة.

ماذا فعل الباب الخلفي فعلياً

كانت الحمولة عبارة عن تعبير دالة فورية التنفيذ (IIFE) أُضيف في بداية ملف extension.js المصغّر. كل ما يأتي بعد البادئة المحقونة يبدو كالإضافة الطبيعية تماماً، بنفس تصديرات activate وdeactivate، ونفس كود الواجهة، ونفس النصوص. وهذا هو الجزء الذي ينبغي أن يقلقك إذا كانت استراتيجية الاكتشاف لديك تعتمد على "مقارنة الحزمة بالنسخة الأصلية": الجزء الخبيث هو بضع مئات من البايتات من جافاسكربت الإضافية فوق ملف سليم يبلغ حجمه ميغابايتات. يعمل الكود لحظة تحميل Node للوحدة، قبل أن تُستدعى دالة activate الخاصة بالإضافة. ولا يحتاج المستخدم إلى النقر على شيء، أو استدعاء Claude، أو التفاعل مع الإضافة أصلاً.

الحمولة نفسها مهمة من أربع مراحل، وبصراحة هي عمل متقن:

  • زرع المفتاح. يُلحق مفتاح Ed25519 العام الذي يتحكم به المهاجم، ويحمل تعليق svc-telemetry، بملف ~/.ssh/authorized_keys مع صلاحيات 0700/0600 الصحيحة.
  • تفعيل SSH. يحاول التأكد من أن sshd يعمل: عبر systemctl على Linux، أو Remote Login على macOS، أو OpenSSH Server عبر PowerShell على Windows.
  • النفق العكسي. يفتح اتصال SSH صادراً إلى خادم يتحكم به المشغّل باستخدام -R *:0:localhost:22، بحيث يستطيع المهاجم الوصول عبر النفق إلى المنفذ 22 للضحية وتسجيل الدخول بالمفتاح المزروع. لا حاجة لبروتوكول C2 مخصص، فـSSH هو قناة التحكم والسيطرة.
  • الاستمرارية والاستطلاع. وكيل مستخدم LaunchAgent باسم com.apple.sysmond.plist على macOS، وإدخال cron بـ @reboot على Linux، ومسار احتياطي في مجلد Startup على Windows. ثم إشارة استطلاع لمرة واحدة تحمل اسم الجهاز، واسم المستخدم، وبريد git الإلكتروني، والعنوان العام، وحتى أربعين اسماً لمتغيرات البيئة تطابق /KEY|TOKEN|SECRET|PASS|AWS|GCP/i.

البند الأخير ذكي بطريقة تستحق الفهم. الإشارة لا تسرّب مفتاح AWS السري الخاص بك، بل تسرّب حقيقة أن لديك واحداً. إنها قائمة استهداف. يحصل المشغّل على قائمة بالأجهزة المخترقة التي يعمل أصحابها كمهندسي سحابة ولديهم بيانات اعتماد فعّالة في بيئتهم، وهؤلاء بالتحديد هم من يعود إليهم أولاً عبر النفق.

خطأ في macOS أنقذ الناس بالصدفة

هذه تفصيلة أجدها مضحكة بشكل قاتم بصفتي من يستجيب للحوادث: مسار التفعيل على macOS في البرمجية الخبيثة مكسور بسبب خطأ كلاسيكي في البرمجة النصية. يشغّل الكود الأمر systemsetup -getremotelogin بصلاحيات مستخدم عادي، ولا يحاول تفعيل Remote Login إلا إذا تطابق الناتج مع /Off/i. لكن على macOS يرفض هذا الأمر العمل دون صلاحيات المسؤول، فيطبع "You need administrator access to run this tool... exiting!" على stdout ويخرج برمز الحالة 0.

// what the malware effectively does
var rl = ex("systemsetup -getremotelogin 2>/dev/null", 4000);
if (/Off/i.test(rl)) {
det("sudo -n systemsetup -setremotelogin on >/dev/null 2>&1");
}

نص الخطأ لا يحتوي على "Off"، فيفشل التعبير النمطي، فلا تُنفَّذ خطوة التفعيل أبداً. يعامل السكربت رسالة "ليس لدي صلاحية للتحقق مما إذا كان SSH متوقفاً" على أنها "SSH يعمل بالفعل". والخروج برمز 0 من أمر فاشل هو أحد أقدم الأخطاء الشائعة في البرمجة النصية، وقد ارتد هذه المرة على كاتب البرمجية بدلاً من مسؤول أنظمة. على جهاز Mac لم يُفعّل فيه Remote Login مسبقاً، يتصل النفق العكسي بالخارج بنجاح، لكن أي شيء يُمرَّر عبره يصطدم بالمنفذ 22 المغلق. المفاتيح والاستمرارية تُزرع مع ذلك، أي أن الجهاز ما زال مخترقاً، لكن مسار الوصول التفاعلي ميت منذ البداية.

لا تطمئن لهذا الأمر. إذا كان Remote Login مفعّلاً عند المستخدم أصلاً، أو فعّله لاحقاً، فالمفتاح المزروع ينتظر في authorized_keys. مسار Windows فيه خطأ مشابه، إذ يمرر أمر PowerShell عبر مساعد يثبّت /bin/sh بشكل ثابت في الكود، ومنطق cron على Linux يمكن أن يمسح crontab الحالي للمستخدم عند التشغيلات المتكررة. البرمجيات الخبيثة التي يكتبها البشر تحمل أخطاء بشرية. وبرمجية الشهر القادم لن تكون كذلك.

لماذا لا تستطيع الأسواق المتفرعة وراثة نموذج ثقة Microsoft

هذه هي النقطة البنيوية، وأريد من قادة الهندسة أن يتأملوها. عندما تثبّت إضافة من سوق Visual Studio الرسمي، فهناك خط إنتاج حقيقي خلفها: حسابات ناشرين مع التحقق من النطاق، وفحص عند النشر، وإجراءات سحب، وشركة لها قسم قانوني على الطرف الآخر. وهو بعيد عن الكمال، فقد تسللت منه إضافات خبيثة، لكنه نظام.

فروع VS Code مثل Cursor لا تستطيع استخدام ذلك السوق لأسباب تتعلق بالترخيص، فتتجه إلى سجلات بديلة مثل Open VSX أو بنيتها الخاصة. واجهة المحرر مألوفة تماماً حتى البايت الأخير. صفحة الإضافة تعرض الاسم نفسه والأيقونة نفسها واسم ناشر معقول. لكن كل ضابط جعل السوق الأصلي جديراً بالثقة هو إعادة تنفيذ له، أو غائب تماماً. من تحقق من الناشر؟ من فحص الحزمة؟ هل بُنيت الأداة من المستودع المصدري الذي تدّعيه، وهل تستطيع التحقق من ذلك؟ في هذه الحادثة، النسخ المعدّلة على ما يبدو لم تكن موجودة أصلاً في سجل Microsoft، بل عاشت فقط في سجل الفرع. كانت الثقة بصرية بحتة.

شاهدنا الفيلم نفسه في عالم حزم السجلات. اختراق LiteLLM على PyPI نجح لأن صلاحية النشر هي الحلقة الضعيفة، لا الكود. الإضافات أسوأ من الحزم بطريقة مهمة واحدة: لا توجد ثقافة ملفات قفل، ولا إعادة بناء قابلة للتكرار مثل npm ci، ولا تثبيت بالهاش. المحرر يحدّث نفسه بصمت، وكما اكتشف أحد المعلّقين في Hacker News، فإن تأخير التحديث التلقائي في VS Code لا ينطبق حتى على "الناشرين الموثوقين"، وهي قائمة لا تستطيع ضبطها. مجموعة إضافاتك شجرة اعتماديات حية وغير مثبّتة، تعمل بكامل صلاحيات مستخدمك، وتحدّث نفسها بينما أنت نائم.

متجران متطابقان، أحدهما متين والآخر يتكشف عن واجهة جوفاء مدعومة من الخلف
السوق المتفرع يبدو متطابقاً من الواجهة، وقد تكون البنية الثقية خلفه مجرد واجهة.

أدوات البرمجة بالذكاء الاصطناعي هي تصعيد للصلاحيات اخترته بنفسك

تجاهل دراما السوق وانظر إلى الهدف الحقيقي. إضافة برمجة بالذكاء الاصطناعي ليست سمة ألوان. تعمل بصلاحيات بيئة التطوير، وهي صلاحياتك أنت، ومهمتها كلها أن تقرأ شجرة الكود لديك، وتحتفظ ببيانات اعتمادك للواجهات البرمجية، وتنفذ أوامر الشل نيابة عنك بشكل متزايد. عندما كتبنا عن كيف تتعامل أدوات CLI للبرمجة الوكيلة مع الصلاحيات، كان الموضوع المتكرر أن الوكيل المفيد والوكيل الخطير يفصل بينهما السياسة، لا القدرة. والإضافة التي تستطيع تشغيل child_process لا تفصلها عن تشغيل أي شيء إلا عملية نشر خبيثة واحدة.

علّق أحدهم بصراحة: كل من يستخدم هذه الأدوات كان فعلياً يشغّل curl-pipe-bash يومياً، ونحن أمضينا عقداً نحذّر المطورين المبتدئين من ذلك. إنها مبالغة، لكنها قليلاً فقط. الفرق بين curl | bash وإضافة وكيلية تحدّث نفسها أن الإضافة تملك واجهة أجمل. سبق أن قلت إن أدوات CLI لا ينبغي أن تثبّت خدمات خلفية افتراضياً، وهذه الحادثة هي ما يحدث عندما يثبّت الخدمة شخص آخر ولا تُستشار أنت أصلاً. عملية ssh منفصلة تبقى بعد إغلاق المحرر هي بالضبط النمط السلوكي الذي أعلّمه في المراجعات، وقد وصلت عبر قناة تحديث موثوقة على يد مهاجم.

كيف تفحص أسطولك الآن

إذا كان أي شخص في مؤسستك يستخدم Cursor، فتعامل مع الأمر كحادثة جارية لا كخبر عابر. المؤشرات عالية القيمة، مأخوذة مباشرة من التقرير الجنائي:

# macOS / Linux: the planted key is the cleanest signal
grep -s svc-telemetry ~/.ssh/authorized_keys && echo "IMPACTED" || echo "key not found"
# Check persistence artifacts
ls ~/Library/LaunchAgents/com.apple.sysmond.plist 2>/dev/null   # macOS
ls ~/.config/.smt ~/.config/.smtk 2>/dev/null                   # macOS + Linux
crontab -l 2>/dev/null | grep -F .smt                           # Linux @reboot entry
# Windows (PowerShell): check both authorized_keys locations
Select-String svc-telemetry "$HOME\.ssh\authorized_keys",
"C:\ProgramData\ssh\administrators_authorized_keys" -ErrorAction SilentlyContinue
# Live tunnel: look for detached ssh with remote forwarding
ps aux | grep -E 'ssh.*-R' | grep -v grep

بعض ملاحظات الصيد من الخبرة. أولاً، تحقق من بصمة المفتاح لا من التعليق فقط، فالحمولة تزيل التكرار بناءً على تعليق svc-telemetry، ومحاولة التنظيف قد تفعل الشيء نفسه. ثانياً، ملف مفتاح النفق يقع في مجلد الملفات المؤقتة باسم يبدأ بـ .stk_ متبوعاً بعشرة محارف سداسية عشرية مشتقة من MD5 لاسم المضيف ومسار المجلد الشخصي؛ وهو حتمي لكل جهاز، لذلك تستطيع حساب اسم الملف بدقة والبحث عنه. ثالثاً، قياسات العمليات في EDR لن تُظهر محاولة التفعيل على macOS للمستخدمين العاديين، لأن الخطأ يعني أنها لا تُنفَّذ أصلاً. غياب systemsetup -setremotelogin من سجلاتك لا يعني غياب الاختراق. المفتاح ووكيل LaunchAgent هما الحقيقة الأرضية.

إذا وجدت المفتاح، فالجهاز يحتاج إلى معالجة كاملة للحوادث: أعد تدوير كل بيانات اعتماد يمكن أن يكون اسم متغير بيئتها قد أُرسل (وهي معظمها، فالتعبير النمطي يلتقط AWS وGCP وأي شيء يحمل KEY أو TOKEN في اسمه)، وألغِ وصول الجهاز، وأعد تثبيت نظامه. لا تكتفِ بحذف المفتاح وتعتبر الأمر منتهياً. المشغّل كان لديه، أو حاول أن يحصل على، وصول تفاعلي إلى الشل، ولا يمكنك حصر ما لمسه من كود الحمولة وحده. وهنا أيضاً تظهر النقاط العمياء في تسجيل المصادقة السحابية: ابحث في سجلات التدقيق السحابية عن استخدام الواجهة أو الواجهة البرمجية خلال الفترة الممتدة بين تحديث الإضافة والكشف عنها، مع تتبع بيانات اعتماد المستخدم المتأثر.

شعاع مصباح يبرز مفتاحاً أحمر متوهجاً من حلقة مفاتيح، وكابل يمتد إلى الظلام
ابحث عن المفتاح المزروع ببصمته لا بتسميته، فالتسمية أول ما يحذفه التنظيف.

التقسية: احتوِ المحرر لا الإضافة فقط

بعد الحادثة يسأل الجميع عما يجب تغييره. موقفي، وسأدافع عنه: لن تصل أبداً إلى منظومة إضافات آمنة عبر التدقيق وحده، لذا فالاحتواء هو الحل. تناولنا المفاضلة العامة في الاحتواء مقابل المراقبة لوكلاء الذكاء الاصطناعي، وهذه الحادثة هي دراسة الحالة للاحتواء. المراقبة لم تخبرك بشيء هنا حتى قامت شركة أمن خارجية بتشريح الحزمة بالصدفة.

  • ثبّت إصدارات الإضافات وعطّل التحديث التلقائي لأي إضافة لها صلاحيات واسعة، وطبّق القاعدة نفسها على الفروع. نعم، ستعاني من إرهاق التحديثات. وهذا أرخص من الاستجابة للحوادث.
  • فلترة الخروج على أجهزة المطورين. يعتمد نموذج الوصول كله هنا على اتصال SSH صادر إلى عنوان IP لخادم خاص افتراضي. إذا كانت أجهزة المطورين لا تستطيع فتح المنفذ 22 الصادر إلى أي وجهة، فتموت مرحلة النفق. قلّ من يفعل ذلك، ولو فعلته لأبطلت هذه الحمولة تماماً.
  • راقب حالة SSH كإنذار مبكر. نبّه عند تفعيل Remote Login، أو ظهور مفاتيح جديدة في authorized_keys، أو وجود عمليات sshd على أجهزة لا ينبغي أن تشغّل sshd أصلاً.
  • اجرد أدوات الذكاء الاصطناعي كما تجرد الخوادم. اعرف أي الإضافات ووكلاء CLI معتمدة، وما الصلاحيات التي تملكها، وأي سوق تأتي منه. إذا كانت الإجابة عن سؤال "من أي سجل تأتي تثبيتات Cursor لدينا" هي هزّ الكتفين، فهذا مشروع ربعك القادم.
  • فضّل الوكلاء الذين يعملون داخل صناديق رملية أو حاويات حيثما أمكن، مع حقن بيانات الاعتماد لكل جلسة بدلاً من تركها في بيئة العملية. يعمل استخراج أسماء متغيرات البيئة لدى الإشارة لأننا نترك الأسرار مبعثرة في بيئات العمليات.

سوق الإضافات بلا مسار تحقق خاص به ليس سوقاً، بل مستضيف ملفات بزر تثبيت.

الخلاصة غير المريحة

لم تُخترَق Anthropic. بل اختُرق سوق Cursor، وتحمّلت علامة Anthropic الضرر على أي حال، لأن الإضافة بالنسبة للمطور هي المنتج، بغض النظر عمّن نشر أي نسخة. هذا هو اقتصاد الأنظمة المتفرعة: أرخص طريقة لضرب هدف عالي القيمة هي مهاجمة أضعف سجل تثق به مستخدمو ذلك الهدف. ومساعدو البرمجة بالذكاء الاصطناعي يقعون عند التقاطع المثالي: قاعدة تثبيت هائلة، وأعلى صلاحية محلية، وبيانات اعتماد في كل مكان، وسلسلة توريد تتفرع وتعيد استضافة نواتجها عبر سجلات ذات أوضاع أمنية متباينة بشدة.

انتهت هذه الحادثة بسحب النسخ الخبيثة خلال نحو إحدى عشرة ساعة، وحدّ خلل في macOS من الضرر. الاستجابة كانت مقبولة. المشكلة في البنية، ولم تتغير: محررك مدير حزم يشغّل كل ما يثبّته باسمك، ويحدّثه بصمت، وفي عدد متزايد من الإعدادات يحصل على حزمه من سجل لم يقيّمه أحد في فريق الأمن لديك. أصلح قواعد الخروج، وثبّت الإضافات، واجرد الوكلاء. هجوم نشر الناشر التالي لن يكون فيه خلل في regex ينقذ مستخدميك.