Next Generation SQL Injection: Github Actions Edition

Alonso Suarez - Jun 7 - - Dev Community

In the evolving landscape of software development, Continuous Integration and Continuous Deployment (CI/CD) tools like GitHub Actions have become indispensable. However, with great power comes great responsibility, and it's crucial to be aware of potential security pitfalls. One such vulnerability is treating untrusted inputs, such as branch names or pull request (PR) titles, as static parameters.
Spoiler alert, they should NOT be trusted

I enjoy puzzles, so here goes one:

steps:
  - name: Generate summary
    run: |
      echo "Pull Request for [${{ github.event.pull_request.title }}](https://github.com/${{ github.repository }}/pull/${{ github.event.pull_request.number }}) has been updated 🎉" >> $GITHUB_STEP_SUMMARY
      echo "Image tagged **v${{ needs.determine_app_version.outputs.app_version }}** has been built and pushed to the registry." >> $GITHUB_STEP_SUMMARY
This will generate a workflow summary like:
Enter fullscreen mode Exit fullscreen mode

Can you spot the vulnerability?

The Problem

When a developer clicks on the Revert PR button in GitHub, the new PR title is Revert "<OLD TITLE>". This breaks the Generate summary step.

Try again if you haven’t spotted the vulnerability

The vulnerability lies in how github.event.pull_request.title input is handled. GitHub Actions expressions dynamically generate code. Unfortunately, if the PR title contains any special characters or unexpected input, it can cause the script to fail or behave unexpectedly.

The Impact

When developers click on Revert PR button, the PR title is Revert "<OLD TITLE>", the echo command in the Generate summary step generates the bash command:

echo "Pull Request for [Revert "<OLD TITLE>"](https://github.com/${{ github.repository }}/pull/${{ github.event.pull_request.number }}) has been updated 🎉" >> $GITHUB_STEP_SUMMARY
Enter fullscreen mode Exit fullscreen mode

The presence of the double quotes within the PR title closes the echo early. However, this allows for bad actors to craft a title that could be used take full control of the runner

The Solution

To prevent this issue, one approach is to use env as an input “encoder” and avoid directly using GitHub Actions ${{ }} expressions. For example:

env:
  TITLE: ${{ github.event.pull_request.title }}
steps:
  - name: Generate summary
    run: |
      echo "Pull Request for [$TITLE](https://github.com/${{ github.repository }}/pull/${{ github.event.pull_request.number }}) has been updated 🎉" >> $GITHUB_STEP_SUMMARY
Enter fullscreen mode Exit fullscreen mode

By using the env context to store untrusted inputs, you avoid potential script-breaking issues caused by special characters pre-rendered by Github Actions.

Leave a comment if you can think on a different way to solve this problem!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .