This is an idea I've been bouncing around in my head for a while.
TL;DR: setup-uv could disable caching by default when it detects that it's being run from a release-shaped trigger. In practice that means the release trigger plus tag-push events.
Summary
GitHub Actions caching is unfortunately not very secure, and is very easy to poison across workflows/jobs.
We've seen attackers successfully use this to pivot from a low-privilege/low-risk job (like a build step) to a high-privilege one, since cache write access isn't disabled when the user does permissions: {}.
The solution is to never load from cache in "sensitive" jobs. In practice that means that jobs that publish release artifacts, for example, should always run fully uncached (but should of course use a locked resolution).
Proposed solution
setup-uv could check what trigger it was invoked under, and modify its caching behavior based on that trigger.
This should be straightforward to do: every GHA job gets a GITHUB_EVENT_PATH variable, which points to the full webhook payload, which in turn reveals the trigger. GITHUB_EVENT_NAME also exposes the bare event name itself, which is sufficient for e.g. release events.
Here's a (different) example of those being read from:
https://github.com/pypa/gh-action-pypi-publish/blob/dc37677b2e1c63e2034f94d8a5b11f265b73ba33/oidc-exchange.py#L286-L308
Concretely, when the user sets enable-cache: auto, we should disable it under the following new conditions:
- The workflow trigger is
pull_request_target or workflow_run (fundamentally insecure)
- The workflow trigger is
release or push with tags (indicates a release flow)
Other context
This would also hush a bunch of findings that come out of zizmor's cache-poisoning audit -- in particular it currently flags most setup-uv invocations since they restore from the cache by default, but if that changes then zizmor can stop emitting those 🙂
This is an idea I've been bouncing around in my head for a while.
TL;DR:
setup-uvcould disable caching by default when it detects that it's being run from a release-shaped trigger. In practice that means thereleasetrigger plus tag-push events.Summary
GitHub Actions caching is unfortunately not very secure, and is very easy to poison across workflows/jobs.
We've seen attackers successfully use this to pivot from a low-privilege/low-risk job (like a build step) to a high-privilege one, since cache write access isn't disabled when the user does
permissions: {}.The solution is to never load from cache in "sensitive" jobs. In practice that means that jobs that publish release artifacts, for example, should always run fully uncached (but should of course use a locked resolution).
Proposed solution
setup-uv could check what trigger it was invoked under, and modify its caching behavior based on that trigger.
This should be straightforward to do: every GHA job gets a
GITHUB_EVENT_PATHvariable, which points to the full webhook payload, which in turn reveals the trigger.GITHUB_EVENT_NAMEalso exposes the bare event name itself, which is sufficient for e.g.releaseevents.Here's a (different) example of those being read from:
https://github.com/pypa/gh-action-pypi-publish/blob/dc37677b2e1c63e2034f94d8a5b11f265b73ba33/oidc-exchange.py#L286-L308
Concretely, when the user sets
enable-cache: auto, we should disable it under the following new conditions:pull_request_targetorworkflow_run(fundamentally insecure)releaseorpushwith tags (indicates a release flow)Other context
This would also hush a bunch of findings that come out of zizmor's
cache-poisoningaudit -- in particular it currently flags mostsetup-uvinvocations since they restore from the cache by default, but if that changes then zizmor can stop emitting those 🙂