اگر Password یا API Key را اشتباهی در GitHub Push کردیم چه کنیم؟
واکنش به Push اشتباه Password یا API Key روی GitHub بر اساس Docs رسمی: اول Rotate، سپس ارزیابی پاکسازی با git-filter-repo و هماهنگی تیم.
Founder & product engineer

لحظهٔ بدی است: Push تمام شده و بعد میبینید .env یا یک API Key داخل Commit بوده است. غریزه میگوید سریع از آخرین Commit پاک کن یا Force Push کن تا کسی نبیند. طبق مستندات رسمی GitHub، اگر دادهٔ حساس از جنس Secret باشد، قدم اول ابطال یا چرخش (revoke/rotate) است — نه بازنویسی تاریخچه.
دلیل ساده است: تا وقتی کلید زنده است، هر کسی که Clone کرده، Fork گرفته، یا URL خام Commit را دیده ممکن است از آن استفاده کند. پاک کردن فایل از نوک شاخه، تاریخچه و کپیهای دیگر را پاک نمیکند.
این صفحه یک Runbook عملی است: تثبیت، چرخش، ارزیابی سوءاستفاده، تصمیم دربارهٔ پاکسازی تاریخچه، هماهنگی تیم، و جلوگیری از تکرار. دستورهای دقیق را همیشه با صفحهٔ رسمی Removing sensitive data همتراز کنید.

