Files
codeql-lab/codeql-custom-queries-actions/example.ql
2025-06-26 08:59:45 -07:00

62 lines
1.8 KiB
Plaintext

// /**
// * @name Empty block
// * @kind problem
// * @problem.severity warning
// * @id go/example/empty-block
// */
// import actions
// select 1
/**
* @name Unpinned tag for a non-immutable Action in workflow
* @description Using a tag for a non-immutable Action that is not pinned to a commit can lead to executing an untrusted Action through a supply chain attack.
* @kind problem
* @security-severity 5.0
* @problem.severity warning
* @precision medium
* @id actions/unpinned-tag
* @tags security
* actions
* external/cwe/cwe-829
*/
import actions
import codeql.actions.security.UseOfUnversionedImmutableAction
bindingset[version]
private predicate isPinnedCommit(string version) { version.regexpMatch("^[A-Fa-f0-9]{40}$") }
bindingset[nwo]
private predicate isTrustedOwner(string nwo) {
// Gets the segment before the first '/' in the name with owner(nwo) string
trustedActionsOwnerDataModel(nwo.substring(0, nwo.indexOf("/")))
}
bindingset[version]
private predicate isPinnedContainer(string version) {
version.regexpMatch("^sha256:[A-Fa-f0-9]{64}$")
}
bindingset[nwo]
private predicate isContainerImage(string nwo) { nwo.regexpMatch("^docker://.+") }
from UsesStep uses, string nwo, string version, Workflow workflow, string name
where
uses.getCallee() = nwo 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 isTrustedOwner(nwo) and
not (if isContainerImage(nwo) then isPinnedContainer(version) else isPinnedCommit(version)) and
not isImmutableAction(uses, nwo)
select uses.getCalleeNode(),
"Unpinned 3rd party Action '" + name + "' step $@ uses '" + nwo + "' with ref '" + version +
"', not a pinned commit hash", uses, uses.toString()