Coordinated Disclosure Timeline

Summary

The zwave-js-bot.yml GitHub workflow is vulnerable to unauthorized modification of the base repository or secrets exfiltration.

Product

zwave-js/zwavejs2mqtt repository

Tested Version

The latest changeset of zwave-js-bot.yml to the date.

Details

Issue 1: A specific comment triggers a potentially untrusted pull request build in a privileged environment

When a user comments on a pull request with @zwave-js-bot fix lint it triggers the following workflow which checks out the pull request and builds the potentially untrusted code:

on:
  issue_comment:
    types: [created] # edited, deleted
...
  # Fix lint errors when an authorized person posts "@zwave-js-bot fix lint"
  fix-lint:
    if: |
      contains(github.event.issue.html_url, '/pull/') &&
      contains(github.event.comment.body, '@zwave-js-bot fix lint') &&
      (github.event.comment.user.login != 'zwave-js-bot') && github.event.comment.user.login != 'zwave-js-assistant[bot]'
...
      - name: Check user's permissions to do this
        id: check
        uses: actions/github-script@v3
        with:
          github-token: ${{secrets.BOT_TOKEN}}
          result-encoding: string
          script: |
            const bot = require(`${process.env.GITHUB_WORKSPACE}/.github/bot-scripts/index.js`);
            return await bot.checkAuthorized({github, context});
...
      - name: Checkout pull request
        if: steps.check.outputs.result == 'true'
        uses: actions/checkout@v2
        with:
          token: ${{secrets.BOT_TOKEN}}
          repository: ${{ fromJSON(steps.get-pr.outputs.result).head.repo.full_name }}
          ref: ${{ fromJSON(steps.get-pr.outputs.result).head.ref }}
...
      - name: Install dependencies
        if: steps.check.outputs.result == 'true'
        run: npm install

The checkAuthorized script verifies that the user is authorized to trigger the workflow. However it also allows the pull request author to trigger the workflow:

if (context.payload.issue.html_url.includes("/pull/")) {
  console.log("Comment appears in a PR, retrieving PR info...");
  // Only the pull request author and authorized users may execute this command
  const { data: pull } = await github.pulls.get({
    ...options,
    pull_number: context.payload.issue.number,
  });

  const allowed = [...authorizedUsers, pull.user.login];
  const commenting = context.payload.comment.user.login;
  console.log(`Authorized users: ${allowed.join(", ")}`);
  console.log(`Commenting user: ${commenting}`);
  const isAuthorized = allowed.includes(commenting);
  console.log(`Is authorized: ${isAuthorized}`);

  if (!isAuthorized) return false;
} else {
  // In issues, only the authorized users may execute any commands

Impact

The triggered workflow has access to the write repository token and secrets. The vulnerability allows for unauthorized modification of the base repository and secrets exfiltration.

Issue 2: A branch name and title from pull request are used to format inline script

on:
  issue_comment:
    types: [created] # edited, deleted
...
      - name: Rebase the branch
        if: steps.check-permissions.outputs.result == 'true'
        id: fix
        run: |
          # Try to rebase
          if git rebase "${{ fromJSON(steps.get-pr.outputs.result).base.ref }}"" ; then
...
      - name: Rebase the branch
        if: steps.check-permissions.outputs.result == 'true'
        id: fix
        run: |
          # Try to reword the commit
          git config user.email "bot@zwave.js"
          git config user.name "Z-Wave JS Bot"
          if git commit --amend -m "${{ fromJSON(steps.get-pr.outputs.result).title }}" ; then

The expression evaluation is vulnerable to inline script injection.

Impact

The triggered workflow has access to the write repository token and secrets. The vulnerability allows for unauthorized modification of the base repository and secrets exfiltration.

Credit

This issue was discovered and reported by GHSL team member @JarLob (Jaroslav Lobačevski).

Contact

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