پاسخ کوتاه
۱) دامنه را مشخص کنید: چه Secretای، کدام مخزن و Branch، Public بود یا Private، چه زمانی Push شد. ۲) همان Secret را فوراً Revoke یا Rotate کنید. ۳) دسترسیهای وابسته را بررسی کنید. ۴) در صورت نیاز تاریخچه را با git-filter-repo پاک کنید — با آگاهی از عوارض Force Push و هماهنگی Cloneها. ۵) برای پاکسازی Cache و ارجاعات PR در GitHub، فقط طبق شرایط Support درخواست دهید. ۶) مانع تکرار شوید: gitignore، push protection، آموزش.
GitHub میگوید بعد از Rotate، همهٔ مراحل بازنویسی تاریخچه ممکن است دیگر ضروری نباشد. اولویت قطع دسترسی مهاجم است، نه زیبایی تاریخچه.
کلید زنده در تاریخچهٔ ظاهراً پاکشده هنوز خطر است؛ کلید مرده در تاریخچهٔ نازیبا اغلب مسئلهٔ امنیتی حاد نیست.
دقیقهٔ صفر تا پانزده: تثبیت
- نوع Secret را بنویسید: رمز دیتابیس، PAT، کلید ابر، درگاه پرداخت، توکن بات و مانند آن.
- محدوده را مشخص کنید: Hash Commit، Branch، Public یا Private، وجود Fork.
- اگر هنوز فقط Local است و Push نشده، تاریخچهٔ محلی را اصلاح کنید و Push نکنید؛ git revert برای حذف Secret مناسب نیست چون Commit اصلی میماند.
- اگر Push شده، مستقیم به پنل ارائهدهندهٔ همان Secret بروید — نه فقط به Git.
- در کانال خصوصی به Lead یا مسئول امنیت خبر دهید؛ جزئیات کلید را در Issue عمومی تکرار نکنید.
اگر secret scanning هشدار داده، همان را جدی بگیرید. طبق About secret scanning، اقدام اول Rotate است.
قدم اجباری: Rotate و Revoke
در پنل سرویس:
- کلید را باطل کنید یا کلید جدید بسازید و کلید قدیم را حذف کنید.
- رمز را عوض کنید و در صورت وجود، Sessionهای فعال را باطل کنید.
- Webhook Secret و امضاهای وابسته را هم بچرخانید.
- مقدار جدید را فقط در Secret store یا متغیر محیطی بگذارید — دوباره داخل Git نه.
راهنمای جلوگیری از نشت به امکان ابطال برخی توکنهای GitHub افشاشده از طریق API هم اشاره میکند. برای بقیهٔ Vendorها، پنل همان سرویس منبع حقیقت است. بعد از چرخش، یک Smoke Test در Staging و Production با کلید جدید انجام دهید تا قطعی طولانی نشود.
آیا باید تاریخچه را بازنویسی کنیم؟
مستندات Removing sensitive data عوارض جدی بازنویسی را فهرست میکند:
- ریسک آلودگی مجدد اگر کسی Clone قدیمی را Pull و سپس Push کند.
- ریسک از دست رفتن کار دیگران روی Branchهای همزمان.
- تغییر Hash همهٔ Commitهای بعدی و شکستن ابزار وابسته به SHA.
- نیاز احتمالی به خاموش کردن موقت Branch Protection برای Force Push.
- خراب شدن نمای Diff در PRهای بستهشدهٔ وابسته و سردرگمی PRهای باز.
- از بین رفتن امضای Commit و Tag در بسیاری از ابزارها.
- کاربران دقیق با Clone قدیمی میتوانند واگرایی تاریخچه را ببینند و دادهٔ حساس محلی را پیدا کنند.
اگر Secret دیگر زنده نیست و دادهٔ غیر Secret حساسی مثل PII انبوه در تاریخچه ندارید، گاهی Rotate کافی است. اگر رمز کاربران، کلید خصوصی بلندعمر، یا دادهٔ شخصی در Git رفته، پاکسازی جدیتر است.
اگر تصمیم به پاکسازی گرفتید
صفحهٔ رسمی چهار سطح بالا میشمارد: بازنویسی محلی با git-filter-repo، بهروزرسانی مخزن روی GitHub، هماهنگی پاکسازی Clone همکاران، و جلوگیری از تکرار.
- از نسخهٔ git-filter-repo با پشتیبانی --sensitive-data-removal استفاده کنید (مستند حداقل نسخهٔ 2.47 را ذکر میکند).
- مسیر فایل را دقیق بدهید؛ اگر فایل Rename شده، مسیرهای قدیمی را هم پوشش دهید یا متن را با --replace-text جایگزین کنید.
- قبل از Force Push، تعداد PRهای متأثر را از خروجی ابزار بسنجید؛ اگر غیرمنتظره زیاد بود، بازنویسی را دور بریزید.
- Force Push آینهای را فقط وقتی اجرا کنید که میفهمید همهٔ Branch و Tagهای مربوط بازنویسی میشوند.
- مراجع refs/pull/ را خودتان پاک نمیکنید؛ برای حذف Cache و ارجاعات PR از GitHub Support طبق شرایط کمک بگیرید.
- همکاران باید Clone را پاکسازی یا از نو Clone کنند؛ یک Merge از تاریخچهٔ آلوده میتواند Secret را برگرداند.
- اگر Forkها Commit آلوده دارند با مالکانشان هماهنگ کنید؛ GitHub اطلاعات تماس آنها را نمیدهد.
GitHub Support دادهٔ غیرحساس را حذف نمیکند و فقط وقتی کمک میکند که ریسک با چرخش اعتبارنامه قابل کاهش نباشد.
جدول اولویت واکنش
| وضعیت | اقدام فوری | پاکسازی تاریخچه |
|---|---|---|
| کلید تست بیاعتبار در Public | حذف از Tip و اطمینان از بیاعتباری | معمولاً اختیاری |
| API Key زندهٔ Production در Public | Rotate فوری و پایش سوءاستفاده | اغلب بله؛ Support در صورت نیاز |
| رمز دیتابیس در Private با دسترسی محدود | Rotate و بررسی Audit | موردی با هماهنگی تیم |
| PII مشتریان در Commit | محدود کردن دسترسی و مشاورهٔ امنیت | جدی با برنامهٔ رسمی |
| هنوز Push نشده | اصلاح تاریخچهٔ محلی؛ Push نکنید | نیاز به GitHub نیست |
پایش سوءاستفاده بعد از چرخش
- صورتحساب و لاگ دسترسی ابر یا درگاه پرداخت را برای بازهٔ نشت ببینید.
- نشستهای کاربر و توکنهای ثانویه را باطل کنید اگر ممکن است مشتق شده باشند.
- Webhookهای مشکوک و کلیدهای SSH/Deploy تازهساخته را بررسی کنید.
- اگر مخزن Public بود، فرض کنید خزندهٔ خودکار هم ممکن است دیده باشد — سرعت چرخش مهمتر از کامل بودن پاکسازی است.
ثبت زمانبندی حادثه (کشف، Rotate، اعلام داخلی) برای یادگیری بعدی و در صورت نیاز انطباق مفید است. جزئیات کلید را در تیکت عمومی ننویسید.
جلوگیری از تکرار
همان صفحهٔ حذف دادهٔ حساس و راهنمای جلوگیری از نشت، پیشگیری را تکرار میکنند:
- نام فایلهای پرریسک را به .gitignore اضافه کنید و Commit کنید.
- Secret را hard-code نکنید؛ از env یا Secret manager استفاده کنید.
- pre-commit hookهایی مثل gitleaks یا git-secrets را برای همهٔ همکاران فعال کنید.
- از git add . کورکورانه بپرهیزید؛ diff استیجشده را بخوانید.
- Push protection را برای مخزن و کاربر فعال نگه دارید.
- Branch Protection و Review اجباری برای مسیرهای حساس بگذارید.
ارتباط با تیم و ذینفعان
پیام داخلی کوتاه بهتر از سکوت است: چه چیزی لو رفت، آیا Rotate شد، آیا کاربر نهایی اثر میبیند، و چه کارهایی از دیگران خواسته میشود (مثلاً re-clone). شرم فردی را از یادگیری تیمی جدا کنید؛ تنبیه علنی باعث مخفیکاری حوادث بعدی میشود.
اگر دادهٔ مشتری یا الزام قراردادی در میان است، مسیر امنیتی/حقوقی سازمان را زود وارد کنید — این مقاله جایگزین آن نیست.
جمعبندی برای تصمیم
بعد از Push اشتباه Secret: اول کلید را بکشید، بعد دربارهٔ زیبایی تاریخچه حرف بزنید. بازنویسی با git-filter-repo واقعی و رسمی است ولی پرهزینه و پرعارضه است. Support گیتهاب Cache و PR را فقط در شرایط حساس تمیز میکند. پیشگیری با push protection و عادت Commit ارزانتر از هر Runbook است.
یک برگهٔ یکصفحهای از این ترتیب را در Wiki تیم بگذارید تا نیمهشب کسی به سراغ «فقط amend» نرود.
نمونهٔ تایملاین یک ساعت اول
دقیقهٔ صفر تا پنج: تأیید کنید Secret واقعی است نه false positive. دقیقهٔ پنج تا بیست: Rotate در پنل Vendor و بهروزرسانی envهای Deploy. دقیقهٔ بیست تا چهل: بررسی لاگ سوءاستفاده و قطع Sessionهای مشکوک. دقیقهٔ چهل تا شصت: تصمیم بگیرید آیا بازنویسی تاریخچه لازم است و چه کسانی باید Clone را عوض کنند. نوشتن این تایملاین روی کاغذ قبل از حادثه، در شب حادثه طلاست.
ارتباط با مشتری و حقوقی
اگر دادهٔ مشتری یا کلید دسترسی به سیستم مشتری در میان است، مسیر اعلام را از روی قرارداد و سیاست حریم خصوصی بخوانید — نه از روی حس. این مقاله جایگزین مشاورهٔ حقوقی نیست. آنچه از زاویهٔ مهندسی قطعی است: تأخیر در Rotate معمولاً بدتر از اعلام داخلی سریع است.
در پیام بیرونی جزئیات فنی Exploit را بیش از حد لازم فاش نکنید؛ روی اثر، اقدام انجامشده و مسیر پشتیبانی تمرکز کنید.
ابزارهایی که مردم اشتباه استفاده میکنند
- git revert: Secret را در تاریخچه نگه میدارد.
- حذف فایل در Commit جدید بدون Rotate: کلید هنوز زنده است.
- Force Push تنها روی یک Branch وقتی Secret در Tag یا Branch دیگر هم هست.
- بستن مخزن یا Private کردن بهجای Rotate پس از نشت Public.
هر کدام ممکن است بخشی از آلودگی را کم کنند ولی جایگزین قدم اجباری ابطال اعتبارنامه نیستند.
تمرین آمادگی
مثل Fire Drill: یک کلید جعلی را عمداً در مخزن آزمایشی Push کنید، هشدار و مسدودسازی را ببینید، و جدول واکنش را زمانگیری کنید. هرگز Drill را روی کلید Production واقعی انجام ندهید. هدف عضلهٔ حافظه است نه تولید حادثه.
بعد از بسته شدن حادثه
- یک صفحهٔ کوتاه Postmortem بدون سرزنش: ریشه، تشخیص، اثر، اقدام اصلاحی.
- اگر gitignore یا CI کمبود داشت، همان Sprint درستش کنید.
- اگر Bypass بیرویه بود، delegated bypass یا آموزش را بررسی کنید.
- تاریخ Rotate و شمارههای تیکت Vendor را بایگانی کنید.
منابع و مراجع
- GitHub Docs — Removing sensitive data from a repository — https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository
- GitHub Docs — About secret scanning — https://docs.github.com/en/code-security/secret-scanning/introduction/about-secret-scanning
- GitHub Docs — Push protection — https://docs.github.com/en/code-security/concepts/secret-security/push-protection
- GitHub Docs — Best practices for preventing data leaks in your organization — https://docs.github.com/en/code-security/getting-started/best-practices-for-preventing-data-leaks-in-your-organization
دستورها و نام UI ممکن است با زمان عوض شوند؛ قبل از Force Push روی مخزن اصلی، صفحهٔ رسمی را دوباره باز کنید.
Author
Soheil Ebrahimpour is the founder of FutureForge. He works on product design, architecture, and getting custom software into production.
Related notes
If you are unsure about architecture or the build path, we can talk about the project.
Describe the problem and the constraints. If there is a fit, we will schedule a conversation.




