This Friday, September 25, GitHub starts refusing work to outdated self-hosted runners. Not with a warning banner you can snooze — with jobs that silently never get queued and registrations that fail outright. If your build fleet has a single long-lived runner that hasn't been touched since last year, this is the week it stops being a runner.
The deadline comes from GitHub's June 12 changelog, which resumed minimum-version enforcement after a March pause. But the more important story isn't the deadline. It's what a version floor can and cannot do for you. An up-to-date runner still executes whatever a workflow tells it to — and the last eighteen months of supply-chain attacks all walked through doors a version check doesn't guard. This post gives you both halves: the exact enforcement facts you need before Friday, and an honest accounting of the holes your fleet still has to close itself.
Four days left: what enforcement actually does
There are two requirements, and confusing them is the most common way teams will get bitten this week:
- To configure or re-register a runner, it must be on version
2.329.0or later (released October 15, 2025). Anything older gets blocked at registration — and since an outdated runner can no longer self-upgrade after running the config script, a stale install is a dead install until you manually upgrade it first. - To keep executing workflow jobs, the runner must install each new runner release within 30 days of its publication. This rule existed before but wasn't consistently enforced. Now it is: miss the 30-day window and GitHub stops queuing jobs to the runner. Worse for the "pin and forget" crowd,
2.329.0is only the floor for registering. A runner pinned there that never updates again will not pick up jobs. And when GitHub publishes a critical security update, job queuing pauses until the update is applied.
Enforcement lands September 25, 2026 for github.com and GitHub Enterprise Cloud. If you're on GitHub Enterprise Cloud with Data Residency, your enforcement date already passed — July 31. GitHub Enterprise Server customers aren't impacted at this time.
You've already lived through the warning shots. Brownouts ran 11:00 AM to 3:00 PM ET on August 24; August 31 and September 2; September 7, 9, and 11 (the 9th blocked job execution too, not just registration); and September 14, 16, and 18. If any of those days produced mysterious "runner didn't pick up the job" incidents that cleared up by late afternoon, that was the brownout telling you which machines are stale. After Friday, that behavior becomes permanent.
Runners with auto-update enabled meet the 30-day rule automatically, as long as they can reach the update service. Runners with auto-update disabled — common in air-gapped setups, golden-image fleets, and "we pin everything" shops — need a manual upgrade cadence starting now, because the effective minimum for job execution slides forward with every new release.
Why GitHub is forcing the upgrade
This isn't arbitrary hygiene theater. Since early 2024, the Actions team has been rearchitecting the backend services behind job execution and runner communication, and the new platform now handles over 120 million jobs per day — more than triple the pre-migration volume — while letting enterprises start seven times more jobs per minute. Older runner versions are protocol-incompatible with that infrastructure. Enforcement is GitHub finishing the migration by removing the versions the new backend can't speak to. That framing matters for the rest of this post: the version floor is a compatibility gate first, and only incidentally a security gate. Which brings us to the honest part.
What a version floor closes — and what it can't
| The version floor closes this | It does nothing for this |
|---|---|
| Stale runner agents that can't speak the current control-plane protocol | Malicious workflow content — a current runner faithfully runs whatever YAML you give it |
| Known runner CVEs, via the rolling 30-day update rule | Compromised third-party actions referenced by mutable tags |
| Registration of ancient runners that predate current auth and update behavior | Rogue runner registration using stolen tokens on attacker-controlled hosts |
| "Works on my frozen 2023 image" drift across a fleet | Cross-job contamination on persistent, non-ephemeral runners |
Read the right column carefully, because every major CI supply-chain incident since early 2025 exploited something in it. A version floor guarantees the agent software is fresh. It says nothing about the code the agent runs, the actions it downloads, or who else registered a runner with your token. That gap isn't a flaw in GitHub's plan — it's just not what version enforcement is for. But if your team treats "all runners green in the fleet dashboard" as "our builds are safe," the next section is the corrective.
Three incidents that prove the gap
tj-actions, March 2025: the mutable tag. Attackers compromised the widely used tj-actions/changed-files action with a stolen personal access token and pointed its version tags at malicious code (CVE-2025-30066, CVSS 8.6). For roughly a day, over 23,000 repositories executed the trojaned action, which dumped workflow secrets into build logs where attackers could read them. A runner-version floor is irrelevant here: the runner did exactly what it was told, running a current-looking action whose tag had been repointed underneath it. The control that would have helped is pinning third-party actions to full commit SHAs — a string that can't be silently repointed the way a tag can — plus treating CI logs as secret-bearing output.
Shai-Hulud 2.0, November 2025: the rogue runner. This self-propagating npm worm backdoored 796 packages with over 20 million weekly downloads. Its payload ran a secret scanner on victim machines and exfiltrated npm, GitHub, and cloud credentials. Then, on victims running inside Linux CI environments, it downloaded the official GitHub Actions runner binary, installed it in a hidden directory, and registered the compromised machine as a self-hosted runner named SHA1HULUD on attacker-controlled repos.
Follow-up workflows serialized every Actions secret to an artifact and cleaned up. Note the inversion: the attacker didn't exploit an outdated runner; they deployed a fresh, legitimate one as a backdoor. No version policy stops that. What stops it is never letting untrusted install scripts see credentials that can register runners, combined with ephemeral build environments that don't survive long enough to be repurposed.
trivy-action, March 2026: the scanner that stole first. Attackers used compromised credentials to ship a malicious Trivy v0.69.4 release, force-push 76 of 77 version tags in aquasecurity/trivy-action (every tag from 0.0.1 through 0.34.2) to credential-stealing malware, replace all seven setup-trivy tags, and push trojaned v0.69.5/v0.69.6 container images (CVE-2026-33634, CVSS 9.4, now in CISA's Known Exploited Vulnerabilities catalog). Every pipeline referencing the action by tag silently ran an infostealer before the legitimate scan. The irony — your security scanner exfiltrating secrets — made the headlines, but the mechanism is the tj-actions lesson repeated at larger scale: mutable references plus a compromised maintainer credential.
Remediation was the same playbook too: rotate every secret any affected pipeline could see, and re-pin to the fixed 0.35.0 release (the first protected by GitHub's immutable releases) by exact commit SHA.
The pattern across all three: the runner was never the vulnerability. The vulnerability was what the runner was asked to run, where it fetched it from, and how long the compromise could persist. A version floor fixes the agent. You still have to fix the workload.
The decision your build fleet faces: track GitHub's timeline or isolate outside it
If you operate a git-push PaaS — or any platform where tenant code triggers builds — enforcement forces a concrete architectural choice, not just a patching sprint:
Option A: stay on Actions runners and comply properly. Turn auto-update back on everywhere it was disabled, or commit to a manual cadence tighter than 30 days. Then fix the workload side: register runners with --ephemeral (or JIT tokens) so each machine takes exactly one job and is destroyed afterward — no persistent state, no cross-job contamination, nothing for a Shai-Hulud-style payload to persist on.
On Kubernetes, that means Actions Runner Controller scale sets with ephemeral runners as the default. SHA-pin every third-party action, refuse mutable tags in tenant-visible templates, and never run untrusted fork PRs on persistent self-hosted runners. GitHub's own hardening guide puts it bluntly: self-hosted runners offer no guarantee of a clean ephemeral VM and can be persistently compromised by untrusted workflow code.
Option B: route builds through your own isolated build step. Decouple tenant builds from GitHub's runner model entirely: your platform receives the push event and runs the build in its own version-pinned, single-tenant, throwaway environment — a fresh container or microVM per build, with no GitHub registration token in reach and no shared filesystem between tenants. You trade GitHub's runner maintenance (and its enforcement calendar) for owning the build executor yourself, but you gain the property the incidents above all point to: compromise of one build cannot become persistence on the fleet, because there is no persistent fleet to infect.
Neither option is free. Option A is less engineering but leaves you on someone else's enforcement calendar forever — this week's scramble repeats every time GitHub ships a critical runner update. Option B is real platform work: image building, caching, log streaming, and secret scoping all become yours. The wrong answer is the middle: persistent self-hosted runners running untrusted tenant workflows with auto-update on, treating the green fleet dashboard as a security posture. That's precisely the shape all three incidents above feasted on.
This week's checklist
Run this before Friday, in order:
- Inventory every self-hosted runner across orgs, enterprises, and arc scale sets. Anything below
2.329.0cannot re-register after enforcement — upgrade those installs first. - Audit the 30-day rule, not just the floor. A runner on
2.329.0from last October is registrable and still won't get jobs. Check each runner's installed version against the latest release date. - Re-enable auto-update wherever it was disabled without an air-gap justification, and verify runners can reach the update service. Where auto-update must stay off, put a sub-30-day manual upgrade cadence on the calendar now.
- Grep every workflow for mutable action pins. Anything referenced as
@vX,@vX.Y, or a branch name — especially former incident vectors liketrivy-actionbelow0.35.0— gets re-pinned to a full commit SHA. - Quarantine untrusted builds. Fork-PR workflows must not run on persistent self-hosted runners. Move them to ephemeral runners, GitHub-hosted runners with approval gates, or your isolated build path.
- Rotate secrets for any pipeline that ran a compromised action. If a workflow executed
trivy-actionby tag between March 19, 2026 and remediation, ortj-actions/changed-filesduring the March 2025 window, assume its accessible secrets are burned.
Enforcement is the floor, not the ceiling
GitHub's version enforcement will do something genuinely useful: it drags every neglected runner on the platform onto a maintained, protocol-compatible agent, and the 30-day rule keeps them there. The rearchitected backend gets its uniform fleet; you get fewer mysterious runner failures. Take the win.
But don't mistake the win for a security strategy. The incidents that actually burned teams this past year never cared what runner version you were on — they cared what your workflows referenced, what credentials a build could see, and whether a compromise could outlive a single job. Friday's deadline fixes the agent. The workload — ephemeral execution, SHA-pinned actions, scoped secrets, untrusted code on throwaway machines — is still yours to build. The teams that treat September 25 as the start of that work, rather than the end of a patching sprint, are the ones whose build fleets will survive the next Shai-Hulud, whatever it calls its runners.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.



