Skip to content

Commit 34c989c

Browse files
Zohayb BhattiZohayb Bhatti
authored andcommitted
security: Add repository and branch validation for workflow_run triggers
- Validate workflow_run is from same repository (not a fork) - Validate branch is in allowed list (main/develop) - Validate SHA format before use - Addresses Kusari security concerns about workflow_run triggers - Maintains workflow chaining while adding security checks
1 parent 15c6b8b commit 34c989c

File tree

4 files changed

+89
-9
lines changed

4 files changed

+89
-9
lines changed

.github/workflows/build-binaries.yml

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,34 @@ jobs:
3939
arch: amd64
4040
output: github-repo-windows-amd64.exe
4141
steps:
42-
- name: Check if lint workflow passed
42+
- name: Validate workflow_run security
4343
if: github.event_name == 'workflow_run'
4444
uses: actions/github-script@v7
4545
with:
4646
script: |
47-
const headSha = context.payload.workflow_run?.head_sha;
47+
const workflowRun = context.payload.workflow_run;
48+
49+
// Validate workflow_run is from the same repository (not a fork)
50+
if (!workflowRun || workflowRun.repository.full_name !== context.repo.owner + '/' + context.repo.repo) {
51+
core.setFailed('Security: workflow_run must be from the same repository');
52+
return;
53+
}
54+
55+
// Validate head SHA format
56+
const headSha = workflowRun.head_sha;
4857
if (!headSha || !/^[a-f0-9]{40}$/i.test(headSha)) {
49-
core.setFailed('Invalid head SHA');
58+
core.setFailed('Invalid head SHA format');
59+
return;
60+
}
61+
62+
// Validate branch is allowed
63+
const allowedBranches = ['main', 'develop'];
64+
if (!allowedBranches.includes(workflowRun.head_branch)) {
65+
core.setFailed(`Security: workflow_run from branch '${workflowRun.head_branch}' is not allowed. Allowed branches: ${allowedBranches.join(', ')}`);
5066
return;
5167
}
68+
69+
// Check if lint workflow passed
5270
const { data: runs } = await github.rest.actions.listWorkflowRuns({
5371
owner: context.repo.owner,
5472
repo: context.repo.repo,

.github/workflows/docker-push.yml

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,34 @@ jobs:
2525
runs-on: ubuntu-latest
2626
if: ${{ github.event_name == 'workflow_dispatch' || (github.event.workflow_run.conclusion == 'success' && (github.event.workflow_run.head_branch == 'main' || github.event.workflow_run.head_branch == 'develop')) }}
2727
steps:
28-
- name: Check if lint workflow passed
28+
- name: Validate workflow_run security
2929
if: github.event_name == 'workflow_run'
3030
uses: actions/github-script@v7
3131
with:
3232
script: |
33-
const headSha = context.payload.workflow_run?.head_sha;
33+
const workflowRun = context.payload.workflow_run;
34+
35+
// Validate workflow_run is from the same repository (not a fork)
36+
if (!workflowRun || workflowRun.repository.full_name !== context.repo.owner + '/' + context.repo.repo) {
37+
core.setFailed('Security: workflow_run must be from the same repository');
38+
return;
39+
}
40+
41+
// Validate head SHA format
42+
const headSha = workflowRun.head_sha;
3443
if (!headSha || !/^[a-f0-9]{40}$/i.test(headSha)) {
35-
core.setFailed('Invalid head SHA');
44+
core.setFailed('Invalid head SHA format');
45+
return;
46+
}
47+
48+
// Validate branch is allowed
49+
const allowedBranches = ['main', 'develop'];
50+
if (!allowedBranches.includes(workflowRun.head_branch)) {
51+
core.setFailed(`Security: workflow_run from branch '${workflowRun.head_branch}' is not allowed. Allowed branches: ${allowedBranches.join(', ')}`);
3652
return;
3753
}
54+
55+
// Check if lint workflow passed
3856
const { data: runs } = await github.rest.actions.listWorkflowRuns({
3957
owner: context.repo.owner,
4058
repo: context.repo.repo,

.github/workflows/integration-test.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,32 @@ jobs:
2121
runs-on: ubuntu-latest
2222
if: ${{ github.event_name == 'workflow_dispatch' || (github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'main') }}
2323
steps:
24+
- name: Validate workflow_run security
25+
if: github.event_name == 'workflow_run'
26+
uses: actions/github-script@v7
27+
with:
28+
script: |
29+
const workflowRun = context.payload.workflow_run;
30+
31+
// Validate workflow_run is from the same repository (not a fork)
32+
if (!workflowRun || workflowRun.repository.full_name !== context.repo.owner + '/' + context.repo.repo) {
33+
core.setFailed('Security: workflow_run must be from the same repository');
34+
return;
35+
}
36+
37+
// Validate head SHA format
38+
const headSha = workflowRun.head_sha;
39+
if (!headSha || !/^[a-f0-9]{40}$/i.test(headSha)) {
40+
core.setFailed('Invalid head SHA format');
41+
return;
42+
}
43+
44+
// Validate branch is allowed
45+
const allowedBranches = ['main'];
46+
if (!allowedBranches.includes(workflowRun.head_branch)) {
47+
core.setFailed(`Security: workflow_run from branch '${workflowRun.head_branch}' is not allowed. Allowed branches: ${allowedBranches.join(', ')}`);
48+
return;
49+
}
2450
- name: Checkout code
2551
uses: actions/checkout@v5
2652
with:

.github/workflows/security-scan.yml

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,34 @@ jobs:
1919
runs-on: ubuntu-latest
2020
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
2121
steps:
22-
- name: Check if lint workflow passed
22+
- name: Validate workflow_run security
2323
if: github.event_name == 'workflow_run'
2424
uses: actions/github-script@v7
2525
with:
2626
script: |
27-
const headSha = context.payload.workflow_run?.head_sha;
27+
const workflowRun = context.payload.workflow_run;
28+
29+
// Validate workflow_run is from the same repository (not a fork)
30+
if (!workflowRun || workflowRun.repository.full_name !== context.repo.owner + '/' + context.repo.repo) {
31+
core.setFailed('Security: workflow_run must be from the same repository');
32+
return;
33+
}
34+
35+
// Validate head SHA format
36+
const headSha = workflowRun.head_sha;
2837
if (!headSha || !/^[a-f0-9]{40}$/i.test(headSha)) {
29-
core.setFailed('Invalid head SHA');
38+
core.setFailed('Invalid head SHA format');
39+
return;
40+
}
41+
42+
// Validate branch is allowed
43+
const allowedBranches = ['main', 'develop'];
44+
if (!allowedBranches.includes(workflowRun.head_branch)) {
45+
core.setFailed(`Security: workflow_run from branch '${workflowRun.head_branch}' is not allowed. Allowed branches: ${allowedBranches.join(', ')}`);
3046
return;
3147
}
48+
49+
// Check if lint workflow passed
3250
const { data: runs } = await github.rest.actions.listWorkflowRuns({
3351
owner: context.repo.owner,
3452
repo: context.repo.repo,

0 commit comments

Comments
 (0)