unversioned immutable actions wip

This commit is contained in:
Kylie Stradley
2024-10-17 16:14:03 -04:00
parent 325727ed6d
commit cf9b853a8f
5 changed files with 105 additions and 0 deletions

View File

@@ -119,6 +119,17 @@ predicate vulnerableActionsDataModel(
Extensions::vulnerableActionsDataModel(action, vulnerable_version, vulnerable_sha, fixed_version)
}
/**
* MaD models for vulnerable actions
* Fields:
* - action: action name
*/
predicate immutableActionsDataModel(
string action
) {
Extensions::immutableActionsDataModel(action)
}
/**
* MaD models for untrusted git commands
* Fields:

View File

@@ -58,6 +58,13 @@ extensible predicate vulnerableActionsDataModel(
string action, string vulnerable_version, string vulnerable_sha, string fixed_version
);
/**
* Holds for actions that are known to be immutable.
*/
extensible predicate immutableActionsDataModel(
string action
);
/**
* Holds for git commands that may introduce untrusted data when called on an attacker controlled branch.
*/

View File

@@ -0,0 +1,22 @@
extensions:
- addsTo:
pack: github/actions-all
extensible: immutableActionsDataModel
data:
- ["actions/checkout"]
- ["actions/cache"]
- ["actions/setup-node"]
- ["actions/upload-artifact"]
- ["actions/setup-python"]
- ["actions/download-artifact"]
- ["actions/github-script"]
- ["actions/setup-java"]
- ["actions/setup-go"]
- ["actions/upload-pages-artifact"]
- ["actions/deploy-pages"]
- ["actions/setup-dotnet"]
- ["actions/stale"]
- ["actions/labeler"]
- ["actions/create-github-app-token"]
- ["actions/configure-pages"]
- ["octokit/request-action"]

View File

@@ -0,0 +1,27 @@
# Unpinned tag for 3rd party Action in workflow
## Description
Using a tag for a 3rd party Action that is not pinned to a commit can lead to executing an untrusted Action through a supply chain attack.
## Recommendations
Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release. Pinning to a particular SHA helps mitigate the risk of a bad actor adding a backdoor to the action's repository, as they would need to generate a SHA-1 collision for a valid Git object payload. When selecting a SHA, you should verify it is from the action's repository and not a repository fork.
## Examples
### Incorrect Usage
```yaml
- uses: tj-actions/changed-files@v44
```
### Correct Usage
```yaml
- uses: tj-actions/changed-files@c65cd883420fd2eb864698a825fc4162dd94482c # v44
```
## References
- [Using third-party actions](https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#using-third-party-actions)

View File

@@ -0,0 +1,38 @@
/**
* @name Unversioned Immutable Action
* @description Using an Immutable Action without a semantic version tag opts out of the protections of Immutable Action
* @kind problem
* @security-severity 5.0
* @problem.severity recommendation
* @precision high
* @id actions/unversioned-immutable-action
* @tags security
* actions
* external/cwe/cwe-829
*/
import actions
bindingset[version]
private predicate isSemanticVersioned(string version) { version.regexpMatch("^v[0-9]+(\\.[0-9]+)*(\\.[xX])?$") }
bindingset[repo]
private predicate isTrustedOrg(string repo) {
exists(string org | org in ["actions", "github", "advanced-security", "octokit"] | repo.matches(org + "/%"))
}
from UsesStep uses, string repo, string version, Workflow workflow, string name
where
uses.getCallee() = repo and
uses.getEnclosingWorkflow() = workflow and
(
workflow.getName() = name
or
not exists(workflow.getName()) and workflow.getLocation().getFile().getBaseName() = name
) and
uses.getVersion() = version and
not isTrustedOrg(repo) and
not isPinnedCommit(version)
select uses.getCalleeNode(),
"Unpinned 3rd party Action '" + name + "' step $@ uses '" + repo + "' with ref '" + version +
"', not a pinned commit hash", uses, uses.toString()