| Field | Value |
|---|---|
| Category | CICD-SEC-1 |
| Rule ID | cicd-sec-1-workflow-run-artifact-poisoning |
| Severity | HIGH |
| OWASP | CICD-SEC-1: Insufficient Flow Control Mechanisms |
| Auto-fix | ✗ |
What the check does
Fires only on workflows triggered byworkflow_run. Within those, it flags any step that downloads artifacts produced by the triggering run:
uses: actions/download-artifact(any version)uses: dawidd6/action-download-artifact- an inline
run:containinggh run download
Why it matters
Theworkflow_run event runs in the base repository’s privileged context — with repository secrets and a token — after another workflow (often the fork-PR pull_request build) completes. Artifacts uploaded by that first workflow are attacker-controlled: a fork PR can put anything in them. If the workflow_run workflow downloads those artifacts and then executes them, unzips them over the workspace, or echoes their contents into a privileged step, the attacker achieves code execution or content injection with secrets in scope.
This is the “artifact poisoning” half of the classic pull_request → workflow_run escalation.
Vulnerable example
Safe alternatives
- Treat downloaded artifacts as untrusted data: validate their shape and contents before use, and never execute them or feed them into a step holding secrets.
- Prefer reading the PR metadata you actually need from the
workflow_runevent payload rather than round-tripping it through an artifact. - If you only need to post a comment or status, do the privileged action with values you control, not values read from the artifact.