@cyclonedx/cdxgen 12.2.0 → 12.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +242 -90
- package/bin/audit.js +191 -0
- package/bin/cdxgen.js +532 -168
- package/bin/convert.js +99 -0
- package/bin/evinse.js +23 -0
- package/bin/repl.js +339 -8
- package/bin/sign.js +8 -0
- package/bin/validate.js +8 -0
- package/bin/verify.js +8 -0
- package/data/container-knowledge-index.json +125 -0
- package/data/gtfobins-index.json +6296 -0
- package/data/lolbas-index.json +150 -0
- package/data/queries-darwin.json +63 -3
- package/data/queries-win.json +45 -3
- package/data/queries.json +74 -2
- package/data/rules/chrome-extensions.yaml +240 -0
- package/data/rules/ci-permissions.yaml +478 -18
- package/data/rules/container-risk.yaml +270 -0
- package/data/rules/obom-runtime.yaml +891 -0
- package/data/rules/package-integrity.yaml +49 -0
- package/data/spdx-export.schema.json +6794 -0
- package/data/spdx-model-v3.0.1.jsonld +15999 -0
- package/lib/audit/index.js +1924 -0
- package/lib/audit/index.poku.js +1488 -0
- package/lib/audit/progress.js +137 -0
- package/lib/audit/progress.poku.js +188 -0
- package/lib/audit/reporters.js +618 -0
- package/lib/audit/scoring.js +310 -0
- package/lib/audit/scoring.poku.js +341 -0
- package/lib/audit/targets.js +260 -0
- package/lib/audit/targets.poku.js +331 -0
- package/lib/cli/index.js +276 -68
- package/lib/cli/index.poku.js +368 -0
- package/lib/helpers/analyzer.js +1052 -5
- package/lib/helpers/analyzer.poku.js +301 -0
- package/lib/helpers/annotationFormatter.js +49 -0
- package/lib/helpers/annotationFormatter.poku.js +44 -0
- package/lib/helpers/bomUtils.js +36 -0
- package/lib/helpers/bomUtils.poku.js +51 -0
- package/lib/helpers/caxa.js +2 -2
- package/lib/helpers/chromextutils.js +1153 -0
- package/lib/helpers/chromextutils.poku.js +493 -0
- package/lib/helpers/ciParsers/githubActions.js +1632 -45
- package/lib/helpers/ciParsers/githubActions.poku.js +853 -1
- package/lib/helpers/containerRisk.js +186 -0
- package/lib/helpers/containerRisk.poku.js +52 -0
- package/lib/helpers/depsUtils.js +16 -0
- package/lib/helpers/depsUtils.poku.js +58 -1
- package/lib/helpers/display.js +245 -61
- package/lib/helpers/display.poku.js +162 -2
- package/lib/helpers/exportUtils.js +123 -0
- package/lib/helpers/exportUtils.poku.js +60 -0
- package/lib/helpers/formulationParsers.js +69 -0
- package/lib/helpers/formulationParsers.poku.js +44 -0
- package/lib/helpers/gtfobins.js +189 -0
- package/lib/helpers/gtfobins.poku.js +49 -0
- package/lib/helpers/lolbas.js +267 -0
- package/lib/helpers/lolbas.poku.js +39 -0
- package/lib/helpers/osqueryTransform.js +84 -0
- package/lib/helpers/osqueryTransform.poku.js +49 -0
- package/lib/helpers/provenanceUtils.js +193 -0
- package/lib/helpers/provenanceUtils.poku.js +145 -0
- package/lib/helpers/pylockutils.js +281 -0
- package/lib/helpers/pylockutils.poku.js +48 -0
- package/lib/helpers/registryProvenance.js +793 -0
- package/lib/helpers/registryProvenance.poku.js +452 -0
- package/lib/helpers/remote/dependency-track.js +84 -0
- package/lib/helpers/remote/dependency-track.poku.js +119 -0
- package/lib/helpers/source.js +1267 -0
- package/lib/helpers/source.poku.js +771 -0
- package/lib/helpers/spdxUtils.js +97 -0
- package/lib/helpers/spdxUtils.poku.js +70 -0
- package/lib/helpers/table.js +384 -0
- package/lib/helpers/table.poku.js +186 -0
- package/lib/helpers/unicodeScan.js +147 -0
- package/lib/helpers/unicodeScan.poku.js +45 -0
- package/lib/helpers/utils.js +882 -136
- package/lib/helpers/utils.poku.js +995 -91
- package/lib/managers/binary.js +29 -5
- package/lib/managers/docker.js +179 -52
- package/lib/managers/docker.poku.js +327 -28
- package/lib/managers/oci.js +107 -23
- package/lib/managers/oci.poku.js +132 -0
- package/lib/server/openapi.yaml +50 -0
- package/lib/server/server.js +228 -331
- package/lib/server/server.poku.js +220 -5
- package/lib/stages/postgen/annotator.js +7 -0
- package/lib/stages/postgen/annotator.poku.js +40 -0
- package/lib/stages/postgen/auditBom.js +20 -5
- package/lib/stages/postgen/auditBom.poku.js +1729 -67
- package/lib/stages/postgen/postgen.js +40 -0
- package/lib/stages/postgen/postgen.poku.js +47 -0
- package/lib/stages/postgen/ruleEngine.js +80 -2
- package/lib/stages/postgen/spdxConverter.js +796 -0
- package/lib/stages/postgen/spdxConverter.poku.js +341 -0
- package/lib/validator/bomValidator.js +232 -0
- package/lib/validator/bomValidator.poku.js +70 -0
- package/lib/validator/complianceRules.js +70 -7
- package/lib/validator/complianceRules.poku.js +30 -0
- package/lib/validator/reporters/annotations.js +2 -2
- package/lib/validator/reporters/console.js +13 -2
- package/lib/validator/reporters.poku.js +13 -0
- package/package.json +10 -8
- package/types/bin/audit.d.ts +3 -0
- package/types/bin/audit.d.ts.map +1 -0
- package/types/bin/convert.d.ts +3 -0
- package/types/bin/convert.d.ts.map +1 -0
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts +115 -0
- package/types/lib/audit/index.d.ts.map +1 -0
- package/types/lib/audit/progress.d.ts +27 -0
- package/types/lib/audit/progress.d.ts.map +1 -0
- package/types/lib/audit/reporters.d.ts +35 -0
- package/types/lib/audit/reporters.d.ts.map +1 -0
- package/types/lib/audit/scoring.d.ts +35 -0
- package/types/lib/audit/scoring.d.ts.map +1 -0
- package/types/lib/audit/targets.d.ts +63 -0
- package/types/lib/audit/targets.d.ts.map +1 -0
- package/types/lib/cli/index.d.ts +8 -0
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/helpers/analyzer.d.ts +13 -0
- package/types/lib/helpers/analyzer.d.ts.map +1 -1
- package/types/lib/helpers/annotationFormatter.d.ts +23 -0
- package/types/lib/helpers/annotationFormatter.d.ts.map +1 -0
- package/types/lib/helpers/bomUtils.d.ts +5 -0
- package/types/lib/helpers/bomUtils.d.ts.map +1 -0
- package/types/lib/helpers/chromextutils.d.ts +97 -0
- package/types/lib/helpers/chromextutils.d.ts.map +1 -0
- package/types/lib/helpers/ciParsers/githubActions.d.ts +3 -8
- package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -1
- package/types/lib/helpers/containerRisk.d.ts +17 -0
- package/types/lib/helpers/containerRisk.d.ts.map +1 -0
- package/types/lib/helpers/depsUtils.d.ts.map +1 -1
- package/types/lib/helpers/display.d.ts +4 -1
- package/types/lib/helpers/display.d.ts.map +1 -1
- package/types/lib/helpers/exportUtils.d.ts +40 -0
- package/types/lib/helpers/exportUtils.d.ts.map +1 -0
- package/types/lib/helpers/formulationParsers.d.ts.map +1 -1
- package/types/lib/helpers/gtfobins.d.ts +17 -0
- package/types/lib/helpers/gtfobins.d.ts.map +1 -0
- package/types/lib/helpers/lolbas.d.ts +16 -0
- package/types/lib/helpers/lolbas.d.ts.map +1 -0
- package/types/lib/helpers/osqueryTransform.d.ts +7 -0
- package/types/lib/helpers/osqueryTransform.d.ts.map +1 -0
- package/types/lib/helpers/provenanceUtils.d.ts +90 -0
- package/types/lib/helpers/provenanceUtils.d.ts.map +1 -0
- package/types/lib/helpers/pylockutils.d.ts +51 -0
- package/types/lib/helpers/pylockutils.d.ts.map +1 -0
- package/types/lib/helpers/registryProvenance.d.ts +17 -0
- package/types/lib/helpers/registryProvenance.d.ts.map +1 -0
- package/types/lib/helpers/remote/dependency-track.d.ts +16 -0
- package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -0
- package/types/lib/helpers/source.d.ts +141 -0
- package/types/lib/helpers/source.d.ts.map +1 -0
- package/types/lib/helpers/spdxUtils.d.ts +2 -0
- package/types/lib/helpers/spdxUtils.d.ts.map +1 -0
- package/types/lib/helpers/table.d.ts +6 -0
- package/types/lib/helpers/table.d.ts.map +1 -0
- package/types/lib/helpers/unicodeScan.d.ts +46 -0
- package/types/lib/helpers/unicodeScan.d.ts.map +1 -0
- package/types/lib/helpers/utils.d.ts +30 -11
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/managers/oci.d.ts.map +1 -1
- package/types/lib/server/server.d.ts +0 -35
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/postgen/spdxConverter.d.ts +11 -0
- package/types/lib/stages/postgen/spdxConverter.d.ts.map +1 -0
- package/types/lib/validator/bomValidator.d.ts +1 -0
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
- package/types/lib/validator/complianceRules.d.ts.map +1 -1
- package/types/lib/validator/reporters/console.d.ts.map +1 -1
- package/types/bin/dependencies.d.ts +0 -3
- package/types/bin/dependencies.d.ts.map +0 -1
- package/types/bin/licenses.d.ts +0 -3
- package/types/bin/licenses.d.ts.map +0 -1
|
@@ -7,8 +7,11 @@
|
|
|
7
7
|
description: "GitHub Actions referenced by tag/branch in workflows with write permissions pose supply chain risk"
|
|
8
8
|
severity: high
|
|
9
9
|
category: ci-permission
|
|
10
|
+
attack:
|
|
11
|
+
tactics: [TA0001, TA0004]
|
|
12
|
+
techniques: [T1195.001]
|
|
10
13
|
condition: |
|
|
11
|
-
|
|
14
|
+
$auditComponents($)[
|
|
12
15
|
$prop($, 'cdx:github:action:isShaPinned') = 'false'
|
|
13
16
|
and (
|
|
14
17
|
$prop($, 'cdx:github:workflow:hasWritePermissions') = 'true'
|
|
@@ -31,30 +34,45 @@
|
|
|
31
34
|
}
|
|
32
35
|
- id: CI-002
|
|
33
36
|
name: "OIDC token issuance to non-official action"
|
|
34
|
-
description: "Workflows granting id-token:write to third-party actions may enable token exfiltration"
|
|
37
|
+
description: "Workflows or jobs granting id-token:write to third-party actions may enable token exfiltration"
|
|
35
38
|
severity: high
|
|
36
39
|
category: ci-permission
|
|
40
|
+
attack:
|
|
41
|
+
tactics: [TA0006]
|
|
42
|
+
techniques: [T1528]
|
|
37
43
|
condition: |
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
$auditComponents($)[
|
|
45
|
+
(
|
|
46
|
+
$prop($, 'cdx:github:workflow:hasIdTokenWrite') = 'true'
|
|
47
|
+
or $prop($, 'cdx:github:job:hasIdTokenWrite') = 'true'
|
|
48
|
+
)
|
|
40
49
|
and $prop($, 'cdx:actions:isOfficial') = 'false'
|
|
41
50
|
]
|
|
42
51
|
location: |
|
|
43
|
-
{
|
|
52
|
+
{
|
|
53
|
+
"bomRef": $."bom-ref",
|
|
54
|
+
"purl": purl,
|
|
55
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
56
|
+
}
|
|
44
57
|
message: "Workflow grants OIDC token access to non-official action '{{ $prop($, 'cdx:github:action:uses') }}'"
|
|
45
58
|
mitigation: "Restrict id-token scope or use only verified/official actions for OIDC operations"
|
|
46
59
|
evidence: |
|
|
47
60
|
{
|
|
48
61
|
"isVerified": $prop($, 'cdx:actions:isVerified'),
|
|
49
|
-
"actionGroup": group
|
|
62
|
+
"actionGroup": group,
|
|
63
|
+
"jobHasIdTokenWrite": $prop($, 'cdx:github:job:hasIdTokenWrite'),
|
|
64
|
+
"workflowHasIdTokenWrite": $prop($, 'cdx:github:workflow:hasIdTokenWrite')
|
|
50
65
|
}
|
|
51
66
|
- id: CI-003
|
|
52
67
|
name: "Action pinned to mutable tag"
|
|
53
68
|
description: "GitHub Actions pinned to tags (vs SHA) can change behavior unexpectedly if tag is moved"
|
|
54
69
|
severity: medium
|
|
55
70
|
category: ci-permission
|
|
71
|
+
attack:
|
|
72
|
+
tactics: [TA0001, TA0005]
|
|
73
|
+
techniques: [T1195.001]
|
|
56
74
|
condition: |
|
|
57
|
-
|
|
75
|
+
$auditComponents($)[
|
|
58
76
|
$prop($, 'cdx:github:action:versionPinningType') = 'tag'
|
|
59
77
|
]
|
|
60
78
|
location: |
|
|
@@ -71,11 +89,11 @@
|
|
|
71
89
|
description: "pull_request_target can execute code in the context of the base branch, risking secret exposure"
|
|
72
90
|
severity: medium
|
|
73
91
|
category: ci-permission
|
|
74
|
-
|
|
92
|
+
attack:
|
|
93
|
+
tactics: [TA0001, TA0004]
|
|
75
94
|
condition: |
|
|
76
|
-
|
|
77
|
-
$
|
|
78
|
-
and $nullSafeProp($, 'cdx:github:workflow:triggers') ~> $trim() ~> $contains('pull_request_target')
|
|
95
|
+
$auditWorkflows($)[
|
|
96
|
+
$prop($, 'cdx:github:workflow:hasPullRequestTargetTrigger') = 'true'
|
|
79
97
|
]
|
|
80
98
|
location: |
|
|
81
99
|
{
|
|
@@ -94,8 +112,11 @@
|
|
|
94
112
|
description: "actions/checkout with persist-credentials=true (default) exposes GITHUB_TOKEN to subsequent steps"
|
|
95
113
|
severity: medium
|
|
96
114
|
category: ci-permission
|
|
115
|
+
attack:
|
|
116
|
+
tactics: [TA0004, TA0006]
|
|
117
|
+
techniques: [T1552]
|
|
97
118
|
condition: |
|
|
98
|
-
|
|
119
|
+
$auditComponents($)[
|
|
99
120
|
$contains($nullSafeProp($, 'cdx:github:action:uses'), 'actions/checkout')
|
|
100
121
|
and $propBool($, 'cdx:github:checkout:persistCredentials') != false
|
|
101
122
|
and (
|
|
@@ -121,10 +142,22 @@
|
|
|
121
142
|
description: "GitHub Actions cache can be poisoned when used in workflows triggered by untrusted input (e.g., pull_request from forks)"
|
|
122
143
|
severity: high
|
|
123
144
|
category: ci-permission
|
|
145
|
+
attack:
|
|
146
|
+
tactics: [TA0001, TA0005]
|
|
147
|
+
techniques: [T1195.001]
|
|
124
148
|
condition: |
|
|
125
|
-
|
|
149
|
+
$auditComponents($)[
|
|
126
150
|
$nullSafeProp($, 'cdx:github:action:uses') ~> $contains('actions/cache')
|
|
127
|
-
and
|
|
151
|
+
and (
|
|
152
|
+
$prop($, 'cdx:github:workflow:hasPullRequestTrigger') = 'true'
|
|
153
|
+
or $prop($, 'cdx:github:workflow:hasPullRequestTargetTrigger') = 'true'
|
|
154
|
+
)
|
|
155
|
+
and (
|
|
156
|
+
$propBool($, 'cdx:github:workflow:hasWritePermissions') = true
|
|
157
|
+
or $propBool($, 'cdx:github:job:hasWritePermissions') = true
|
|
158
|
+
or $prop($, 'cdx:github:cache:hasRestoreKeys') = 'true'
|
|
159
|
+
or $prop($, 'cdx:github:cache:keyUsesHashFiles') != 'true'
|
|
160
|
+
)
|
|
128
161
|
]
|
|
129
162
|
location: |
|
|
130
163
|
{
|
|
@@ -132,11 +165,13 @@
|
|
|
132
165
|
"purl": purl,
|
|
133
166
|
"file": $prop($, 'cdx:github:workflow:file')
|
|
134
167
|
}
|
|
135
|
-
message: "Cache action used in
|
|
168
|
+
message: "Cache action used in pull-request-reachable workflow; cache key '{{ $prop($, 'cdx:github:cache:key') }}' may be writable by untrusted code"
|
|
136
169
|
mitigation: "Scope cache keys to PR-specific values, validate restored cache contents, or avoid caching in untrusted workflows"
|
|
137
170
|
evidence: |
|
|
138
171
|
{
|
|
139
172
|
"cacheKey": $prop($, 'cdx:github:cache:key'),
|
|
173
|
+
"hasRestoreKeys": $prop($, 'cdx:github:cache:hasRestoreKeys'),
|
|
174
|
+
"keyUsesHashFiles": $prop($, 'cdx:github:cache:keyUsesHashFiles'),
|
|
140
175
|
"cachePath": $prop($, 'cdx:github:cache:path'),
|
|
141
176
|
"triggers": $prop($, 'cdx:github:workflow:triggers')
|
|
142
177
|
}
|
|
@@ -145,8 +180,11 @@
|
|
|
145
180
|
description: "Direct interpolation of github.event.* or inputs.* into run: blocks enables command injection"
|
|
146
181
|
severity: critical
|
|
147
182
|
category: ci-permission
|
|
183
|
+
attack:
|
|
184
|
+
tactics: [TA0002, TA0004]
|
|
185
|
+
techniques: [T1059]
|
|
148
186
|
condition: |
|
|
149
|
-
|
|
187
|
+
$auditComponents($)[
|
|
150
188
|
$prop($, 'cdx:github:step:hasUntrustedInterpolation') = 'true'
|
|
151
189
|
and $prop($, 'cdx:github:step:type') = 'run'
|
|
152
190
|
]
|
|
@@ -167,9 +205,15 @@
|
|
|
167
205
|
description: "Triggers like pull_request_target, issue_comment, or workflow_run combined with write permissions enable privilege escalation"
|
|
168
206
|
severity: high
|
|
169
207
|
category: ci-permission
|
|
208
|
+
attack:
|
|
209
|
+
tactics: [TA0001, TA0004]
|
|
170
210
|
condition: |
|
|
171
|
-
|
|
172
|
-
|
|
211
|
+
$auditWorkflows($)[
|
|
212
|
+
(
|
|
213
|
+
$prop($, 'cdx:github:workflow:hasPullRequestTargetTrigger') = 'true'
|
|
214
|
+
or $prop($, 'cdx:github:workflow:hasIssueCommentTrigger') = 'true'
|
|
215
|
+
or $prop($, 'cdx:github:workflow:hasWorkflowRunTrigger') = 'true'
|
|
216
|
+
)
|
|
173
217
|
and $prop($, 'cdx:github:workflow:hasWritePermissions') = 'true'
|
|
174
218
|
]
|
|
175
219
|
location: |
|
|
@@ -184,3 +228,419 @@
|
|
|
184
228
|
"triggers": $prop($, 'cdx:github:workflow:triggers'),
|
|
185
229
|
"hasWritePermissions": $prop($, 'cdx:github:workflow:hasWritePermissions')
|
|
186
230
|
}
|
|
231
|
+
|
|
232
|
+
- id: CI-009
|
|
233
|
+
name: "Workflow file contains hidden Unicode characters"
|
|
234
|
+
description: "Hidden Unicode in workflow files can disguise malicious logic, comments, or diffs and should be reviewed before merge"
|
|
235
|
+
severity: medium
|
|
236
|
+
category: ci-permission
|
|
237
|
+
attack:
|
|
238
|
+
tactics: [TA0005]
|
|
239
|
+
techniques: [T1027]
|
|
240
|
+
condition: |
|
|
241
|
+
$auditWorkflows($)[
|
|
242
|
+
$prop($, 'cdx:github:workflow:hasHiddenUnicode') = 'true'
|
|
243
|
+
]
|
|
244
|
+
location: |
|
|
245
|
+
{
|
|
246
|
+
"bomRef": $."bom-ref",
|
|
247
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
248
|
+
}
|
|
249
|
+
message: "Workflow '{{ $prop($, 'cdx:github:workflow:name') }}' contains hidden Unicode characters"
|
|
250
|
+
mitigation: "Review the file in an editor that reveals bidirectional, zero-width, and control characters; remove suspicious hidden Unicode before merge"
|
|
251
|
+
evidence: |
|
|
252
|
+
{
|
|
253
|
+
"codePoints": $prop($, 'cdx:github:workflow:hiddenUnicodeCodePoints'),
|
|
254
|
+
"lineNumbers": $prop($, 'cdx:github:workflow:hiddenUnicodeLineNumbers'),
|
|
255
|
+
"inComments": $prop($, 'cdx:github:workflow:hiddenUnicodeInComments')
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
- id: CI-010
|
|
259
|
+
name: "Legacy token-based package publishing step"
|
|
260
|
+
description: "npm and PyPI publishing should prefer trusted publishing or OIDC-backed flows instead of long-lived token secrets or explicit --token arguments"
|
|
261
|
+
severity: medium
|
|
262
|
+
category: ci-permission
|
|
263
|
+
attack:
|
|
264
|
+
tactics: [TA0006, TA0010]
|
|
265
|
+
techniques: [T1528]
|
|
266
|
+
condition: |
|
|
267
|
+
$auditComponents($)[
|
|
268
|
+
$prop($, 'cdx:github:step:isPublishCommand') = 'true'
|
|
269
|
+
and $prop($, 'cdx:github:step:usesLegacyPublishToken') = 'true'
|
|
270
|
+
]
|
|
271
|
+
location: |
|
|
272
|
+
{
|
|
273
|
+
"bomRef": $."bom-ref",
|
|
274
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
275
|
+
}
|
|
276
|
+
message: "Workflow publish step '{{ name }}' uses legacy {{ $prop($, 'cdx:github:step:publishEcosystem') }} token-based publishing"
|
|
277
|
+
mitigation: "Prefer trusted publishing or short-lived OIDC-backed release flows instead of persistent package tokens or explicit --token arguments"
|
|
278
|
+
evidence: |
|
|
279
|
+
{
|
|
280
|
+
"ecosystem": $prop($, 'cdx:github:step:publishEcosystem'),
|
|
281
|
+
"tokenSources": $prop($, 'cdx:github:step:legacyPublishTokenSources'),
|
|
282
|
+
"stepCommand": $prop($, 'cdx:github:step:command')
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
- id: CI-011
|
|
286
|
+
name: "External reusable workflow inherits caller secrets"
|
|
287
|
+
description: "Reusable workflows invoked from external repositories with secrets: inherit expand the trust boundary and can expose repository credentials"
|
|
288
|
+
severity: high
|
|
289
|
+
category: ci-permission
|
|
290
|
+
attack:
|
|
291
|
+
tactics: [TA0006, TA0008]
|
|
292
|
+
techniques: [T1528, T1552]
|
|
293
|
+
condition: |
|
|
294
|
+
$auditComponents($)[
|
|
295
|
+
$prop($, 'cdx:github:reusableWorkflow:isExternal') = 'true'
|
|
296
|
+
and $prop($, 'cdx:github:reusableWorkflow:secretsInherit') = 'true'
|
|
297
|
+
]
|
|
298
|
+
location: |
|
|
299
|
+
{
|
|
300
|
+
"bomRef": $."bom-ref",
|
|
301
|
+
"purl": purl,
|
|
302
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
303
|
+
}
|
|
304
|
+
message: "Reusable workflow '{{ $prop($, 'cdx:github:reusableWorkflow:uses') }}' inherits caller secrets from an external repository"
|
|
305
|
+
mitigation: "Avoid secrets: inherit for external reusable workflows; pass only the minimum explicit secrets and pin the reusable workflow to a full SHA"
|
|
306
|
+
evidence: |
|
|
307
|
+
{
|
|
308
|
+
"uses": $prop($, 'cdx:github:reusableWorkflow:uses'),
|
|
309
|
+
"isShaPinned": $prop($, 'cdx:github:reusableWorkflow:isShaPinned'),
|
|
310
|
+
"withKeys": $prop($, 'cdx:github:reusableWorkflow:withKeys')
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
- id: CI-012
|
|
314
|
+
name: "External reusable workflow pinned to mutable ref"
|
|
315
|
+
description: "Reusable workflows referenced by tag or branch can change behavior without review and should be pinned to immutable SHAs"
|
|
316
|
+
severity: medium
|
|
317
|
+
category: ci-permission
|
|
318
|
+
attack:
|
|
319
|
+
tactics: [TA0001, TA0005]
|
|
320
|
+
techniques: [T1195.001]
|
|
321
|
+
condition: |
|
|
322
|
+
$auditComponents($)[
|
|
323
|
+
$prop($, 'cdx:github:reusableWorkflow:isExternal') = 'true'
|
|
324
|
+
and $prop($, 'cdx:github:reusableWorkflow:isShaPinned') = 'false'
|
|
325
|
+
]
|
|
326
|
+
location: |
|
|
327
|
+
{
|
|
328
|
+
"bomRef": $."bom-ref",
|
|
329
|
+
"purl": purl,
|
|
330
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
331
|
+
}
|
|
332
|
+
message: "External reusable workflow '{{ $prop($, 'cdx:github:reusableWorkflow:uses') }}' is pinned to a mutable ref"
|
|
333
|
+
mitigation: "Pin reusable workflows to full SHAs and review updates through a normal change-management process"
|
|
334
|
+
evidence: |
|
|
335
|
+
{
|
|
336
|
+
"pinningType": $prop($, 'cdx:github:reusableWorkflow:versionPinningType'),
|
|
337
|
+
"ref": $prop($, 'cdx:github:reusableWorkflow:ref')
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
- id: CI-013
|
|
341
|
+
name: "High-risk trigger reaches a self-hosted runner"
|
|
342
|
+
description: "High-risk triggers executing on self-hosted runners can expose internal network access, credentials, and long-lived runner state"
|
|
343
|
+
severity: high
|
|
344
|
+
category: ci-permission
|
|
345
|
+
attack:
|
|
346
|
+
tactics: [TA0004, TA0008]
|
|
347
|
+
condition: |
|
|
348
|
+
$auditComponents($)[
|
|
349
|
+
(
|
|
350
|
+
$prop($, 'cdx:github:workflow:hasPullRequestTargetTrigger') = 'true'
|
|
351
|
+
or $prop($, 'cdx:github:workflow:hasIssueCommentTrigger') = 'true'
|
|
352
|
+
or $prop($, 'cdx:github:workflow:hasWorkflowRunTrigger') = 'true'
|
|
353
|
+
)
|
|
354
|
+
and $prop($, 'cdx:github:job:isSelfHosted') = 'true'
|
|
355
|
+
]
|
|
356
|
+
location: |
|
|
357
|
+
{
|
|
358
|
+
"bomRef": $."bom-ref",
|
|
359
|
+
"purl": purl,
|
|
360
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
361
|
+
}
|
|
362
|
+
message: "High-risk workflow trigger reaches self-hosted runner in job '{{ $prop($, 'cdx:github:job:name') }}'"
|
|
363
|
+
mitigation: "Restrict self-hosted runners to trusted workflows only, isolate runner credentials, and gate high-risk triggers with manual approval"
|
|
364
|
+
evidence: |
|
|
365
|
+
{
|
|
366
|
+
"triggers": $prop($, 'cdx:github:workflow:triggers'),
|
|
367
|
+
"jobRunner": $prop($, 'cdx:github:job:runner'),
|
|
368
|
+
"jobName": $prop($, 'cdx:github:job:name')
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
- id: CI-014
|
|
372
|
+
name: "Privileged workflow mutates downstream runner state"
|
|
373
|
+
description: "Writing to GITHUB_ENV, GITHUB_PATH, or GITHUB_OUTPUT in privileged workflows can persist attacker-controlled state across later steps and jobs"
|
|
374
|
+
severity: high
|
|
375
|
+
category: ci-permission
|
|
376
|
+
attack:
|
|
377
|
+
tactics: [TA0003, TA0004, TA0005]
|
|
378
|
+
techniques: [T1059]
|
|
379
|
+
condition: |
|
|
380
|
+
$auditComponents($)[
|
|
381
|
+
$prop($, 'cdx:github:step:type') = 'run'
|
|
382
|
+
and $prop($, 'cdx:github:step:mutatesRunnerState') = 'true'
|
|
383
|
+
and (
|
|
384
|
+
$prop($, 'cdx:github:workflow:hasWritePermissions') = 'true'
|
|
385
|
+
or $prop($, 'cdx:github:job:hasWritePermissions') = 'true'
|
|
386
|
+
or $prop($, 'cdx:github:workflow:hasIdTokenWrite') = 'true'
|
|
387
|
+
or $prop($, 'cdx:github:job:hasIdTokenWrite') = 'true'
|
|
388
|
+
)
|
|
389
|
+
]
|
|
390
|
+
location: |
|
|
391
|
+
{
|
|
392
|
+
"bomRef": $."bom-ref",
|
|
393
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
394
|
+
}
|
|
395
|
+
message: "Privileged workflow step '{{ name }}' mutates runner state via '{{ $prop($, 'cdx:github:step:runnerStateTargets') }}'"
|
|
396
|
+
mitigation: "Avoid mutating shared runner state in privileged jobs; prefer tightly-scoped step outputs and review all GITHUB_ENV/GITHUB_PATH/GITHUB_OUTPUT writes"
|
|
397
|
+
evidence: |
|
|
398
|
+
{
|
|
399
|
+
"runnerStateTargets": $prop($, 'cdx:github:step:runnerStateTargets'),
|
|
400
|
+
"stepCommand": $prop($, 'cdx:github:step:command'),
|
|
401
|
+
"jobName": $prop($, 'cdx:github:job:name')
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
- id: CI-015
|
|
405
|
+
name: "Outbound network command references sensitive context"
|
|
406
|
+
description: "Run steps that invoke outbound network tools while transmitting secrets, github.token, or OIDC request context are strong exfiltration indicators"
|
|
407
|
+
severity: high
|
|
408
|
+
category: ci-permission
|
|
409
|
+
attack:
|
|
410
|
+
tactics: [TA0006, TA0010]
|
|
411
|
+
techniques: [T1048]
|
|
412
|
+
condition: |
|
|
413
|
+
$auditComponents($)[
|
|
414
|
+
$prop($, 'cdx:github:step:type') = 'run'
|
|
415
|
+
and $prop($, 'cdx:github:step:hasOutboundNetworkCommand') = 'true'
|
|
416
|
+
and $prop($, 'cdx:github:step:referencesSensitiveContext') = 'true'
|
|
417
|
+
and $prop($, 'cdx:github:step:likelyExfiltration') = 'true'
|
|
418
|
+
]
|
|
419
|
+
location: |
|
|
420
|
+
{
|
|
421
|
+
"bomRef": $."bom-ref",
|
|
422
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
423
|
+
}
|
|
424
|
+
message: "Outbound command in step '{{ name }}' references sensitive context '{{ $prop($, 'cdx:github:step:sensitiveContextRefs') }}'"
|
|
425
|
+
mitigation: "Review outbound network steps for secret or token use, disable unnecessary network egress, and move sensitive values into least-privileged isolated jobs"
|
|
426
|
+
evidence: |
|
|
427
|
+
{
|
|
428
|
+
"networkTools": $prop($, 'cdx:github:step:outboundNetworkTools'),
|
|
429
|
+
"sensitiveContextRefs": $prop($, 'cdx:github:step:sensitiveContextRefs'),
|
|
430
|
+
"exfiltrationIndicators": $prop($, 'cdx:github:step:exfiltrationIndicators'),
|
|
431
|
+
"stepCommand": $prop($, 'cdx:github:step:command')
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
- id: CI-016
|
|
435
|
+
name: "Privileged reusable workflow accepts caller secrets"
|
|
436
|
+
description: "workflow_call producers that request caller-provided secrets while also holding write or OIDC permissions expand the blast radius across repositories and workflows"
|
|
437
|
+
severity: high
|
|
438
|
+
category: ci-permission
|
|
439
|
+
attack:
|
|
440
|
+
tactics: [TA0006, TA0008]
|
|
441
|
+
techniques: [T1528, T1552]
|
|
442
|
+
condition: |
|
|
443
|
+
$auditWorkflows($)[
|
|
444
|
+
$prop($, 'cdx:github:workflow:isWorkflowCallProducer') = 'true'
|
|
445
|
+
and $safeStr($prop($, 'cdx:github:workflow:workflowCallSecrets')) != ''
|
|
446
|
+
and (
|
|
447
|
+
$propBool($, 'cdx:github:workflow:hasWritePermissions') = true
|
|
448
|
+
or $propBool($, 'cdx:github:workflow:hasIdTokenWrite') = true
|
|
449
|
+
)
|
|
450
|
+
]
|
|
451
|
+
location: |
|
|
452
|
+
{
|
|
453
|
+
"bomRef": $."bom-ref",
|
|
454
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
455
|
+
}
|
|
456
|
+
message: "Reusable workflow '{{ $prop($, 'cdx:github:workflow:name') }}' accepts caller secrets while running with privileged permissions"
|
|
457
|
+
mitigation: "Avoid broad secret interfaces on reusable workflows with write or OIDC permissions; split privileged work into a narrowly scoped follow-up job and require only explicit minimal secrets"
|
|
458
|
+
evidence: |
|
|
459
|
+
{
|
|
460
|
+
"workflowCallSecrets": $prop($, 'cdx:github:workflow:workflowCallSecrets'),
|
|
461
|
+
"writeScopes": $prop($, 'cdx:github:workflow:writeScopes'),
|
|
462
|
+
"hasWritePermissions": $prop($, 'cdx:github:workflow:hasWritePermissions'),
|
|
463
|
+
"hasIdTokenWrite": $prop($, 'cdx:github:workflow:hasIdTokenWrite')
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
- id: CI-017
|
|
467
|
+
name: "Privileged reusable workflow exports caller-influenced outputs"
|
|
468
|
+
description: "workflow_call producers that both accept caller-controlled inputs and emit outputs from privileged execution contexts can propagate unsafe values into downstream trusted jobs"
|
|
469
|
+
severity: medium
|
|
470
|
+
category: ci-permission
|
|
471
|
+
attack:
|
|
472
|
+
tactics: [TA0003, TA0004]
|
|
473
|
+
condition: |
|
|
474
|
+
$auditWorkflows($)[
|
|
475
|
+
$prop($, 'cdx:github:workflow:isWorkflowCallProducer') = 'true'
|
|
476
|
+
and $safeStr($prop($, 'cdx:github:workflow:workflowCallInputs')) != ''
|
|
477
|
+
and $safeStr($prop($, 'cdx:github:workflow:workflowCallOutputs')) != ''
|
|
478
|
+
and (
|
|
479
|
+
$propBool($, 'cdx:github:workflow:hasWritePermissions') = true
|
|
480
|
+
or $propBool($, 'cdx:github:workflow:hasIdTokenWrite') = true
|
|
481
|
+
)
|
|
482
|
+
]
|
|
483
|
+
location: |
|
|
484
|
+
{
|
|
485
|
+
"bomRef": $."bom-ref",
|
|
486
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
487
|
+
}
|
|
488
|
+
message: "Reusable workflow '{{ $prop($, 'cdx:github:workflow:name') }}' exports outputs from a privileged workflow_call interface that also accepts caller inputs"
|
|
489
|
+
mitigation: "Review workflow_call outputs for trust-boundary crossings, sanitize caller-controlled data before emitting outputs, and avoid combining privileged permissions with broad producer interfaces"
|
|
490
|
+
evidence: |
|
|
491
|
+
{
|
|
492
|
+
"workflowCallInputs": $prop($, 'cdx:github:workflow:workflowCallInputs'),
|
|
493
|
+
"workflowCallOutputs": $prop($, 'cdx:github:workflow:workflowCallOutputs'),
|
|
494
|
+
"hasWritePermissions": $prop($, 'cdx:github:workflow:hasWritePermissions'),
|
|
495
|
+
"hasIdTokenWrite": $prop($, 'cdx:github:workflow:hasIdTokenWrite')
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
- id: CI-018
|
|
499
|
+
name: "Fork-reachable workflow dispatches downstream workflow or repository events"
|
|
500
|
+
description: "Dispatching workflow_dispatch or repository_dispatch from fork-reachable or privileged jobs can create a lateral-movement path into downstream workflows with broader credentials"
|
|
501
|
+
severity: high
|
|
502
|
+
category: ci-permission
|
|
503
|
+
attack:
|
|
504
|
+
tactics: [TA0004, TA0008]
|
|
505
|
+
techniques: [T1528]
|
|
506
|
+
condition: |
|
|
507
|
+
$auditComponents($)[
|
|
508
|
+
$prop($, 'cdx:github:step:dispatchesWorkflow') = 'true'
|
|
509
|
+
and $prop($, 'cdx:github:step:referencesSensitiveContext') = 'true'
|
|
510
|
+
and (
|
|
511
|
+
$propBool($, 'cdx:github:workflow:hasPullRequestTrigger') = true
|
|
512
|
+
or $propBool($, 'cdx:github:workflow:hasPullRequestTargetTrigger') = true
|
|
513
|
+
or $propBool($, 'cdx:github:workflow:hasIssueCommentTrigger') = true
|
|
514
|
+
or $propBool($, 'cdx:github:workflow:hasWorkflowRunTrigger') = true
|
|
515
|
+
or $propBool($, 'cdx:github:workflow:hasWritePermissions') = true
|
|
516
|
+
or $propBool($, 'cdx:github:job:hasWritePermissions') = true
|
|
517
|
+
or $propBool($, 'cdx:github:workflow:hasIdTokenWrite') = true
|
|
518
|
+
or $propBool($, 'cdx:github:job:hasIdTokenWrite') = true
|
|
519
|
+
)
|
|
520
|
+
]
|
|
521
|
+
location: |
|
|
522
|
+
{
|
|
523
|
+
"bomRef": $."bom-ref",
|
|
524
|
+
"purl": purl,
|
|
525
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
526
|
+
}
|
|
527
|
+
message: "Workflow step '{{ name }}' dispatches '{{ $prop($, 'cdx:github:step:dispatchKinds') }}' toward '{{ $prop($, 'cdx:github:step:dispatchTargets') }}' from a fork-reachable or privileged context"
|
|
528
|
+
mitigation: "Avoid chaining downstream workflow_dispatch or repository_dispatch calls from pull-request/fork-reachable jobs; isolate release dispatchers into trusted workflows with narrowly scoped credentials"
|
|
529
|
+
evidence: |
|
|
530
|
+
{
|
|
531
|
+
"dispatchKinds": $prop($, 'cdx:github:step:dispatchKinds'),
|
|
532
|
+
"dispatchMechanisms": $prop($, 'cdx:github:step:dispatchMechanisms'),
|
|
533
|
+
"dispatchTargets": $prop($, 'cdx:github:step:dispatchTargets'),
|
|
534
|
+
"localReceiverWorkflowFiles": $prop($, 'cdx:github:step:dispatchReceiverWorkflowFiles'),
|
|
535
|
+
"localReceiverWorkflowNames": $prop($, 'cdx:github:step:dispatchReceiverWorkflowNames'),
|
|
536
|
+
"sensitiveContextRefs": $prop($, 'cdx:github:step:sensitiveContextRefs'),
|
|
537
|
+
"workflowTriggers": $prop($, 'cdx:github:workflow:triggers'),
|
|
538
|
+
"writeScopes": $prop($, 'cdx:github:workflow:writeScopes')
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
- id: CI-019
|
|
542
|
+
name: "Workflow dispatch step references explicit fork context"
|
|
543
|
+
description: "Dispatch chains that inspect pull_request head-repository or fork context before invoking downstream workflows are strong signals of fork-to-privileged lateral movement"
|
|
544
|
+
severity: critical
|
|
545
|
+
category: ci-permission
|
|
546
|
+
attack:
|
|
547
|
+
tactics: [TA0004, TA0008]
|
|
548
|
+
techniques: [T1528, T1552]
|
|
549
|
+
condition: |
|
|
550
|
+
$auditComponents($)[
|
|
551
|
+
$prop($, 'cdx:github:step:dispatchesWorkflow') = 'true'
|
|
552
|
+
and $prop($, 'cdx:github:step:referencesForkContext') = 'true'
|
|
553
|
+
and $prop($, 'cdx:github:step:referencesSensitiveContext') = 'true'
|
|
554
|
+
and (
|
|
555
|
+
$prop($, 'cdx:github:step:hasLocalDispatchReceiver') = 'true'
|
|
556
|
+
or $safeStr($prop($, 'cdx:github:step:hasLocalDispatchReceiver')) = ''
|
|
557
|
+
)
|
|
558
|
+
]
|
|
559
|
+
location: |
|
|
560
|
+
{
|
|
561
|
+
"bomRef": $."bom-ref",
|
|
562
|
+
"purl": purl,
|
|
563
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
564
|
+
}
|
|
565
|
+
message: "Workflow step '{{ name }}' combines explicit fork/head-repository context with downstream dispatch '{{ $safeStr($prop($, 'cdx:github:step:dispatchReceiverWorkflowNames')) != '' ? $prop($, 'cdx:github:step:dispatchReceiverWorkflowNames') : $prop($, 'cdx:github:step:dispatchTargets') }}'"
|
|
566
|
+
mitigation: "Do not route fork-derived context into workflow_dispatch or repository_dispatch calls. Split privileged follow-up workflows behind trusted branch-only triggers and avoid sharing long-lived tokens into fork-reachable jobs"
|
|
567
|
+
evidence: |
|
|
568
|
+
{
|
|
569
|
+
"forkContextRefs": $prop($, 'cdx:github:step:forkContextRefs'),
|
|
570
|
+
"dispatchKinds": $prop($, 'cdx:github:step:dispatchKinds'),
|
|
571
|
+
"dispatchTargets": $prop($, 'cdx:github:step:dispatchTargets'),
|
|
572
|
+
"hasLocalDispatchReceiver": $prop($, 'cdx:github:step:hasLocalDispatchReceiver'),
|
|
573
|
+
"localReceiverWorkflowFiles": $prop($, 'cdx:github:step:dispatchReceiverWorkflowFiles'),
|
|
574
|
+
"localReceiverWorkflowNames": $prop($, 'cdx:github:step:dispatchReceiverWorkflowNames'),
|
|
575
|
+
"localReceiverMatchBasis": $prop($, 'cdx:github:step:dispatchReceiverMatchBasis'),
|
|
576
|
+
"sensitiveContextRefs": $prop($, 'cdx:github:step:sensitiveContextRefs')
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
- id: CI-020
|
|
580
|
+
name: "pull_request_target checks out PR head or fork context"
|
|
581
|
+
description: "Checking out github.event.pull_request.head.* repository or ref inside pull_request_target executes untrusted fork code with base-repository privileges"
|
|
582
|
+
severity: critical
|
|
583
|
+
category: ci-permission
|
|
584
|
+
attack:
|
|
585
|
+
tactics: [TA0001, TA0004]
|
|
586
|
+
techniques: [T1195.001, T1552]
|
|
587
|
+
condition: |
|
|
588
|
+
$auditComponents($)[
|
|
589
|
+
$contains($nullSafeProp($, 'cdx:github:action:uses'), 'actions/checkout')
|
|
590
|
+
and $prop($, 'cdx:github:workflow:hasPullRequestTargetTrigger') = 'true'
|
|
591
|
+
and (
|
|
592
|
+
$prop($, 'cdx:github:checkout:checksOutUntrustedRef') = 'true'
|
|
593
|
+
or $prop($, 'cdx:github:checkout:referencesForkContext') = 'true'
|
|
594
|
+
)
|
|
595
|
+
]
|
|
596
|
+
location: |
|
|
597
|
+
{
|
|
598
|
+
"bomRef": $."bom-ref",
|
|
599
|
+
"purl": purl,
|
|
600
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
601
|
+
}
|
|
602
|
+
message: "Checkout step '{{ $prop($, 'cdx:github:action:uses') }}' pulls PR head or fork context inside pull_request_target"
|
|
603
|
+
mitigation: "Do not checkout github.event.pull_request.head.* in pull_request_target workflows. Prefer pull_request with read-only permissions or split trusted follow-up work into a separate branch-only workflow"
|
|
604
|
+
evidence: |
|
|
605
|
+
{
|
|
606
|
+
"checkoutRef": $prop($, 'cdx:github:checkout:ref'),
|
|
607
|
+
"checkoutRepository": $prop($, 'cdx:github:checkout:repository'),
|
|
608
|
+
"untrustedRefContexts": $prop($, 'cdx:github:checkout:untrustedRefContexts'),
|
|
609
|
+
"forkContextRefs": $prop($, 'cdx:github:checkout:forkContextRefs'),
|
|
610
|
+
"persistCredentials": $prop($, 'cdx:github:checkout:persistCredentials'),
|
|
611
|
+
"workflowHasWritePermissions": $prop($, 'cdx:github:workflow:hasWritePermissions')
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
- id: CI-021
|
|
615
|
+
name: "Heuristic: high-risk trigger with implicit permissions and sensitive operations"
|
|
616
|
+
description: "High-risk GitHub Actions workflows that omit explicit permissions blocks while still performing sensitive operations may rely on repository-default token scopes. This is a review heuristic, not proof of write access."
|
|
617
|
+
severity: medium
|
|
618
|
+
category: ci-permission
|
|
619
|
+
attack:
|
|
620
|
+
tactics: [TA0004, TA0006]
|
|
621
|
+
techniques: [T1528, T1552]
|
|
622
|
+
condition: |
|
|
623
|
+
$auditComponents($)[
|
|
624
|
+
$prop($, 'cdx:github:workflow:hasHighRiskTrigger') = 'true'
|
|
625
|
+
and $prop($, 'cdx:github:workflow:hasAnyExplicitPermissionsBlock') = 'false'
|
|
626
|
+
and $prop($, 'cdx:github:step:hasSensitiveOperations') = 'true'
|
|
627
|
+
]
|
|
628
|
+
location: |
|
|
629
|
+
{
|
|
630
|
+
"bomRef": $."bom-ref",
|
|
631
|
+
"purl": purl,
|
|
632
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
633
|
+
}
|
|
634
|
+
message: "Heuristic review: workflow '{{ $prop($, 'cdx:github:workflow:name') }}' uses a high-risk trigger without an explicit permissions block while step '{{ $safeStr($prop($, 'cdx:github:step:name')) != '' ? $prop($, 'cdx:github:step:name') : name }}' performs sensitive operation(s) '{{ $prop($, 'cdx:github:step:sensitiveOperations') }}'"
|
|
635
|
+
mitigation: "Add an explicit top-level permissions: block (for example permissions: {}) and re-grant only the minimum per-job scopes needed for the sensitive step"
|
|
636
|
+
evidence: |
|
|
637
|
+
{
|
|
638
|
+
"workflowTriggers": $prop($, 'cdx:github:workflow:triggers'),
|
|
639
|
+
"workflowHasExplicitPermissionsBlock": $prop($, 'cdx:github:workflow:hasExplicitPermissionsBlock'),
|
|
640
|
+
"workflowHasAnyExplicitPermissionsBlock": $prop($, 'cdx:github:workflow:hasAnyExplicitPermissionsBlock'),
|
|
641
|
+
"jobHasExplicitPermissionsBlock": $prop($, 'cdx:github:job:hasExplicitPermissionsBlock'),
|
|
642
|
+
"sensitiveOperations": $prop($, 'cdx:github:step:sensitiveOperations'),
|
|
643
|
+
"sensitiveContextRefs": $prop($, 'cdx:github:step:sensitiveContextRefs'),
|
|
644
|
+
"dispatchKinds": $prop($, 'cdx:github:step:dispatchKinds')
|
|
645
|
+
}
|
|
646
|
+
|