Proper Github Workflow Security

Base Metricscoreseverity
overall0none

Type: Investigated

Status: fixed

Reporting Date: 2023.04.05

The github action workflows were checked for usage of risky patterns, handling community contributions where workflows are triggered with pull_request and were found to be properly implemented.

Description

The initial check of the .workflows directory indicated that some workflows are run as soon as a pull request is created.

We consulted the github documentation for the usage of pull_request and found the usage to be without immediate risks, as only pull_request_target with an explicit checkout of an untrusted pull request directly exposes the GITHUB_TOKEN1 by default. The current instance does not facilitate the vulnerable combination.

Due to the dangers inherent to automatic processing of PRs, GitHub’s standard pull_request workflow trigger by default prevents write permissions and secrets access to the target repository. However, in some scenarios such access is needed to properly process the PR. To this end the pull_request_target workflow trigger was introduced. 2

Proof of Concept

To simplify the understanding a small proof of concept was created. The following steps verify that secrets configured in the repository are not leaked when a PR triggers a specific workflow file, that has been modified by a potential attacker.

Create initial workflow .github/workflow/leaky.yml file on main

name: leaky secret test

on:
  pull_request:
    branches: [ "main" ]
    paths:
      - ".github/workflows/leaky.yml"
     
jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: checkout
        uses: actions/checkout@v3
        
      - name: Run a one-line script
        run: echo Hello, world!

Create PR with following changes

name: leaky secret test

on:
  pull_request:
    branches: [ "main" ]
    paths:
      - ".github/workflows/leaky.yml"
     
jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: checkout
        uses: actions/checkout@v3
        
      - name: Run a one-line script
        run: |
          printf "Got secret: '%s'\n" ${{ secrets.SUPER_SECRET_VALUE }}

The action is being run with following output

Run printf "Got secret: '%s'\n" ***
  printf "Got secret: '%s'\n" ***
  shell: /usr/bin/bash -e {0}
Got secret: '***'