yaml.github-actions.security.workflow-run-target-code-checkout.workflow-run-target-code-checkout

profile photo of semgrepsemgrep
Author
unknown
Download Count*

This GitHub Actions workflow file uses workflow_run and checks out code from the incoming pull request. When using workflow_run, the Action runs in the context of the target repository, which includes access to all repository secrets. Normally, this is safe because the Action only runs code from the target repository, not the incoming PR. However, by checking out the incoming PR code, you're now using the incoming code for the rest of the action. You may be inadvertently executing arbitrary code from the incoming PR with access to repository secrets, which would let an attacker steal repository secrets. This normally happens by running build scripts (e.g., npm build and make) or dependency installation scripts (e.g., python setup.py install). Audit your workflow file to make sure no code from the incoming PR is executed. Please see https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ for additional mitigations.

Run Locally

Run in CI

Defintion

rules:
  - id: workflow-run-target-code-checkout
    languages:
      - yaml
    message: This GitHub Actions workflow file uses `workflow_run` and checks out
      code from the incoming pull request. When using `workflow_run`, the Action
      runs in the context of the target repository, which includes access to all
      repository secrets. Normally, this is safe because the Action only runs
      code from the target repository, not the incoming PR. However, by checking
      out the incoming PR code, you're now using the incoming code for the rest
      of the action. You may be inadvertently executing arbitrary code from the
      incoming PR with access to repository secrets, which would let an attacker
      steal repository secrets. This normally happens by running build scripts
      (e.g., `npm build` and `make`) or dependency installation scripts (e.g.,
      `python setup.py install`). Audit your workflow file to make sure no code
      from the incoming PR is executed. Please see
      https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
      for additional mitigations.
    metadata:
      category: security
      owasp: A01:2017 - Injection
      cwe: "CWE-913: Improper Control of Dynamically-Managed Code Resources"
      likelihood: MEDIUM
      impact: MEDIUM
      confidence: MEDIUM
      subcategory:
        - vuln
      references:
        - https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
        - https://github.com/justinsteven/advisories/blob/master/2021_github_actions_checkspelling_token_leak_via_advice_symlink.md
        - https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability
      technology:
        - github-actions
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Code Injection
    patterns:
      - pattern-inside: |
          on:
            ...
            workflow_run: ...
            ...
          ...
      - pattern-inside: |
          jobs:
            ...
            $JOBNAME:
              ...
              steps:
                ...
      - pattern: |
          ...
          uses: "$ACTION"
          with:
            ...
            ref: $EXPR
      - metavariable-regex:
          metavariable: $ACTION
          regex: actions/checkout@.*
      - metavariable-pattern:
          language: generic
          metavariable: $EXPR
          patterns:
            - pattern: ${{ github.event.workflow_run ... }}
    severity: WARNING

Examples

workflow-run-target-code-checkout.test.yaml

on:
  # pull_request_target:
  workflow_run:
    workflows: ["smth-else"]
    types:
    - completed
  pull_request:

jobs:
  build:
    name: Build and test
    runs-on: ubuntu-latest
    steps:
      # ruleid: workflow-run-target-code-checkout
      - uses: actions/checkout@v2
        with:
          ref: ${{ github.event.workflow_run.head.sha }}

      - uses: actions/setup-node@v1
      - run: |
          npm install
          npm build

      - uses: completely/fakeaction@v2
        with:
          arg1: ${{ secrets.supersecret }}

      - uses: fakerepo/comment-on-pr@v1
        with:
          message: |
            Thank you!

  build2:
    name: Build and test 2
    runs-on: ubuntu-latest
    steps:
      # ruleid: workflow-run-target-code-checkout
      - uses: actions/checkout@v2.3.4
        with:
          ref: ${{ github.event.workflow_run.head.sha }}

      - uses: actions/setup-node@v1
      - run: |
          npm install
          npm build

      - uses: completely/fakeaction@v2
        with:
          arg1: ${{ secrets.supersecret }}

      - uses: fakerepo/comment-on-pr@v1
        with:
          message: |
            Thank you!

  this-is-safe-because-no-checkout:
    name: Echo
    runs-on: ubuntu-latest
    steps:
      # ok: workflow-run-target-code-checkout
      - name: echo
        run: |
          echo "Hello, world"

  spelling:
    name: Spell checking
    runs-on: ubuntu-latest
    steps:
      # ruleid: workflow-run-target-code-checkout
      - name: checkout-merge
        if: contains(github.event_name, 'pull_request')
        uses: actions/checkout@v2
        with:
          ref: refs/pull/${{github.event.workflow_run.number}}/merge