diff --git a/ql/lib/codeql/actions/ast/internal/Ast.qll b/ql/lib/codeql/actions/ast/internal/Ast.qll index 7458cc1b053..d05174f4787 100644 --- a/ql/lib/codeql/actions/ast/internal/Ast.qll +++ b/ql/lib/codeql/actions/ast/internal/Ast.qll @@ -417,8 +417,10 @@ class ReusableWorkflowImpl extends AstNodeImpl, WorkflowImpl { override AstNodeImpl getAChildNode() { result.getNode() = n.getAChildNode*() } override EventImpl getATriggerEvent() { + // The trigger event for a reusable workflow is the trigger event of the caller workflow this.getACaller().getEnclosingWorkflow().getOn().getAnEvent() = result or + // or the trigger event of the workflow if it has any other than workflow_call this.getOn().getAnEvent() = result and not result.getName() = "workflow_call" } @@ -803,8 +805,13 @@ class JobImpl extends AstNodeImpl, TJobNode { /** Gets the trigger event that starts this workflow. */ EventImpl getATriggerEvent() { - result = this.getEnclosingWorkflow().getATriggerEvent() or - result = this.getEnclosingWorkflow().(ReusableWorkflowImpl).getACaller().getATriggerEvent() + if this.getEnclosingWorkflow() instanceof ReusableWorkflowImpl + then + result = this.getEnclosingWorkflow().(ReusableWorkflowImpl).getACaller().getATriggerEvent() + or + result = this.getEnclosingWorkflow().getATriggerEvent() and + not result.getName() = "workflow_call" + else result = this.getEnclosingWorkflow().getATriggerEvent() } /** Gets the runs-on field of the job. */ @@ -844,9 +851,8 @@ class JobImpl extends AstNodeImpl, TJobNode { ) } - private predicate hasExplicitWritePermission() { - // the job has an explicit write permission - this.getPermissions().getAPermission().matches("%write") + private predicate hasExplicitNonePermission() { + exists(this.getPermissions()) and not exists(this.getPermissions().getAPermission()) } private predicate hasExplicitReadPermission() { @@ -855,15 +861,57 @@ class JobImpl extends AstNodeImpl, TJobNode { not this.getPermissions().getAPermission().matches("%write") } - private predicate hasImplicitWritePermission() { + private predicate hasExplicitWritePermission() { // the job has an explicit write permission - this.getEnclosingWorkflow().getPermissions().getAPermission().matches("%write") + this.getPermissions().getAPermission().matches("%write") + } + + private predicate hasImplicitNonePermission() { + not exists(this.getPermissions()) and + exists(this.getEnclosingWorkflow().getPermissions()) and + not exists(this.getEnclosingWorkflow().getPermissions().getAPermission()) + or + not exists(this.getPermissions()) and + not exists(this.getEnclosingWorkflow().getPermissions()) and + exists(this.getEnclosingWorkflow().(ReusableWorkflowImpl).getACaller().getPermissions()) and + not exists( + this.getEnclosingWorkflow() + .(ReusableWorkflowImpl) + .getACaller() + .getPermissions() + .getAPermission() + ) } private predicate hasImplicitReadPermission() { // the job has not an explicit write permission + not exists(this.getPermissions()) and exists(this.getEnclosingWorkflow().getPermissions().getAPermission()) and not this.getEnclosingWorkflow().getPermissions().getAPermission().matches("%write") + or + not exists(this.getPermissions()) and + not exists(this.getEnclosingWorkflow().getPermissions()) and + this.getEnclosingWorkflow() + .(ReusableWorkflowImpl) + .getACaller() + .getPermissions() + .getAPermission() + .matches("%read") + } + + private predicate hasImplicitWritePermission() { + // the job has an explicit write permission + not exists(this.getPermissions()) and + this.getEnclosingWorkflow().getPermissions().getAPermission().matches("%write") + or + not exists(this.getPermissions()) and + not exists(this.getEnclosingWorkflow().getPermissions()) and + this.getEnclosingWorkflow() + .(ReusableWorkflowImpl) + .getACaller() + .getPermissions() + .getAPermission() + .matches("%write") } private predicate hasRuntimeData() { @@ -922,6 +970,8 @@ class JobImpl extends AstNodeImpl, TJobNode { // and the job is not explicitly non-privileged not ( ( + this.hasExplicitNonePermission() or + this.hasImplicitNonePermission() or this.hasExplicitReadPermission() or this.hasImplicitReadPermission() ) and diff --git a/ql/lib/codeql/actions/security/ControlChecks.qll b/ql/lib/codeql/actions/security/ControlChecks.qll index 1a47f4d92d0..1a3e1e15fe8 100644 --- a/ql/lib/codeql/actions/security/ControlChecks.qll +++ b/ql/lib/codeql/actions/security/ControlChecks.qll @@ -38,7 +38,7 @@ abstract class ControlCheck extends AstNode { } predicate protects(Step step, Event event, string category) { - event.getEnclosingWorkflow() = step.getEnclosingWorkflow() and + event = step.getEnclosingWorkflow().getATriggerEvent() and this.dominates(step) and this.protectsCategoryAndEvent(category, event.getName()) } diff --git a/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql b/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql index 9efd9b036cd..31a4cdf94e5 100644 --- a/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql +++ b/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql @@ -20,39 +20,28 @@ import codeql.actions.security.ControlChecks query predicate edges(Step a, Step b) { a.getNextStep() = b } -from PRHeadCheckoutStep checkout, PoisonableStep step +from PRHeadCheckoutStep checkout, PoisonableStep step, Event event where // the checkout is followed by a known poisonable step checkout.getAFollowingStep() = step and // the checkout occurs in a privileged context inPrivilegedContext(checkout) and + event = checkout.getEnclosingJob().getATriggerEvent() and ( // issue_comment: check for date comparison checks and actor/access control checks - exists(Event event | - event = checkout.getEnclosingJob().getATriggerEvent() and + event.getName() = "issue_comment" and + not exists(ControlCheck check, CommentVsHeadDateCheck date_check | ( - event.getName() = "issue_comment" - or - event.getName() = "workflow_call" and - checkout.getEnclosingWorkflow().(ReusableWorkflow).getACaller().getATriggerEvent().getName() = - "issue_comment" + check instanceof ActorCheck or + check instanceof AssociationCheck or + check instanceof PermissionCheck ) and - not exists(ControlCheck check, CommentVsHeadDateCheck date_check | - ( - check instanceof ActorCheck or - check instanceof AssociationCheck or - check instanceof PermissionCheck - ) and - check.dominates(checkout) and - date_check.dominates(checkout) - ) + check.dominates(checkout) and + date_check.dominates(checkout) ) or // not issue_comment triggered workflows - exists(Event event | - not event.getName() = "issue_comment" and - event = checkout.getEnclosingJob().getATriggerEvent() and - not exists(ControlCheck check | check.protects(checkout, event, "untrusted-checkout")) - ) + not event.getName() = "issue_comment" and + not exists(ControlCheck check | check.protects(checkout, event, "untrusted-checkout")) ) select step, checkout, step, "Execution of untrusted code on a privileged workflow." diff --git a/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql b/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql index ce138fb0478..bc6f0e36e56 100644 --- a/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql +++ b/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql @@ -18,39 +18,28 @@ import codeql.actions.security.UntrustedCheckoutQuery import codeql.actions.security.PoisonableSteps import codeql.actions.security.ControlChecks -from PRHeadCheckoutStep checkout +from PRHeadCheckoutStep checkout, Event event where // the checkout is NOT followed by a known poisonable step not checkout.getAFollowingStep() instanceof PoisonableStep and // the checkout occurs in a privileged context inPrivilegedContext(checkout) and + event = checkout.getEnclosingJob().getATriggerEvent() and ( // issue_comment: check for date comparison checks and actor/access control checks - exists(Event event | - event = checkout.getEnclosingJob().getATriggerEvent() and + event.getName() = "issue_comment" and + not exists(ControlCheck check, CommentVsHeadDateCheck date_check | ( - event.getName() = "issue_comment" - or - event.getName() = "workflow_call" and - checkout.getEnclosingWorkflow().(ReusableWorkflow).getACaller().getATriggerEvent().getName() = - "issue_comment" + check instanceof ActorCheck or + check instanceof AssociationCheck or + check instanceof PermissionCheck ) and - not exists(ControlCheck check, CommentVsHeadDateCheck date_check | - ( - check instanceof ActorCheck or - check instanceof AssociationCheck or - check instanceof PermissionCheck - ) and - check.dominates(checkout) and - date_check.dominates(checkout) - ) + check.dominates(checkout) and + date_check.dominates(checkout) ) or // not issue_comment triggered workflows - exists(Event event | - not event.getName() = "issue_comment" and - event = checkout.getEnclosingJob().getATriggerEvent() and - not exists(ControlCheck check | check.protects(checkout, event, "untrusted-checkout")) - ) + not event.getName() = "issue_comment" and + not exists(ControlCheck check | check.protects(checkout, event, "untrusted-checkout")) ) select checkout, "Potential execution of untrusted code on a privileged workflow." diff --git a/ql/test/query-tests/Security/CWE-078/.github/workflows/documentation.yml b/ql/test/query-tests/Security/CWE-078/.github/workflows/documentation.yml index 46ffbce9628..db04b69ac16 100644 --- a/ql/test/query-tests/Security/CWE-078/.github/workflows/documentation.yml +++ b/ql/test/query-tests/Security/CWE-078/.github/workflows/documentation.yml @@ -2,7 +2,7 @@ name: Documentation on: workflow_dispatch: - workflow_call: + pull_request: jobs: parse_commit_info: diff --git a/ql/test/query-tests/Security/CWE-078/CommandInjectionCritical.expected b/ql/test/query-tests/Security/CWE-078/CommandInjectionCritical.expected index e2fe23cccc6..decabad082f 100644 --- a/ql/test/query-tests/Security/CWE-078/CommandInjectionCritical.expected +++ b/ql/test/query-tests/Security/CWE-078/CommandInjectionCritical.expected @@ -1,8 +1,6 @@ edges nodes | .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | semmle.label | github.event.comment.body | -| .github/workflows/documentation.yml:87:28:87:66 | github.event.head_commit.message | semmle.label | github.event.head_commit.message | subpaths #select | .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | Potential command injection in $@, which may be controlled by an external user. | .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | ${{ github.event.comment.body }} | -| .github/workflows/documentation.yml:87:28:87:66 | github.event.head_commit.message | .github/workflows/documentation.yml:87:28:87:66 | github.event.head_commit.message | .github/workflows/documentation.yml:87:28:87:66 | github.event.head_commit.message | Potential command injection in $@, which may be controlled by an external user. | .github/workflows/documentation.yml:87:28:87:66 | github.event.head_commit.message | ${{ github.event.head_commit.message }} | diff --git a/ql/test/query-tests/Security/CWE-078/CommandInjectionMedium.expected b/ql/test/query-tests/Security/CWE-078/CommandInjectionMedium.expected index ebbf2f7cf0b..99ebb1edc05 100644 --- a/ql/test/query-tests/Security/CWE-078/CommandInjectionMedium.expected +++ b/ql/test/query-tests/Security/CWE-078/CommandInjectionMedium.expected @@ -1,6 +1,5 @@ edges nodes | .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | semmle.label | github.event.comment.body | -| .github/workflows/documentation.yml:87:28:87:66 | github.event.head_commit.message | semmle.label | github.event.head_commit.message | subpaths #select diff --git a/ql/test/query-tests/Security/CWE-094/.github/workflows/reusable-workflow-caller-1.yml b/ql/test/query-tests/Security/CWE-094/.github/workflows/reusable-workflow-caller-1.yml index 9c0b72dffea..a237856b6ce 100644 --- a/ql/test/query-tests/Security/CWE-094/.github/workflows/reusable-workflow-caller-1.yml +++ b/ql/test/query-tests/Security/CWE-094/.github/workflows/reusable-workflow-caller-1.yml @@ -1,11 +1,11 @@ name: Caller on: - issue_comment: + pull_request_target: jobs: test: permissions: {} uses: ./.github/workflows/reusable-workflow-1.yml with: - taint: ${{ github.event.comment.body }} + taint: ${{ github.event.pull_request.title }} diff --git a/ql/test/query-tests/Security/CWE-094/.github/workflows/reusable-workflow-caller-2.yml b/ql/test/query-tests/Security/CWE-094/.github/workflows/reusable-workflow-caller-2.yml index 46be8d7009d..0f87d1e9394 100644 --- a/ql/test/query-tests/Security/CWE-094/.github/workflows/reusable-workflow-caller-2.yml +++ b/ql/test/query-tests/Security/CWE-094/.github/workflows/reusable-workflow-caller-2.yml @@ -1,10 +1,10 @@ name: Caller on: - issue_comment: + pull_request_target: jobs: test: uses: ./.github/workflows/reusable-workflow-2.yml with: - taint: ${{ github.event.comment.body }} + taint: ${{ github.event.pull_request.title }} diff --git a/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected b/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected index 9ebd5508802..818b106b6d7 100644 --- a/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected +++ b/ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected @@ -70,8 +70,8 @@ edges | .github/workflows/reusable-workflow-1.yml:44:19:44:56 | github.event.pull_request.title | .github/workflows/reusable-workflow-1.yml:53:26:53:39 | env.log | provenance | | | .github/workflows/reusable-workflow-2.yml:6:7:6:11 | input taint | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | provenance | | | .github/workflows/reusable-workflow-2.yml:44:19:44:56 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | provenance | | -| .github/workflows/reusable-workflow-caller-1.yml:11:15:11:46 | github.event.comment.body | .github/workflows/reusable-workflow-1.yml:6:7:6:11 | input taint | provenance | | -| .github/workflows/reusable-workflow-caller-2.yml:10:15:10:46 | github.event.comment.body | .github/workflows/reusable-workflow-2.yml:6:7:6:11 | input taint | provenance | | +| .github/workflows/reusable-workflow-caller-1.yml:11:15:11:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-1.yml:6:7:6:11 | input taint | provenance | | +| .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:6:7:6:11 | input taint | provenance | | | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | provenance | | | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | provenance | | | .github/workflows/self_needs.yml:13:9:19:6 | Uses Step: source [value] | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | provenance | | @@ -287,8 +287,8 @@ nodes | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | semmle.label | inputs.taint | | .github/workflows/reusable-workflow-2.yml:44:19:44:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | semmle.label | env.log | -| .github/workflows/reusable-workflow-caller-1.yml:11:15:11:46 | github.event.comment.body | semmle.label | github.event.comment.body | -| .github/workflows/reusable-workflow-caller-2.yml:10:15:10:46 | github.event.comment.body | semmle.label | github.event.comment.body | +| .github/workflows/reusable-workflow-caller-1.yml:11:15:11:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | +| .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | semmle.label | Job outputs node [job_output] | | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | semmle.label | steps.source.outputs.value | | .github/workflows/self_needs.yml:13:9:19:6 | Uses Step: source [value] | semmle.label | Uses Step: source [value] | @@ -451,9 +451,7 @@ subpaths | .github/workflows/pull_request_target.yml:14:19:14:69 | github.event.pull_request.head.repo.homepage | .github/workflows/pull_request_target.yml:14:19:14:69 | github.event.pull_request.head.repo.homepage | .github/workflows/pull_request_target.yml:14:19:14:69 | github.event.pull_request.head.repo.homepage | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/pull_request_target.yml:14:19:14:69 | github.event.pull_request.head.repo.homepage | ${{ github.event.pull_request.head.repo.homepage }} | | .github/workflows/pull_request_target.yml:15:19:15:59 | github.event.pull_request.head.ref | .github/workflows/pull_request_target.yml:15:19:15:59 | github.event.pull_request.head.ref | .github/workflows/pull_request_target.yml:15:19:15:59 | github.event.pull_request.head.ref | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/pull_request_target.yml:15:19:15:59 | github.event.pull_request.head.ref | ${{ github.event.pull_request.head.ref }} | | .github/workflows/pull_request_target.yml:16:19:16:40 | github.head_ref | .github/workflows/pull_request_target.yml:16:19:16:40 | github.head_ref | .github/workflows/pull_request_target.yml:16:19:16:40 | github.head_ref | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/pull_request_target.yml:16:19:16:40 | github.head_ref | ${{ github.head_ref }} | -| .github/workflows/reusable-workflow-1.yml:36:21:36:39 | inputs.taint | .github/workflows/reusable-workflow-caller-1.yml:11:15:11:46 | github.event.comment.body | .github/workflows/reusable-workflow-1.yml:36:21:36:39 | inputs.taint | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/reusable-workflow-1.yml:36:21:36:39 | inputs.taint | ${{ inputs.taint }} | -| .github/workflows/reusable-workflow-1.yml:53:26:53:39 | env.log | .github/workflows/reusable-workflow-1.yml:44:19:44:56 | github.event.pull_request.title | .github/workflows/reusable-workflow-1.yml:53:26:53:39 | env.log | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/reusable-workflow-1.yml:53:26:53:39 | env.log | ${{ env.log }} | -| .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | .github/workflows/reusable-workflow-caller-2.yml:10:15:10:46 | github.event.comment.body | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | ${{ inputs.taint }} | +| .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | ${{ inputs.taint }} | | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | .github/workflows/reusable-workflow-2.yml:44:19:44:56 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | ${{ env.log }} | | .github/workflows/self_needs.yml:19:15:19:47 | steps.source.outputs.value | .github/workflows/self_needs.yml:16:20:16:57 | github.event['comment']['body'] | .github/workflows/self_needs.yml:19:15:19:47 | steps.source.outputs.value | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/self_needs.yml:19:15:19:47 | steps.source.outputs.value | ${{ steps.source.outputs.value }} | | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | .github/workflows/self_needs.yml:16:20:16:57 | github.event['comment']['body'] | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | ${{ needs.test1.outputs.job_output }} | diff --git a/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected b/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected index 26d4741a469..75b64cea3e5 100644 --- a/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected +++ b/ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected @@ -70,8 +70,8 @@ edges | .github/workflows/reusable-workflow-1.yml:44:19:44:56 | github.event.pull_request.title | .github/workflows/reusable-workflow-1.yml:53:26:53:39 | env.log | provenance | | | .github/workflows/reusable-workflow-2.yml:6:7:6:11 | input taint | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | provenance | | | .github/workflows/reusable-workflow-2.yml:44:19:44:56 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | provenance | | -| .github/workflows/reusable-workflow-caller-1.yml:11:15:11:46 | github.event.comment.body | .github/workflows/reusable-workflow-1.yml:6:7:6:11 | input taint | provenance | | -| .github/workflows/reusable-workflow-caller-2.yml:10:15:10:46 | github.event.comment.body | .github/workflows/reusable-workflow-2.yml:6:7:6:11 | input taint | provenance | | +| .github/workflows/reusable-workflow-caller-1.yml:11:15:11:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-1.yml:6:7:6:11 | input taint | provenance | | +| .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:6:7:6:11 | input taint | provenance | | | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | provenance | | | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | provenance | | | .github/workflows/self_needs.yml:13:9:19:6 | Uses Step: source [value] | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | provenance | | @@ -287,8 +287,8 @@ nodes | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | semmle.label | inputs.taint | | .github/workflows/reusable-workflow-2.yml:44:19:44:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | semmle.label | env.log | -| .github/workflows/reusable-workflow-caller-1.yml:11:15:11:46 | github.event.comment.body | semmle.label | github.event.comment.body | -| .github/workflows/reusable-workflow-caller-2.yml:10:15:10:46 | github.event.comment.body | semmle.label | github.event.comment.body | +| .github/workflows/reusable-workflow-caller-1.yml:11:15:11:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | +| .github/workflows/reusable-workflow-caller-2.yml:10:15:10:52 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/self_needs.yml:11:7:12:4 | Job outputs node [job_output] | semmle.label | Job outputs node [job_output] | | .github/workflows/self_needs.yml:11:20:11:52 | steps.source.outputs.value | semmle.label | steps.source.outputs.value | | .github/workflows/self_needs.yml:13:9:19:6 | Uses Step: source [value] | semmle.label | Uses Step: source [value] | @@ -414,10 +414,8 @@ subpaths | .github/workflows/push.yml:14:19:14:64 | github.event.head_commit.committer.name | .github/workflows/push.yml:14:19:14:64 | github.event.head_commit.committer.name | .github/workflows/push.yml:14:19:14:64 | github.event.head_commit.committer.name | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:14:19:14:64 | github.event.head_commit.committer.name | ${{ github.event.head_commit.committer.name }} | | .github/workflows/push.yml:15:19:15:65 | github.event.commits[11].committer.email | .github/workflows/push.yml:15:19:15:65 | github.event.commits[11].committer.email | .github/workflows/push.yml:15:19:15:65 | github.event.commits[11].committer.email | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:15:19:15:65 | github.event.commits[11].committer.email | ${{ github.event.commits[11].committer.email }} | | .github/workflows/push.yml:16:19:16:64 | github.event.commits[11].committer.name | .github/workflows/push.yml:16:19:16:64 | github.event.commits[11].committer.name | .github/workflows/push.yml:16:19:16:64 | github.event.commits[11].committer.name | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:16:19:16:64 | github.event.commits[11].committer.name | ${{ github.event.commits[11].committer.name }} | -| .github/workflows/reusable-workflow-1.yml:36:21:36:39 | inputs.taint | .github/workflows/reusable-workflow-caller-1.yml:11:15:11:46 | github.event.comment.body | .github/workflows/reusable-workflow-1.yml:36:21:36:39 | inputs.taint | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/reusable-workflow-1.yml:36:21:36:39 | inputs.taint | ${{ inputs.taint }} | +| .github/workflows/reusable-workflow-1.yml:36:21:36:39 | inputs.taint | .github/workflows/reusable-workflow-caller-1.yml:11:15:11:52 | github.event.pull_request.title | .github/workflows/reusable-workflow-1.yml:36:21:36:39 | inputs.taint | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/reusable-workflow-1.yml:36:21:36:39 | inputs.taint | ${{ inputs.taint }} | | .github/workflows/reusable-workflow-1.yml:53:26:53:39 | env.log | .github/workflows/reusable-workflow-1.yml:44:19:44:56 | github.event.pull_request.title | .github/workflows/reusable-workflow-1.yml:53:26:53:39 | env.log | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/reusable-workflow-1.yml:53:26:53:39 | env.log | ${{ env.log }} | -| .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | .github/workflows/reusable-workflow-caller-2.yml:10:15:10:46 | github.event.comment.body | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/reusable-workflow-2.yml:36:21:36:39 | inputs.taint | ${{ inputs.taint }} | -| .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | .github/workflows/reusable-workflow-2.yml:44:19:44:56 | github.event.pull_request.title | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/reusable-workflow-2.yml:53:26:53:39 | env.log | ${{ env.log }} | | .github/workflows/simple1.yml:16:18:16:49 | steps.summary.outputs.value | .github/workflows/simple1.yml:11:20:11:58 | github.event.head_commit.message | .github/workflows/simple1.yml:16:18:16:49 | steps.summary.outputs.value | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/simple1.yml:16:18:16:49 | steps.summary.outputs.value | ${{steps.summary.outputs.value}} | | .github/workflows/test10.yml:57:34:57:77 | github.event.workflow_run.head_branch | .github/workflows/test10.yml:57:34:57:77 | github.event.workflow_run.head_branch | .github/workflows/test10.yml:57:34:57:77 | github.event.workflow_run.head_branch | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test10.yml:57:34:57:77 | github.event.workflow_run.head_branch | ${{ github.event.workflow_run.head_branch }} | | .github/workflows/test10.yml:147:34:147:77 | github.event.workflow_run.head_branch | .github/workflows/test10.yml:147:34:147:77 | github.event.workflow_run.head_branch | .github/workflows/test10.yml:147:34:147:77 | github.event.workflow_run.head_branch | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test10.yml:147:34:147:77 | github.event.workflow_run.head_branch | ${{ github.event.workflow_run.head_branch }} | diff --git a/ql/test/query-tests/Security/CWE-829/.github/workflows/reusable_caller3.yaml b/ql/test/query-tests/Security/CWE-829/.github/workflows/reusable_caller3.yaml index 1e7558b3bc0..560475dc938 100644 --- a/ql/test/query-tests/Security/CWE-829/.github/workflows/reusable_caller3.yaml +++ b/ql/test/query-tests/Security/CWE-829/.github/workflows/reusable_caller3.yaml @@ -1,7 +1,7 @@ name: assets-test on: - pull_request: + pull_request_target: jobs: check-execution-context: diff --git a/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected b/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected index 4fbfca24126..13637396f90 100644 --- a/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected +++ b/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected @@ -255,7 +255,6 @@ edges | .github/workflows/gitcheckout.yml:21:11:23:22 | Run Step | .github/workflows/gitcheckout.yml:10:11:18:8 | Run Step | .github/workflows/gitcheckout.yml:21:11:23:22 | Run Step | Execution of untrusted code on a privileged workflow. | | .github/workflows/level0.yml:107:9:112:2 | Run Step | .github/workflows/level0.yml:99:9:103:6 | Uses Step | .github/workflows/level0.yml:107:9:112:2 | Run Step | Execution of untrusted code on a privileged workflow. | | .github/workflows/level0.yml:133:9:135:23 | Run Step | .github/workflows/level0.yml:125:9:129:6 | Uses Step | .github/workflows/level0.yml:133:9:135:23 | Run Step | Execution of untrusted code on a privileged workflow. | -| .github/workflows/mend.yml:29:9:33:28 | Uses Step | .github/workflows/mend.yml:22:9:29:6 | Uses Step | .github/workflows/mend.yml:29:9:33:28 | Uses Step | Execution of untrusted code on a privileged workflow. | | .github/workflows/poc2.yml:42:9:47:6 | Uses Step | .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:42:9:47:6 | Uses Step | Execution of untrusted code on a privileged workflow. | | .github/workflows/poc2.yml:52:9:58:24 | Run Step | .github/workflows/poc2.yml:37:9:42:6 | Uses Step | .github/workflows/poc2.yml:52:9:58:24 | Run Step | Execution of untrusted code on a privileged workflow. | | .github/workflows/pr-workflow.yml:222:9:227:6 | Uses Step | .github/workflows/pr-workflow.yml:216:9:222:6 | Uses Step | .github/workflows/pr-workflow.yml:222:9:227:6 | Uses Step | Execution of untrusted code on a privileged workflow. | @@ -273,7 +272,6 @@ edges | .github/workflows/test7.yml:33:9:36:6 | Run Step | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:33:9:36:6 | Run Step | Execution of untrusted code on a privileged workflow. | | .github/workflows/test7.yml:36:9:39:6 | Run Step | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:36:9:39:6 | Run Step | Execution of untrusted code on a privileged workflow. | | .github/workflows/test7.yml:49:9:58:20 | Run Step: benchmark-pr | .github/workflows/test7.yml:19:9:24:6 | Uses Step | .github/workflows/test7.yml:49:9:58:20 | Run Step: benchmark-pr | Execution of untrusted code on a privileged workflow. | -| .github/workflows/test9.yml:16:9:17:48 | Run Step | .github/workflows/test9.yml:11:9:16:6 | Uses Step | .github/workflows/test9.yml:16:9:17:48 | Run Step | Execution of untrusted code on a privileged workflow. | | .github/workflows/test10.yml:25:9:30:2 | Run Step | .github/workflows/test10.yml:20:9:25:6 | Uses Step | .github/workflows/test10.yml:25:9:30:2 | Run Step | Execution of untrusted code on a privileged workflow. | | .github/workflows/test11.yml:90:7:93:54 | Uses Step | .github/workflows/test11.yml:84:7:90:4 | Uses Step | .github/workflows/test11.yml:90:7:93:54 | Uses Step | Execution of untrusted code on a privileged workflow. | | .github/workflows/untrusted_checkout4.yml:61:7:67:4 | Run Step | .github/workflows/untrusted_checkout4.yml:55:7:61:4 | Uses Step | .github/workflows/untrusted_checkout4.yml:61:7:67:4 | Run Step | Execution of untrusted code on a privileged workflow. | diff --git a/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutHigh.expected b/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutHigh.expected index 181bd5673bc..81a8c63c882 100644 --- a/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutHigh.expected +++ b/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutHigh.expected @@ -1,7 +1,3 @@ -| .github/workflows/issue_comment_3rd_party_action.yml:16:9:22:2 | Uses Step | Potential execution of untrusted code on a privileged workflow. | -| .github/workflows/issue_comment_3rd_party_action.yml:30:9:36:2 | Uses Step | Potential execution of untrusted code on a privileged workflow. | -| .github/workflows/issue_comment_3rd_party_action.yml:45:9:49:6 | Uses Step | Potential execution of untrusted code on a privileged workflow. | -| .github/workflows/issue_comment_3rd_party_action.yml:49:9:52:25 | Uses Step | Potential execution of untrusted code on a privileged workflow. | | .github/workflows/issue_comment_direct.yml:12:9:16:2 | Uses Step | Potential execution of untrusted code on a privileged workflow. | | .github/workflows/issue_comment_direct.yml:20:9:24:2 | Uses Step | Potential execution of untrusted code on a privileged workflow. | | .github/workflows/issue_comment_direct.yml:28:9:32:2 | Uses Step | Potential execution of untrusted code on a privileged workflow. | diff --git a/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutMedium.expected b/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutMedium.expected index eb9fcc2418a..29237c9a544 100644 --- a/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutMedium.expected +++ b/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutMedium.expected @@ -4,9 +4,15 @@ | .github/workflows/dependabot1.yml:15:9:19:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. | | .github/workflows/dependabot1.yml:39:9:43:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. | | .github/workflows/dependabot2.yml:33:9:38:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. | +| .github/workflows/issue_comment_3rd_party_action.yml:16:9:22:2 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. | +| .github/workflows/issue_comment_3rd_party_action.yml:30:9:36:2 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. | +| .github/workflows/issue_comment_3rd_party_action.yml:45:9:49:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. | +| .github/workflows/issue_comment_3rd_party_action.yml:49:9:52:25 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. | +| .github/workflows/mend.yml:22:9:29:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. | | .github/workflows/poc3.yml:18:7:25:4 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. | | .github/workflows/poc.yml:30:9:36:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. | | .github/workflows/priv_pull_request_checkout.yml:14:9:20:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. | | .github/workflows/test3.yml:28:9:33:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. | | .github/workflows/test4.yml:18:7:25:4 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. | | .github/workflows/test8.yml:20:9:26:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. | +| .github/workflows/test9.yml:11:9:16:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |