Gh Actions - Context Script Injections
Reading time: 5 minutes
tip
Impara e pratica il hacking AWS: HackTricks Training AWS Red Team Expert (ARTE)
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:  HackTricks Training GCP Red Team Expert (GRTE)
HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure:
Impara e pratica il hacking Azure:  HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos su github.
Comprendere il rischio
GitHub Actions valuta le espressioni ${{ ... }} prima che lo step venga eseguito. Il valore valutato viene inserito nel programma dello step (per i run steps, uno script shell). Se interpoli input non attendibile direttamente dentro run:, l'attaccante controlla parte del programma shell e può eseguire comandi arbitrari.
Docs: https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions and contexts/functions: https://docs.github.com/en/actions/learn-github-actions/contexts
Punti chiave:
- La valutazione (rendering) avviene prima dell'esecuzione. Lo script di run viene generato con tutte le espressioni risolte, poi eseguito dalla shell.
- Molti contexts contengono campi controllati dall'utente a seconda dell'evento che attiva il workflow (issues, PRs, comments, discussions, forks, stars, ecc.). Vedi il riferimento sull'input non attendibile: https://securitylab.github.com/resources/github-actions-untrusted-input/
- L'escaping/quoting della shell dentro run: non è una difesa affidabile, perché l'iniezione avviene nella fase di rendering del template. Gli attaccanti possono uscire dalle virgolette o iniettare operatori mediante input appositamente creato.
Pattern vulnerabile → RCE sul runner
Workflow vulnerabile (triggerato quando qualcuno apre una nuova issue):
name: New Issue Created
on:
issues:
types: [opened]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: New issue
run: |
echo "New issue ${{ github.event.issue.title }} created"
- name: Add "new" label to issue
uses: actions-ecosystem/action-add-labels@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
labels: new
Se un attacker apre un issue intitolato $(id), lo step renderizzato diventa:
echo "New issue $(id) created"
La command substitution esegue id sul runner. Esempio di output:
New issue uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),100(users),999(systemd-journal) created
Perché l'uso delle virgolette non ti salva:
- Le espressioni vengono renderizzate per prime, poi viene eseguito lo script risultante. Se il valore non attendibile contiene $(...), ;,"/', o newlines, può alterare la struttura del programma nonostante le tue virgolette.
Pattern sicuro (shell variables via env)
Mitigazione corretta: copia l'input non attendibile in una variabile di ambiente, quindi usa l'espansione nativa della shell ($VAR) nello script di run. Non reinserire con ${{ ... }} all'interno del comando.
# safe
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: New issue
env:
TITLE: ${{ github.event.issue.title }}
run: |
echo "New issue $TITLE created"
Note:
- Evita di usare ${{ env.TITLE }} dentro run:. Questo reintroduce il rendering dei template nel comando e comporta lo stesso rischio di injection.
- Preferisci passare input non attendibili tramite la mappatura env: e riferirli con $VAR in run:.
Superfici attivabili da utenti esterni (trattare come non attendibili)
Account con solo permesso di lettura sui repository pubblici possono comunque innescare molti eventi. Qualsiasi campo nei contesti derivati da questi eventi deve essere considerato controllato dall'attaccante a meno che non sia dimostrato il contrario. Esempi:
- issues, issue_comment
- discussion, discussion_comment (orgs can restrict discussions)
- pull_request, pull_request_review, pull_request_review_comment
- pull_request_target (pericoloso se usato in modo errato, viene eseguito nel contesto del repository base)
- fork (chiunque può forkare repository pubblici)
- watch (starring a repo)
- Indirettamente tramite catene workflow_run/workflow_call
Quali campi specifici sono controllati dall'attaccante dipende dall'evento. Consulta la guida di GitHub Security Lab sugli input non attendibili: https://securitylab.github.com/resources/github-actions-untrusted-input/
Suggerimenti pratici
- Minimizza l'uso di espressioni all'interno di run:. Preferisci la mappatura env: + $VAR.
- Se devi trasformare l'input, fallo nella shell usando strumenti sicuri (printf %q, jq -r, ecc.), sempre partendo da una variabile di shell.
- Fai particolare attenzione quando interpoli nomi dei branch, titoli delle PR, username, label, titoli delle discussion e PR head refs in script, flag della riga di comando o percorsi di file.
- Per reusable workflows e composite actions, applica lo stesso schema: mappa su env e poi riferiscilo con $VAR.
Riferimenti
- GitHub Actions: A Cloudy Day for Security - Part 1
- GitHub workflow syntax
- Contexts and expression syntax
- Untrusted input reference for GitHub Actions
tip
Impara e pratica il hacking AWS: HackTricks Training AWS Red Team Expert (ARTE)
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:  HackTricks Training GCP Red Team Expert (GRTE)
HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure:
Impara e pratica il hacking Azure:  HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos su github.
 HackTricks Cloud
HackTricks Cloud