تخطَّ إلى المحتوى

pull_request_target

أمان pull_request_target وPwn Requests pull_request_target

pull_request_target يشغّل الـ workflow بصلاحيات المستودع الأساسي كاملة (أسرار وGITHUB_TOKEN) حتى لو كان الـ pull request قادماً من fork لا يُوثق به، وهو ما يجعله خطراً إذا شُغِّل كود الـ PR نفسه ضمنه.

بعكس pull_request العادي الذي يعمل في بيئة معزولة بلا وصول للأسرار عند قدوم الـ PR من fork، pull_request_target يمنح الـ workflow صلاحيات المستودع الأساسي كاملة دائماً، بغض النظر عن مصدر الـ pull request. هذا الفرق مقصود ومفيد لحالات محددة (مثل إضافة تعليق أو تسمية تلقائية على الـ PR)، لكنه يتحول لثغرة فعلية إن سحب الـ workflow كود الـ pull request نفسه (عبر ref: github.event.pull_request.head.sha) ثم شغّله — لأن أي كود ضمن ذلك الـ PR يُنفَّذ حينها بنفس الأسرار والتوكن الكاملين. هذا النمط يُعرف باسم pwn request وكان سبباً جذرياً لعدة حوادث سلسلة توريد فعلية.

منذ منتصف 2026، أصبح actions/checkout (من الإصدار v7 فما فوق، ومدعوم لاحقاً بالتراجع backport على إصدارات أقدم) يرفض افتراضياً سحب كود fork pull request ضمن workflows تعمل بـ pull_request_target أو workflow_run (عند حدث pull_request أصلي)، ما لم يُفعَّل ذلك صراحة بمدخل allow-unsafe-pr-checkout.

الصياغة

on: pull_request_target
jobs:
  <اسم>:
    steps:
      - uses: actions/checkout@v7
        with:
          persist-credentials: false

📄 مثال

# آمن: pull_request_target بدون سحب كود الـ PR نفسه
on: pull_request_target

jobs:
  label:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7   # يسحب فرع المستودع الأساسي فقط، لا كود الـ PR
        with:
          persist-credentials: false
      - run: echo "معالجة بيانات وصفية للـ PR فقط، لا كود المساهم"

أهم النقاط

العنصرالوظيفة
pull_request_targetيعمل بصلاحيات المستودع الأساسي كاملة (أسرار وGITHUB_TOKEN) بغض النظر عن مصدر الـ PR
pull_requestيعمل بمعزل عن الأسرار عند قدوم الـ PR من fork — الخيار الآمن الافتراضي لتشغيل كود المساهمين
allow-unsafe-pr-checkoutمدخل صريح في actions/checkout يجب تفعيله عمداً للسماح بسحب كود fork ضمن pull_request_target بعد مراجعة المخاطر
persist-credentialsعند true (الافتراضي) يترك GITHUB_TOKEN معداً على الـ runner لأي أمر git لاحق؛ عطّله إلى false إن لم تحتج push

💡 نصائح عملية

  • إن لم تكن متأكداً من حاجتك لـ pull_request_target، استخدم pull_request العادي — الفرق بينهما جوهري وليس تفصيلاً بسيطاً
  • استخدم workflow_run كبديل أكثر أماناً عندما تحتاج فعلياً تشغيل كود من fork لكن بصلاحيات منفصلة عن job يقرأ النتائج لاحقاً

⚠️ أخطاء شائعة

  • سحب github.event.pull_request.head.sha ضمن workflow يعمل بـ pull_request_target ثم تشغيل ذلك الكود (npm test، build...) — هذا هو نمط pwn request بالضبط
  • ترك persist-credentials على true افتراضياً حتى في jobs لا تحتاج push أو commit فعلي لاحقاً

🎓 تريد فهم الصورة الكاملة خطوة بخطوة؟ ابدأ من مسار DEVOPS الكامل بالعربي.

📚 للتعمق التقني الكامل بالإنجليزية: MDN Web Docs