سختکردن GitHub Actions در برابر حملههای بیرونی
خلاصهٔ کاملتر
به گفتهٔ نویسندهٔ Socket، حملههای زنجیرهٔ تأمین ۲۰۲۵ و ۲۰۲۶ بیشتر از دل پکیجهای معتبر و پرمصرف اومدن، نه از پکیجهای جعلی. کد مخرب موقع release وارد شده و اغلب این release روی GitHub Actions اجرا میشده. نمونههاش tj-actions/changed-files، Nx s1ngularity، Shai-Hulud، trivy-action، axios، TanStack Router و LiteLLM 1.107.0 هستن. این مقاله قسمت اول یه مجموعهست و فقط مهاجمی رو بررسی میکنه که هیچ credentialی از سازمان تو نداره.
قدم اول: اکشنها رو با تگ صدا نزن. وقتی مینویسی owner/action@v4، اون تگ یه اشارهگر قابل جابهجاییه و هر کی حساب نگهدارنده رو بدزده میتونه اونو به یه commit دیگه ببره. تو مارس ۲۰۲۵ همین بلا سر tj-actions/changed-files اومد (CVE-2025-30066): حدود ۲۳ هزار مخزن تحت تأثیر بودن و هر کی با SHA پین کرده بود سالم موند. نویسنده پیشنهاد میکنه از workflow lockfile استفاده کنی، یعنی فایلی که gh actions-lock میسازه و commit هر اکشن، حتی اکشنهای تودرتو، رو ثبت و موقع اجرا چک میکنه.
این lockfile چند تا محدودیت داره: reusable workflowها، اکشنهای محلی ./، container imageها و GitHub Enterprise Server رو پوشش نمیده و اونجا باید هنوز با SHA پین کنی. خود SHA هم فقط ثابت بودن رو تضمین میکنه نه منشأ رو؛ چون commitی که تو یه fork push شده از آدرس مخزن اصلی هم قابل دسترسیه (بهش impostor commit میگن). یه cooldown هم بذار: Wiz تخمین میزنه تأخیر ۷ تا ۱۴ روزه جلوی ۸۰ تا ۹۰ درصد این حملهها رو میگیره.
قدم دوم: GITHUB_TOKEN رو بدون دسترسی شروع کن. سازمانهایی که قبل از فوریهٔ ۲۰۲۳ ساخته شدن بهصورت پیشفرض به این توکن دسترسی نوشتن میدن. نویسنده میگه این توکن تقریباً تو همهٔ زنجیرههای حمله مرحلهٔ ارتقای دسترسی بوده، مثل Ultralytics و Nx. راهحل اینه که پیشفرض سازمان رو read-only کنی، بالای workflow بنویسی permissions: {} و برای هر job فقط حداقل لازم رو بدی:
permissions: {}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: readقدم سوم: کد ناشناس رو تو pull_request_target بیلد نکن. این trigger تو context دارای دسترسی مخزن اصلی اجرا میشه، پس اگه کد PR یه fork رو checkout و اجرا کنی، secretها لو میرن. به گفتهٔ مقاله این پرسوءاستفادهترین اشتباه تو GitHub Actions هست؛ Ultralytics با cache poisoning یه ماینر رو تو نسخههای 8.3.41 و 8.3.42 منتشر کرد و TanStack هم ۸۴ نسخهٔ مخرب تو ۴۲ پکیج داد. راهحل اینه که از pull_request معمولی استفاده کنی و کار دارای دسترسی رو تو یه job جدا با workflow_run انجام بدی. انتشار هم باید تو job جدایی باشه که کد پروژه رو اجرا نمیکنه. GitHub از ۲ دسامبر ۲۰۲۶ مسدودکردن pull_request_target رو روی مخزنهای عمومی اجباری میکنه.
نکات کلیدی:
- تگهایی مثل @v4 قابل جابهجاییان؛ تو حملهٔ tj-actions حدود ۲۳ هزار مخزن درگیر شدن
- gh actions-lock فایل actions.lock میسازه و اکشنهای تودرتو رو هم قفل میکنه
- lockfile روی GitHub Enterprise Server و reusable workflowها کار نمیکنه و اونجا باید SHA پین کنی
- cooldown بین ۷ تا ۱۴ روز طبق تخمین Wiz جلوی ۸۰ تا ۹۰ درصد حملهها رو میگیره
- با permissions: {} شروع کن و برای هر job حداقل دسترسی رو بده
- اجرای اجباری مسدودسازی pull_request_target روی مخزنهای عمومی از ۲ دسامبر ۲۰۲۶




