You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/pentesting-ci-cd/github-security/abusing-github-actions/README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -481,6 +481,7 @@ GitHub exposes a cross-workflow cache that is keyed only by the string you suppl
481
481
- Cache entries are shared across workflows and branches whenever the `key` or `restore-keys` match. GitHub does not scope them to trust levels.
482
482
- Saving to the cache is allowed even when the job supposedly has read-only repository permissions, so “safe” workflows can still poison high-trust caches.
483
483
- Official actions (`setup-node`, `setup-python`, dependency caches, etc.) frequently reuse deterministic keys, so identifying the correct key is trivial once the workflow file is public.
484
+
- Restores are just zstd tarball extractions with no integrity checks, so poisoned caches can overwrite scripts, `package.json`, or other files under the restore path.
484
485
485
486
**Mitigations**
486
487
@@ -806,4 +807,3 @@ An organization in GitHub is very proactive in reporting accounts to GitHub. All
Copy file name to clipboardExpand all lines: src/pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-cache-poisoning.md
+15Lines changed: 15 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,7 +10,10 @@ The GitHub Actions cache is global to a repository. Any workflow that knows a ca
10
10
11
11
-`actions/cache` exposes both restore and save operations (`actions/cache@v4`, `actions/cache/save@v4`, `actions/cache/restore@v4`). The save call is allowed for any job except truly untrusted `pull_request` workflows triggered from forks.
12
12
- Cache entries are identified solely by the `key`. Broad `restore-keys` make it easy to inject payloads because the attacker only needs to collide with a prefix.
13
+
- Cache keys and versions are client-specified values; the cache service does not validate that a key/version matches a trusted workflow or cache path.
14
+
- The cache server URL + runtime token are long-lived relative to the workflow (historically ~6 hours, now ~90 minutes) and are not user-revocable. As of late 2024 GitHub blocks cache writes after the originating job completes, so attackers must write while the job is still running or pre-poison future keys.
13
15
- The cached filesystem is restored verbatim. If the cache contains scripts or binaries that are executed later, the attacker controls that execution path.
16
+
- The cache file itself is not validated on restore; it is just a zstd-compressed archive, so a poisoned entry can overwrite scripts, `package.json`, or other files under the restore path.
14
17
15
18
## Example exploitation chain
16
19
@@ -41,6 +44,16 @@ steps:
41
44
42
45
The second job now runs attacker-controlled code while holding release credentials (PyPI tokens, PATs, cloud deploy keys, etc.).
43
46
47
+
## Poisoning mechanics
48
+
49
+
GitHub Actions cache entries are typically zstd-compressed tar archives. You can craft one locally and upload it to the cache:
50
+
51
+
```bash
52
+
tar --zstd -cf poisoned_cache.tzstd cache/contents/here
53
+
```
54
+
55
+
On a cache hit, the restore action will extract the archive as-is. If the cache path includes scripts or config files that are executed later (build tooling, `action.yml`, `package.json`, etc.), you can overwrite them to gain execution.
56
+
44
57
## Practical exploitation tips
45
58
46
59
- Target workflows triggered by `pull_request_target`, `issue_comment`, or bot commands that still save caches; GitHub lets them overwrite repository-wide keys even when the runner only has read access to the repo.
@@ -50,5 +63,7 @@ The second job now runs attacker-controlled code while holding release credentia
50
63
## References
51
64
52
65
-[A Survey of 2024–2025 Open-Source Supply-Chain Compromises and Their Root Causes](https://words.filippo.io/compromise-survey/)
66
+
-[The Monsters in Your Build Cache: GitHub Actions Cache Poisoning](http://adnanthekhan.com/2024/05/06/the-monsters-in-your-build-cache-github-actions-cache-poisoning/)
0 commit comments