Coordinated Disclosure Timeline
- 2020-11-30: Report sent to maintainer.
- 2021-01-23: Issue resolved.
Summary
The design and promoted usage examples of afc163/surge-preview GitHub action makes the consuming workflows vulnerable to arbitrary code execution. The repository of afc163/surge-preview GitHub action falls into the same trap and is vulnerable to arbitrary code execution.
Product
afc163/surge-preview action and GitHub repository
Tested Version
The latest changeset 33b194b to the date.
Details
pull_request_target
was introduced to allow triggered workflows to comment on PRs, label them, assign people, etc.. In order to make it possible the triggered action runner has read/write token for the base repository and the access to secrets. In order to prevent untrusted code from execution it runs in a context of the base repository.
By explicitly checking out and running build script from a fork the untrusted code is running in an environment that is able to push to the base repository and to access secrets.
Issue 1: afc163/surge-preview GitHub action is designed to run potentially untrusted code from a Pull Request on pull_request_target
Below is an excerpt from an example of usage in the documentation:
on: pull_request_target
...
- uses: actions/checkout@v2
with:
ref: refs/pull/${{ github.event.pull_request.number }}/merge
- uses: afc163/surge-preview@v1
id: preview_step
with:
surge_token: ${{ secrets.SURGE_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
dist: public
build: |
npm install
npm run build
...
Since the action needs the SURGE_TOKEN
for functioning and worklows triggered on pull_request
do not have the access to secrets it promotes using pull_request_target
and explicitly checking out the code from the Pull Request. One of the action’s arguments is a build
script that instructs the action how to build the source. If the argument is not provided it uses npm install & npm run build
by default:
...
build:
description: 'build scripts'
default: |
npm install
npm run build
required: false
...
A potentially untrusted Pull Request may execute an arbitrary script in a workflow that has read/write repository access and potentially can access secrets.
Impact
The vulnerability allows for unauthorized modification of the using repository and secrets exfiltration.
Issue 2: Untrusted code is explicitly checked out and run on a Pull Request from a fork
The action’s repositry itself has a Pull Request workflow:
pull_request_target:
# use default types + closed event type
types: [opened, synchronize, reopened, closed]
...
- uses: actions/checkout@v2
with:
ref: refs/pull/${{ github.event.pull_request.number }}/merge
- uses: ./
id: preview_step
name: test afc163/surge-preview
with:
surge_token: ${{ secrets.SURGE_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
teardown: 'true'
dist: public/preview
build: |
mkdir -p public/preview
npm install
npm run build-preview -- public/preview
...
Impact
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-2020-266
in any communication regarding this issue.