On April 28, 2026, Wiz Research disclosed CVE-2026-3854, a CVSS 8.7 command injection in the internal git pipeline that backs both GitHub.com and GitHub Enterprise Server. An authenticated user with push access to any repository — including a throwaway one they created themselves — could chain three field injections in an internal X-Stat header and land code execution as the git service user on a shared storage node. On GitHub.com, that meant filesystem access to repository data belonging to other tenants on the same node. On GHES, it meant full instance compromise. GitHub patched github.com in roughly two hours after the report and shipped GHES patches a week later, but Wiz’s telemetry still showed 88% of public-facing GHES instances unpatched at disclosure.

This one is worth reading carefully, both because the bug class is recurring and because of how it was found. The Wiz writeup credits AI-assisted reverse engineering (IDA MCP) with making the audit of compiled babeld, gitauth, gitrpcd, and the pre-receive Go binary economically feasible. That is not a marketing footnote. It is a meaningful change in what a small research team can audit in a closed-source binary pipeline, and it points at where the next round of these findings is going to come from.

What actually broke

When a user runs git push over SSH, GitHub’s edge daemon babeld authenticates the session through gitauth, then forwards the operation to an internal RPC server (gitrpcd) that fronts the pre-receive hook binary. Security policy — file size limits, branch name rules, custom hook configuration, the deployment environment — is not re-derived downstream. It is serialized into a single internal header, X-Stat, as semicolon-delimited key=value pairs. gitrpcd and the pre-receive binary parse that header and trust every field, because the trust boundary was supposed to be at babeld.

The header parser uses last-write-wins semantics: if key appears twice, the later value silently overrides the earlier one. And babeld copies user-supplied git push -o option values into X-Stat verbatim, without escaping the semicolon delimiter. So a push option of the form x;rails_env=development;custom_hooks_dir=/tmp/x;repo_pre_receive_hooks=... does not stay in its push_option_0 field. It breaks out and synthesizes whatever downstream policy fields the attacker wants.

Three of those fields, chained, are enough for RCE:

  • rails_env controls whether the pre-receive binary executes custom hooks inside a sandbox or directly as the git user. Inject any non-production value and the sandbox path is gone.
  • custom_hooks_dir is the base directory used to resolve hook script paths.
  • repo_pre_receive_hooks is the JSON list of hook definitions to execute, including the script path. There is no path traversal validation, so a ../ payload joined onto the attacker-controlled base resolves to any binary on the filesystem.

On GHES this fires immediately. On GitHub.com the custom-hooks code path is gated by another X-Stat boolean that defaults to false in the multi-tenant deployment — and is itself injectable through the same primitive. One additional field flip and the chain works on github.com too. Wiz published packet captures showing the injected fields appearing alongside legitimate ones in the wire-format header, which is about as unambiguous as proof gets.

Patch state and required action

GitHub.com is fixed; nothing for tenants to do there. GHES operators have to upgrade. Fixed versions per the advisory:

Branch Fixed version
3.14.x 3.14.24
3.15.x 3.15.19
3.16.x 3.16.15
3.17.x 3.17.12
3.18.x 3.18.6
3.19.x 3.19.3

If an enterprise is sitting on a <= 3.19.1 build with SSH push exposed to anyone who can authenticate — including via SAML/SCIM-provisioned accounts that nobody is auditing — that instance is exploitable today by any user who can clone and push to a single repo. There is no privileged role required.

The control story

This is not exotic. Strip away the specifics and CVE-2026-3854 is a textbook input-validation failure where a delimiter-significant character in untrusted input bleeds into a structured internal protocol. The control families that map onto the prevention story are unsurprising:

  • SI-10 Information Input Validation. Sanitizing semicolons in git push -o values before embedding them in a semicolon-delimited header is the entire fix. Every internal protocol with structured fields needs explicit input-validation rules at the boundary, not implicit trust.
  • SC-3 / SC-8 Boundary and transmission protection. gitrpcd treated babeld as fully trusted. That is reasonable in a network-isolation sense, but the trust was being smuggled through an unauthenticated, unsigned header. An HMAC over the X-Stat payload computed by gitauth and verified downstream would have made the injection useless even with an unfixed parser.
  • CM-6 / CM-7 Configuration Settings and Least Functionality. A non-production execution path that runs custom hooks unsandboxed, switched on by a single string field, has no business being reachable in a production binary. This is the same lesson as every debug endpoint that has ever shipped to prod.
  • SR-3 / SR-11 Supply Chain. GitHub is upstream of essentially every software supply chain that matters. ATO packages that note GitHub Enterprise Cloud as an authorization boundary inheritance need to refresh their CRMs to capture this incident and the response, because auditors are going to ask.
  • RA-5 / CA-7 Vulnerability Monitoring and Continuous Monitoring. GHES versioning is trivially fingerprintable, and 88% of internet-facing instances were still vulnerable at disclosure. If a continuous monitoring program is not flagging GHES version drift on a daily cadence, it is not actually monitoring.

What the AI-assisted discovery story changes

The finding itself is a string-parsing bug. The interesting part is that it lived inside several compiled binaries written in different languages, glued together by an undocumented internal header, and Wiz audited the whole pipeline using AI-driven reverse engineering. Closed-source binary review at that scope used to be reserved for nation-state and large-vendor red teams. It is now within reach of a six-person research group, and the reviews are going to find more of these. Defenders building multi-service systems should assume that the cost asymmetry has shifted and that internal protocols which were quietly considered “audited by obscurity” are about to stop being audited that way.

The specific lesson: any place where one service serializes user-influenced data into a structured format that another service parses and trusts is a candidate for this exact bug class. Audit those boundaries before someone with an MCP-enabled disassembler does it for you.

References: Wiz Research advisory at https://www.wiz.io/blog/github-rce-vulnerability-cve-2026-3854 and GitHub’s response at https://github.blog/security/securing-the-git-push-pipeline-responding-to-a-critical-remote-code-execution-vulnerability/.