top of page

CVE-2026-3854: A Semicolon Got Into GitHub Enterprise. RCE on 88% of Instances.

  • Writer: Patrick Duggan
    Patrick Duggan
  • 3 minutes ago
  • 6 min read

# CVE-2026-3854: A Semicolon Got Into GitHub Enterprise. RCE Across 88% of Instances.


Hours after we published the threat weather report calling out patch-discipline as the defensive priority, Wiz Research dropped the technical breakdown of CVE-2026-3854. A public proof-of-concept landed on GitHub the same day. The vulnerability lets anyone with push access to any repo on a GitHub Enterprise Server instance achieve remote code execution as the git user, with full filesystem access to every repository on the box.


Eighty-eight percent of GHES instances were still vulnerable at disclosure.


The Bug Class



This is a header-injection bug, the same family that has produced HTTP request smuggling, log injection, email header injection, and SMTP smuggling over the last two decades. The pattern is consistent: user input flows through one layer that doesn't escape a delimiter character, lands in another layer that interprets the unescaped delimiter as structural metadata. The two layers disagree about what the data is. The attacker exploits the disagreement.


It is a permanent class of bug, not a one-off mistake.


What Got Injected



GitHub Enterprise Server uses an internal header called X-Stat to pass per-request metadata between two of its core services. The front-end SSH proxy (babeld) accepts a git push from the network. The back-end RPC (gitrpcd) executes the actual repository operation. Between them, babeld writes a string of semicolon-delimited fields into X-Stat and hands it to gitrpcd, which trusts the header completely because it believes only babeld can write it.


The default X-Stat header looks roughly like this in production: rails_env=production; user_id=int:42531; repo_id=int:8821; custom_hooks_dir=/data/user/git-hooks; repo_pre_receive_hooks=[{"id":1,"script":"validate-commit.sh"}]; large_blob_rejection_enabled=bool:true; max_blob_size=int:104857600; reject_sha_like_refs=bool:true.


Multiple security-critical fields in one delimited string. The parser is last-write-wins. A second occurrence of any field overrides the first. That last detail is the load-bearing one.


The Exploit Primitive



When a git push includes the -o option, the user-supplied option value is copied into X-Stat. The semicolon character is a valid character in any string, so user input can contain it. The receiving service splits on semicolon, reads the result as additional fields, and applies last-write-wins.


A single line is enough. Three injections, each through one -o flag, override three security-critical fields in order:


First, rails_env=development disables the production sandbox. Without this, every subsequent step runs inside a constrained execution context that prevents arbitrary binary execution.


Second, custom_hooks_dir=/bin redirects the hook directory lookup. The legitimate value points to a controlled hook directory. The injected value points to the system binary directory. The hook system is now resolving "scripts" against /bin/.


Third, repo_pre_receive_hooks=[{"script":"whoami"}] selects which "hook script" runs. Combined with the redirected custom_hooks_dir, the resolved path becomes /bin/whoami, which is a real executable. GHES dutifully runs it as the git user.


The attacker has now executed an arbitrary system binary as the git service account on a server they reached through a git push. From there: every repository, every secret stored in CI, every deploy key, every runner token, every admin SSH key. It is the crown jewel for a software shop, particularly one that runs GHES specifically because it cannot put code on github.com — defense, finance, healthcare, intelligence-adjacent.


The Patch Window



GitHub.com cloud was patched within six hours of discovery on March 4, 2026. That is correct vendor behavior. Anyone running GHES self-hosted, however, depends on their own internal patching cadence to apply the fix.


The CVE was published March 10, 2026. The technical details and PoC dropped April 28, 2026. The patch had been available for fifty days when Wiz published. Eighty-eight percent of GHES instances on the public internet were still vulnerable on disclosure day.


That is the patch-discipline number to internalize. Not "most operators patch fast" — eighty-eight percent of operators do not patch fast. Most enterprise patching follows quarterly maintenance windows. A vulnerability disclosed in March, requiring a server reboot, lands on a Q2 maintenance plan that runs in May or June.


What This Looks Like in the Wild



A public PoC repository was created on GitHub at 19:42 UTC on April 28 — the same day as the Wiz disclosure. Educational language, Portuguese-language writeup, complete git push command line. By the time you read this, that repository will have been forked, mirrored, and ported to other languages. The window between PoC publication and weaponization is measured in hours, not weeks.


