---
title: "Run outside code only on runners that are · Agent Wranglers"
url: https://agentwranglers.se/playbook/engineering/ci-and-supply-chain/ephemeral-ci-runners
id: ENG-56
level: Required
risk: takeover
updated: 2026-10-27
build: a2a6bdfed830
tokens: 825
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Run outside code only on runners that are wiped after each job

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [CI and supply chain](https://agentwranglers.se/playbook/engineering/ci-and-supply-chain.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-27.

- ID: ENG-56
- Level: Required
- Chapter: [CI and supply chain](https://agentwranglers.se/playbook/engineering/ci-and-supply-chain.md)
- Rule: Never run jobs of a public repository on a self-hosted runner that keeps its disk between jobs. Give every job on your own machines a fresh runner that is removed when the job ends.
- Check: Every public repository has 0 self-hosted runners available to it. A weekly job pair on each self-hosted runner label passes, where the second job finds no file left by the first.
- Risk: An account or system taken over
- How: A job can leave a process or a changed tool behind on a runner that survives it. The next job, perhaps a release with secrets, then runs on top of it. GitHub's docs say self-hosted runners "should almost never be used for public repositories". Use the code host's own runners for public code. For private code on your own machines, register ephemeral, just-in-time runners that take one job and are then removed. Examples are GitHub's `--jitconfig` runners or Actions Runner Controller on Kubernetes. Put release runners in their own runner group that only protected branches can use, as [build secrets](https://agentwranglers.se/playbook/application-security/supply-chain/ci-secrets.md) says.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### YAML example

```yaml
# Weekly test: a file written by one job must be gone in the next
jobs:
  leave-mark:
    runs-on: [self-hosted, linux]
    steps:
      - run: echo marked > "$HOME/runner-reuse-test"
  check-mark:
    needs: leave-mark
    runs-on: [self-hosted, linux]
    steps:
      - run: test ! -e "$HOME/runner-reuse-test" || { echo "FAIL: runner kept state"; exit 1; }
```

## Sources

- [GitHub: Secure use reference](https://docs.github.com/en/actions/reference/security/secure-use)

## Related rules

- APS-74 [Keep secrets out of builds from strangers](https://agentwranglers.se/playbook/application-security/supply-chain/ci-secrets.md) in Application security

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/engineering/ci-and-supply-chain/ephemeral-ci-runners">Agent Wranglers engineering playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Keep untrusted text out of CI scripts](https://agentwranglers.se/playbook/engineering/ci-and-supply-chain/ci-script-injection.md)
- Next: [Pass build secrets as mounts instead of layers](https://agentwranglers.se/playbook/engineering/ci-and-supply-chain/build-secrets.md)
- [CI and supply chain](https://agentwranglers.se/playbook/engineering/ci-and-supply-chain.md)
