Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion checks/raw/dangerous_workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ func containsUntrustedContextPattern(variable string) bool {
if strings.Contains(variable, "github.head_ref") {
return true
}
return strings.Contains(variable, "github.event.") && untrustedContextPattern.MatchString(variable)
return strings.Contains(variable, "github.event.") &&
(untrustedContextPattern.MatchString(variable) ||
untrustedContextPattern.MatchString(fmt.Sprintf("toJSON(%s)", variable)))
Comment on lines +55 to +57
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't work as expected for the small example Pedro showed in his issue. I was curious about toJSON(github), which also ends up being vulnerable. But not every toJSON call would be vulnerable, only examples that are less specific. For example
toJSON(github.event.pull_request.state) should be declared as safe (though this is contrived)

Here's a patch with a test I was trying. As well as the example in my test repo (workflow now disabled):
https://github.com/spencerschrock/actions-test/actions/runs/17951418605/job/51051442328

diff --git a/checks/dangerous_workflow_test.go b/checks/dangerous_workflow_test.go
index 15befe75..58e4fb04 100644
--- a/checks/dangerous_workflow_test.go
+++ b/checks/dangerous_workflow_test.go
@@ -72,6 +72,15 @@ func TestDangerousWorkflow(t *testing.T) {
 				Score: checker.MaxResultScore,
 			},
 		},
+		{
+			name:          "toJSON injection is a failing score",
+			workflowPaths: []string{".github/workflows/github-workflow-dangerous-toJSON.yml"},
+			err:           nil,
+			expected: scut.TestReturn{
+				Score:        checker.MinResultScore,
+				NumberOfWarn: 2,
+			},
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/checks/testdata/.github/workflows/github-workflow-dangerous-toJSON.yml b/checks/testdata/.github/workflows/github-workflow-dangerous-toJSON.yml
new file mode 100644
index 00000000..c986aa08
--- /dev/null
+++ b/checks/testdata/.github/workflows/github-workflow-dangerous-toJSON.yml
@@ -0,0 +1,11 @@
+on:
+  pull_request_target:
+
+jobs:
+  get-pwned:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Log event and get pwned
+        run: |
+          echo '${{ toJSON(github.event) }}' | jq
+          echo '${{ toJSON(github) }}' | jq

}

type triggerName string
Expand Down
7 changes: 7 additions & 0 deletions checks/raw/dangerous_workflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package raw
import (
"context"
"errors"
"fmt"
"io"
"os"
"testing"
Expand Down Expand Up @@ -83,6 +84,12 @@ func TestUntrustedContextVariables(t *testing.T) {
if r := containsUntrustedContextPattern(tt.variable); !r == tt.expected {
t.Fail()
}
if r := containsUntrustedContextPattern(fmt.Sprintf("toJSON(%s)", tt.variable)); !r == tt.expected {
t.Fail()
}
if r := containsUntrustedContextPattern(fmt.Sprintf("toJSON( %s )", tt.variable)); !r == tt.expected {
t.Fail()
}
})
}
}
Expand Down
Loading