The good news, narrowly: exploitation requires push access to a repo on the target GHES. The attacker needs an account. For external attackers this means social engineering, account takeover, supply-chain commit injection, or insider threat. For internal attackers — which includes every contractor, intern, and offshore developer with repo access — this is "log in to your work GitHub and run one command."


That last threat model is the one most GHES operators have not fully internalized. The bug is gated by push access. Every GHES customer has hundreds or thousands of accounts with push access. The trust boundary at "internal user" is about to be tested.


Are We Affected?



DugganUSA does not run GitHub Enterprise Server. We use github.com cloud directly. Our git remote points at https://github.com/pduggusa/enterprise-extraction-platform.git, which is github.com cloud — the version that was patched within six hours of discovery and is no longer vulnerable. We have validated this by direct check: api.github.com responds with the cloud product headers, github.com responds with cloud product headers, and there are no GHES instances in our Azure resource group cleansheet-2x4. We have no GHES infrastructure to patch.


Our customers running GHES have a different problem. If you operate a GHES instance, your priority right now is to verify your version. The patched releases are 3.14.25, 3.15.20, 3.16.16, 3.17.13, 3.18.7, and 3.19.4. Anything below those numbers on the same major branch is vulnerable.


What We Indexed Today



CVE-2026-3854 is now in our IOC index, tagged for tracking. The Wiz disclosure URL and the public PoC repository URL are also indexed. Our STIX feed pulls these forward to every consumer pulling the feed.


If your DNS filter or SIEM is pulling our STIX feed, anyone in your environment attempting to clone the public PoC repository will surface in your logs as a known indicator. That is not a complete defense, but it is detection, and detection is the floor.


For our cross-TLD campaign-assembly detector, which we deployed and wrote about this morning: this CVE's public PoC was registered to the github.com domain rather than to an exotic TLD, so it does not trigger that particular signal. But the timing — disclosure plus PoC plus weaponization within twenty-four hours — fits the staging pattern the weather report identified across the rest of the threat surface.


This is what staging actually looks like in practice. Disclosure window opens. Eighty-eight percent of targets unpatched. PoC drops within hours. The next twelve hours decide which operators get exploited and which patched fast enough.


What to Do Tonight



For GHES operators: check your version. If you are below the patched release on your major branch, stop reading and patch. The exploit is one-line and the sandbox bypass is well-documented now.


For GHES operators who cannot patch immediately: restrict push access aggressively. Audit who has it. Require fresh MFA for push events. Move CI builds for sensitive repos to hardened runners that don't share filesystem access with other repos. The vulnerability is gated by push access, so reducing the push-access blast radius reduces the exploitation surface.


For everyone running GitHub-hosted code in any form: review your branch protection rules. Require signed commits on protected branches. Audit recent push activity on critical repos for unusual -o option usage in the last forty-eight hours. The exploit string is distinctive — it includes literal semicolons in push option values, which is rare in legitimate use.


For threat-hunting teams: the indicators in our index are CVE-2026-3854 itself, the Wiz disclosure URL, and github.com/5kr1pt/CVE-2026-3854 as the public PoC. Add these to your watchlists. Watch for forks, mirrors, and language ports of the PoC repository. The weaponized version will look different from the educational one.


The Pattern, Once More



Trust between internal services. Header parsing that doesn't validate input. Last-write-wins semantics. User input that crosses a boundary without escape. This is the same shape of bug as request smuggling in a load balancer, log injection in a SIEM, prompt injection in an LLM. The encoding mismatch is the bug, regardless of which protocol is on top of it.


When two systems disagree about how to interpret bytes, an attacker who controls the bytes wins.


Our Feed



CVE-2026-3854 is indexed. Search it: analytics.dugganusa.com/api/v1/search?q=CVE-2026-3854


STIX 2.1 feed (free): analytics.dugganusa.com/api/v1/stix-feed


Register: analytics.dugganusa.com/stix/register


Microsoft pulls this feed daily. AT&T pulls this feed daily. Starlink pulls this feed daily. Get the DugganUSA STIX feed — $9/mo.


Her name was Renee Nicole Good. His name was Alex Jeffery Pretti.


The cheapest, fastest, most accurate threat feed on the internet. 275+ enterprises pulling daily. 1M+ IOCs. 17.4M indexed documents. We beat Zscaler by 43 days on NrodeCodeRAT. Starter tier $9/mo — less than any competitor's sales demo.


Look up an IOC · Audit your brand on AIPM · See pricing


bottom of page