Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
10 changes: 10 additions & 0 deletions actions/ql/lib/codeql/actions/config/Config.qll
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,13 @@ predicate untrustedGitCommandDataModel(string cmd_regex, string flag) {
predicate untrustedGhCommandDataModel(string cmd_regex, string flag) {
Extensions::untrustedGhCommandDataModel(cmd_regex, flag)
}

/**
* MaD models for permissions needed by actions
* Fields:
* - action: action name
* - permission: permission name
Comment thread
yoff marked this conversation as resolved.
Outdated
*/
predicate actionsPermissionsDataModel(string action, string permission) {
Extensions::actionsPermissionsDataModel(action, permission)
}
10 changes: 10 additions & 0 deletions actions/ql/lib/codeql/actions/config/ConfigExtensions.qll
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,13 @@ extensible predicate untrustedGitCommandDataModel(string cmd_regex, string flag)
* Holds for gh commands that may introduce untrusted data
*/
extensible predicate untrustedGhCommandDataModel(string cmd_regex, string flag);

/**
* Holds if `action` needs `permission` to run.
Comment thread
yoff marked this conversation as resolved.
* - 'action' is the name of the action without any version information.
* E.g. for the action selector `actions/checkout@v2`, `action` is `actions/checkout`.
* - `permission` is of the form `scope-name: read|write`, for example `contents: read`.
* - see https://github.com/actions/checkout?tab=readme-ov-file#recommended-permissions
* for an example of recommended permissions.
Comment thread
yoff marked this conversation as resolved.
*/
extensible predicate actionsPermissionsDataModel(string action, string permission);
37 changes: 37 additions & 0 deletions actions/ql/lib/ext/config/actions_permissions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
extensions:
- addsTo:
pack: codeql/actions-all
extensible: actionsPermissionsDataModel
data:
- ["actions/checkout", "contents: read"]
- ["actions/setup-node", "contents: read"]
- ["actions/setup-python", "contents: read"]
- ["actions/setup-java", "contents: read"]
- ["actions/setup-go", "contents: read"]
- ["actions/setup-dotnet", "contents: read"]
- ["actions/labeler", "contents: read"]
- ["actions/labeler", "pull-requests: write"]
- ["actions/attest", "id-token: write"]
- ["actions/attest", "attestations: write"]
# No permissions needed for actions/add-to-project
- ["actions/dependency-review-action", "contents: read"]
- ["actions/attest-sbom", "id-token: write"]
- ["actions/attest-sbom", "attestations: write"]
- ["actions/stale", "contents: write"]
- ["actions/stale", "issues: write"]
- ["actions/stale", "pull-requests: write"]
- ["actions/attest-build-provenance", "id-token: write"]
- ["actions/attest-build-provenance", "attestations: write"]
- ["actions/jekyll-build-pages", "contents: read"]
- ["actions/jekyll-build-pages", "pages: write"]
- ["actions/jekyll-build-pages", "id-token: write"]
- ["actions/publish-action", "contents: write"]
- ["actions/versions-package-tools", "contents: read"]
- ["actions/versions-package-tools", "actions: read"]
- ["actions/reusable-workflows", "contents: read"]
- ["actions/reusable-workflows", "actions: read"]
# TODO: Add permissions for actions/download-artifact
# TODO: Add permissions for actions/upload-artifact
# TODO: Add permissions for actions/cache


21 changes: 18 additions & 3 deletions actions/ql/src/Security/CWE-275/MissingActionsPermissions.ql
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,28 @@

import actions

from Job job
Step stepInJob(Job job) { result = job.(LocalJob).getAStep() }

string jobNeedsPermission(Job job) {
actionsPermissionsDataModel(stepInJob(job).(UsesStep).getCallee(), result)
}

/** Gets a suggestion for the minimal token permissions for `job`, as a JSON string. */
string permissionsForJob(Job job) {
Comment thread
yoff marked this conversation as resolved.
result =
"{" + concat(string permission | permission = jobNeedsPermission(job) | permission, ", ") + "}"
}

from Job job, string permissions
where
not exists(job.getPermissions()) and
not exists(job.getEnclosingWorkflow().getPermissions()) and
// exists a trigger event that is not a workflow_call
exists(Event e |
e = job.getATriggerEvent() and
not e.getName() = "workflow_call"
)
select job, "Actions Job or Workflow does not set permissions"
) and
permissions = permissionsForJob(job)
select job,
"Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: "
+ permissions
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
on:
workflow_call:
workflow_dispatch:

jobs:
build:
name: Build and test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/jekyll-build-pages


Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
on:
workflow_call:
workflow_dispatch:

jobs:
build:
name: Build and test
runs-on: ubuntu-latest
steps:
- uses: actions/add-to-project@v2
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
| .github/workflows/perms1.yml:6:5:9:32 | Job: build | Actions Job or Workflow does not set permissions |
| .github/workflows/perms2.yml:6:5:10:2 | Job: build | Actions Job or Workflow does not set permissions |
| .github/workflows/perms5.yml:7:5:10:32 | Job: build | Actions Job or Workflow does not set permissions |
| .github/workflows/perms1.yml:6:5:9:32 | Job: build | Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read} |
| .github/workflows/perms2.yml:6:5:10:2 | Job: build | Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read} |
| .github/workflows/perms5.yml:7:5:10:32 | Job: build | Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read} |
| .github/workflows/perms6.yml:7:5:11:39 | Job: build | Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read, id-token: write, pages: write} |
| .github/workflows/perms7.yml:7:5:10:38 | Job: build | Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {} |
Loading