diff --git a/src/audit/cache_poisoning.rs b/src/audit/cache_poisoning.rs index c8cb0ed..f34518d 100644 --- a/src/audit/cache_poisoning.rs +++ b/src/audit/cache_poisoning.rs @@ -4,7 +4,7 @@ use crate::models::{Job, Step, Steps, Uses}; use crate::state::AuditState; use github_actions_models::common::expr::ExplicitExpr; use github_actions_models::common::Env; -use github_actions_models::workflow::event::{BareEvent, OptionalBody}; +use github_actions_models::workflow::event::{BareEvent, BranchFilters, OptionalBody}; use github_actions_models::workflow::job::StepBody; use github_actions_models::workflow::Trigger; use std::ops::Deref; @@ -317,7 +317,19 @@ impl CachePoisoning { Trigger::BareEvent(event) => *event == BareEvent::Release, Trigger::BareEvents(events) => events.contains(&BareEvent::Release), Trigger::Events(events) => match &events.push { - OptionalBody::Body(body) => body.tag_filters.is_some(), + OptionalBody::Body(body) => { + let pushing_new_tag = &body.tag_filters.is_some(); + let pushing_to_release_branch = + if let Some(BranchFilters::Branches(branches)) = &body.branch_filters { + branches + .iter() + .any(|branch| branch.to_lowercase().contains("release")) + } else { + false + }; + + *pushing_new_tag || pushing_to_release_branch + } _ => false, }, } diff --git a/tests/snapshot.rs b/tests/snapshot.rs index 291ca88..5e835db 100644 --- a/tests/snapshot.rs +++ b/tests/snapshot.rs @@ -334,6 +334,12 @@ fn cache_poisoning() -> Result<()> { )) .run()?); + insta::assert_snapshot!(zizmor() + .workflow(workflow_under_test( + "cache-poisoning/workflow-release-branch-trigger.yml" + )) + .run()?); + Ok(()) } diff --git a/tests/snapshots/snapshot__cache_poisoning-13.snap b/tests/snapshots/snapshot__cache_poisoning-13.snap new file mode 100644 index 0000000..9b8a048 --- /dev/null +++ b/tests/snapshots/snapshot__cache_poisoning-13.snap @@ -0,0 +1,22 @@ +--- +source: tests/snapshot.rs +expression: "zizmor().workflow(workflow_under_test(\"cache-poisoning/workflow-release-branch-trigger.yml\")).run()?" +snapshot_kind: text +--- +error[cache-poisoning]: runtime artifacts potentially vulnerable to a cache poisoning attack + --> @@INPUT@@:1:1 + | + 1 | / on: + 2 | | push: + 3 | | branches: + 4 | | - 'release-v2.0.0' + | |________________________^ generally used when publishing artifacts generated at runtime + 5 | +... +15 | - name: Setup CI caching +16 | uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cache enabled by default here + | + = note: audit confidence → Low + +1 finding: 0 unknown, 0 informational, 0 low, 0 medium, 1 high diff --git a/tests/test-data/cache-poisoning/workflow-release-branch-trigger.yml b/tests/test-data/cache-poisoning/workflow-release-branch-trigger.yml new file mode 100644 index 0000000..6a374b7 --- /dev/null +++ b/tests/test-data/cache-poisoning/workflow-release-branch-trigger.yml @@ -0,0 +1,19 @@ +on: + push: + branches: + - 'release-v2.0.0' + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - name: Project Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + persist-credentials: false + + - name: Setup CI caching + uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab + + - name: Publish on crates.io + run: cargo publish --token ${{ secrets.CRATESIO_PUBLISH_TOKEN }}