في مكان ما داخل مستودع GitHub عام، تجلس كلمة مرور قاعدة بيانات إنتاج داخل ملف JSON. تجلس هناك منذ 217 يومًا. لا أحد كتبها عن قصد. وصلت إلى هناك لأن مطورًا سأل وكيل برمجة بالذكاء الاصطناعي عن سبب فشل تسجيل الدخول على staging، فاقترح الوكيل الأمر البديهي، فلمس المطور زر "نعم، ولا تسأل مجددًا".
تلك اللمسة هي الحكاية كلها.
في 6 نوفمبر، نشرت شركة الأمن Apiiro بحثًا يوضح أن هذا النمط بالذات ترك 2,539 سرًّا حقيقيًّا مكشوفًا في 1,994 مستودع GitHub عام. من بينها: مفتاح سحابي إداري لشركة قواعد بيانات، بلا تاريخ انتهاء؛ وكلمة مرور Postgres إنتاج على Azure؛ وتوكن إنتاج لـ Square؛ وكلمة مرور المالك لقاعدة بيانات سجلات طبية. ثلاث وستون مؤسسة، معظمها شركات برمجيات، لديها بيانات اعتماد حيّة واحدة على الأقل داخل قائمة صلاحيات عامة. شركة واحدة أكدت أن مفتاحها كان ما زال يعمل حين اتصل بها الباحثون.
هذه ليست مشكلة نموذج. هذه مشكلة سلوك منتج، وهي تحدث لفرق ظنّت أنها كانت حذرة.
الآلية ثلاثة كلمات
يسأل Claude Code قبل تنفيذ أي أمر shell. هذا هو الحاجز، وهو حاجز معقول. لكن السؤال يعرض خيارًا: "نعم، ولا تسأل مجددًا". إن اخترته، يكتب Claude Code قاعدة صلاحية داخل .claude/settings.local.json في مجلد المشروع. القاعدة هي نص الأمر، كلمة بكلمة.
إن كان الأمر PGPASSWORD=hunter2 psql -h prod-db.internal -U admin، فالقاعدة هي PGPASSWORD=hunter2 psql -h prod-db.internal -U admin. الوكيل لم يقرر حفظ كلمة مرورك. حفظ أمرك، وأمرك كان يحتوي كلمة مرورك.
أعادت Apiiro إنتاج السلوك مع أحدث نماذج Anthropic، Opus 5.5 وFable 5.1. الأمر يتعلق بالأداة المحيطة، لا بطبقة الاستدلال. ومن بين ستة عشر وكيل برمجة قارن الباحثون توثيقها، يبقى Claude Code الوحيد المؤكد أنه يحفظ الأمر الكامل الموافق عليه داخل ملف في المشروع، وبشكل افتراضي.
الحماية موجودة، لكنها لا تُسافر
هنا يصبح الأمر مثيرًا، وهنا تتوقف معظم التحليلات خطوة مبكرة.
يحاول Claude Code فعلًا إبقاء هذا الملف خارج git. في أول مرة يكتبه داخل مستودع، يضيفه إلى قائمة استبعاد git العالمية الخاصة بك. على جهازك، وفي إعدادات git لديك، يتجاهل git هذا المسار في كل مستودع تلمسه. هذه هندسة مدروسة بصدق.
وهي أيضًا هندسة لا تصمد أمام الواقع.
الاستبعادات العالمية تعيش في إعدادات مستخدم واحد على حاسوب واحد. وبمجرد أن يكون الملف قد تم عمل commit له، لا تفعل تلك الاستبعادات شيئًا. لا تحمي نسخة على جهاز زميل، ولا مجلدًا صار مستودعًا لاحقًا، ولا fork. والأهم: لا يضيف Claude Code المسار إلى .gitignore الخاص بالمشروع نفسه، فالحماية ليست جزءًا من المستودع أصلًا. لا تُسافر مع الكود أبدًا.
والأسوأ: في 539 من أصل 1,105 مستودعات فيها سر مؤكد، كان الـ commit الذي غيّر الملف يحمل Claude كمؤلف مشارك. الوكيل، وهو يفعل ما تفعله الوكلاء، عمل commit للعمل. وكان العمل يحتوي قائمة صلاحياته الخاصة.
ماذا تقول الأرقام فعلًا
فحصت Apiiro 104,185 نسخة عامة من .claude/settings.local.json في 103,617 مستودعًا. منها 1,122 ملفًا (نحو 1.1%) تحتوي سرًّا حقيقيًّا: 1,379 بيانات اعتماد مختلفة. التفصيل يستحق التوقف عنده:
- 379 كلمة مرور قاعدة بيانات و122 مفتاح service-role لـ Supabase، وهذه تفتح قاعدة البيانات مباشرة
- 103 توكنات حساب Supabase، التي تتحكم في كل مشاريع ذلك الحساب
- 43 بيانات دخول SSH إلى خوادم عامة، بعضها بصلاحية root عبر
sshpass - 42 توكن GitHub وGitLab وnpm، و23 مفتاح AWS، و6 مفاتيح خاصة
أكثر من ثلث بيانات الاعتماد المكشوفة تفتح قاعدة بيانات. هذه ليست توكنات تُدوَّر كل ربع سنة. هذه هي الجواهر نفسها، في ملف باسم ودود.
وارتباط الحجم بالخطر وحشي: ملف واحد من كل عشرة يتجاوز 8 كيلوبايت يحتوي سرًّا حقيقيًّا، مقابل أقل من واحد من كل خمسمئة تحت 500 بايت. وكلما طال نقر المطور على "لا تسأل مجددًا"، ثقل الملف. الملف المكشوف الوسيط تم عمل commit له أول مرة قبل 217 يومًا من الاكتشاف. وفي 118 مستودعًا مضى عليه أكثر من سنة.
وحذف الملف لا يحل شيئًا. النسخ الأقدم تحتوي 734 سرًّا آخر في 509 مستودعات، لا تظهر في أي نسخة حالية، غالبًا لأن أحدهم حذف الملف في النهاية. والـ forks تزيد الطين بلة: 211 fork من 74 مستودعًا تحمل الأسرار نفسها الموجودة في الأصل. هذه خاصية git الكلاسيكية التي تفاجئ الجميع في المرة الأولى: سر تم عمل commit له هو سر دائم، وسر دائم في مستودع عام هو سر منشور.
أداة فحص الأسرار لديك على الأرجح لم تره
هذا هو الجزء الذي تحتاج فرق الأمن سماعه. شغّلت Apiiro أداتي gitleaks وTruffleHog على كل الملفات الـ104,185. من بين الـ1,122 التي كانت تحتوي سرًّا حقيقيًّا، رصدت gitleaks عدد 564 ورصدت TruffleHog عدد 643. و215 ملفًا لم ترصدها أي منهما.
النقطة العمياء هي كلمات المرور داخل الأوامر. أدوات الفحص معايرة على أشكال المفاتيح: بادئة مزوّد، سلسلة عشوائية طويلة، حد للإنتروبيا. أما كلمة مرور بعد PGPASSWORD= أو sshpass -p أو mysql -p، أو داخل ترويسة bearer في استدعاء curl، فهي مجرد كلمة عادية في سطر أوامر عادي. تبدو مثل shell، لأنها shell فعلًا.
والنمط لا يقتصر على ملف واحد. البحث نفسه وجد أسرارًا في:
- ملف
.claude/settings.jsonالمشترك الذي تعمل الفرق commit له عن قصد (298 من 76,011 ملفًا) - نصوص محادثات الوكلاء المصدَّرة من
.specstoryوAider وCursor (120 ملفًا في 87 مستودعًا) - ملفات ذاكرة الوكلاء مثل
MEMORY.md(9 مستودعات) - ملاحظات التسليم والنشر (33 ملفًا، ثلثها كتبه الوكيل نفسه)
- إعدادات الموافقة التلقائية في VS Code Copilot (9 مستودعات)
والعادة التي تُسرّب هي نفسها في كل مكان: إنسان يكتب سرًّا داخل أمر، ووكيل يسجّل الأمر بأمانة تامة.
ما العمل، بالترتيب
دوّر أولًا. نظّف بعد ذلك. هذا الترتيب ليس تفضيلًا، بل هو التسلسل الوحيد الذي يعمل، لأن بيانات الاعتماد في اللحظة التي تلمس فيها commit عامًا تصبح ملكًا لكل من قرأه، والتاريخ يتذكر.
- ابحث عن الملف في مؤسستك. افحص GitHub عن
.claude/settings.local.jsonو.claude/settings.jsonفي كل المستودعات، وافحص تاريخ git حتى في المستودعات التي لم يبق فيها الملف اليوم. - دوّر كل ما احتواه الملف يومًا ما، من كلمات مرور وتوكنات ومفاتيح وسلاسل اتصال، قبل أن تبدأ الحذف.
- أوقف تتبعه وتجاهله. نفّذ
git rm --cached .claude/settings.local.jsonوأضفه إلى.gitignoreالخاص بالمستودع نفسه، لا إلى العام فقط. - افتح الملف على حاسوبك أنت، سواء كان في git أم لا، واحذف كل قاعدة تحتوي سرًّا. معظم هذه الملفات لم تلمس GitHub أبدًا، وما زالت نصًّا صريحًا على القرص.
- توقف عن وضع الأسرار داخل الأوامر. استخدم
$DB_URLمن مدير أسرار، حتى تسجّل القاعدة اسم متغير لا بيانات اعتماد. - وافق على أنماط، لا على أوامر.
Bash(npm run:*)قاعدة. أماnpm run deploy --token abc123فهي تسريب.
ولفرق الأمن أربع إضافات: اعتبر .claude/ و.cursor/ و.gemini/ و.specstory/ وملفات ذاكرة الوكلاء مسارات تحمل أسرارًا بدرجة .env نفسها، على الحواسيب كما في المستودعات؛ وأضفها إلى الفحص في pre-commit وCI بما في ذلك التاريخ؛ وأضف .claude/settings.local.json إلى قالب .gitignore في مؤسستك؛ وابدأ بفرز بيانات الاعتماد المقترنة بعنوان خادم عام، لأنها هي التي تمنح وصولًا من أي مكان.
الخلاصة التي نكررها
الدرس ليس أن "وكلاء الذكاء الاصطناعي خطيرون". نموذج الصلاحيات في Anthropic منطقي، والاستبعاد العالمي في Claude Code يدل على أن أحدًا فكّر في هذا العطل تحديدًا. الدرس هو أن إعدادات الراحة تتحول بهدوء إلى مخازن. كل "لا تسأل مجددًا" سجل. وكل سجل له مسار. وكل مسار ينتهي عاجلًا أو آجلًا في مستودع، أو أرشيف، أو طبقة Docker، أو مجلد متزامن.
إن كان فريقك يعمل بوكلاء البرمجة منذ سنة، فلديك على الأرجح مجلد .claude/ أقدم من أي سياسة كتبتها بعد ذلك. اذهب واقرأه. لا نسخة المستودع، بل النسخة التي على الحاسوب أمامك. ثم انظر ماذا قالت أدوات الفحص عنه، وافترض أنها لم تقل شيئًا.
الأمر الذي وافقت عليه مرة واحدة ما زال يحمل كلمة مرورك. وسيظل يحملها حتى تُدوّرها.