PatchDay Alert
Analysis · 7 min read · 1,336 words By Colten Anderson · Commentary

Gogs has a critical RCE and no one is coming to fix it

Rapid7 found a push-button remote code execution flaw in Gogs, shipped a Metasploit module with it, and ran 72 days from report to publication with no patch and two months of maintainer silence. There is no fix. There may never be one.

Gogs has a critical RCE and no one is coming to fix it

The single maintainer of Gogs got a report of a critical remote code execution flaw on March 17, acknowledged it once on March 28, and then went quiet for roughly 60 days while Rapid7 tried four more times to get a response. Seventy-two days from report to publication, zero patches. On May 28 Rapid7 published anyway, with a working Metasploit module attached. There is still no patch. Going by the last two years of this project’s track record, there may never be one.

That is the whole story, and it is worse than a single bad bug. A bug is an accident. This is the second time this exact class of flaw has surfaced in Gogs, and the second time the maintainer has gone quiet rather than fix it.

What broke

The flaw is an argument injection (CWE-88) in the “Rebase before merging” pull-request path, tracked as GHSA-qf6p-p7ww-cwr9 and scored CVSSv4 9.4. There is no CVE assigned. That detail matters operationally, and I will come back to it.

The mechanics are almost embarrassingly simple. The Merge() function in internal/database/pull.go builds a git rebase command and passes a branch name straight to git without the POSIX -- end-of-options separator. -- is the convention that tells a command-line parser “everything after this is a positional argument, not a flag.” Leave it out and any branch name that starts with -- gets read as an option. So an attacker names a branch --exec=touch${IFS}/tmp/rce_proof, git parses it as a real git rebase --exec flag, and git rebase --exec runs its argument through sh -c. The ${IFS} trick smuggles whitespace past git’s ban on literal spaces in branch names. Code runs as the Gogs server user, which can read every repository, credential, password hash, API token, and SSH key on the box.

The fix is one token. Insert -- before the branch name. The code has simply never done it.

If “argument injection in Gogs” sounds familiar, that is the point. SonarSource reported four critical flaws in 2024 (CVE-2024-39930 through -39933, CVSS up to 9.9), including SSH argument injection in the same CWE-88 family. The maintainer responded once, then stopped, and all four were still unpatched 15 months later when SonarSource published. The Merge() path was a different code path that never got cleaned up. This is what an unfixed bug class looks like: the same mistake, in a new function, every time someone goes looking.

”Authenticated,” with an asterisk

Rapid7 calls this an authenticated RCE, and on paper that sounds like a meaningful barrier. It mostly is not. Gogs ships with open registration (DISABLE_REGISTRATION = false) and no cap on repository creation (MAX_CREATION_LIMIT = -1). On a default internet-facing install, an outsider self-registers, creates a repo they own, flips on “Rebase before merging” under Settings → Advanced, and exploits it. Rapid7 describes the full chain as automatable in seconds. “Authenticated” here means “the attacker filled out a signup form.”

Confirmed vulnerable: Gogs 0.14.2, the current stable release, and the 0.15.0+dev branch. Rapid7 notes that any earlier version supporting rebase merging is likely affected too, so the exposure window stretches back years rather than weeks.

How many instances are actually out there is genuinely unclear. Shodan returns roughly 1,100 to 1,140 internet-facing Gogs servers; Shadowserver tracks 2,400-plus, heaviest in Asia. Neither documents its fingerprinting, and the public count understates real deployment anyway, because most Gogs sits behind a VPN or on an internal network. If you run it internally and assumed that made this someone else’s problem, the only barrier between an insider and code execution is a signup form you control.

No in-the-wild exploitation of this specific flaw is confirmed as of May 29. That is not reassurance. A production-quality Metasploit module with two modes shipped alongside the disclosure, which collapses the window between “published” and “mass-scanned” to hours. And Gogs is already a proven target: a separate path-traversal RCE, CVE-2025-8110, was exploited at scale across 700-plus instances earlier this year and made CISA’s Known Exploited Vulnerabilities catalog. “Unconfirmed” on a tool with that history is a timing statement, not a safety one.

Why this keeps happening

Gogs is one developer’s project. It always has been. In 2016 contributors frustrated that the maintainer would not share write access forked it into Gitea, which grew into a community-governed project with a real contributor base. The governance problem that caused the fork in 2016 is the exact same problem you are reading about now: a critical bug, one person who can fix it, and that person unreachable.

I do not know whether the silence is burnout, a life event, or a decision to walk away without saying so. From the outside it does not matter. The operational reality is identical: a single point of failure who is currently failing, on a piece of infrastructure that holds your source code and your deploy keys. That is a structural risk, not a bug-of-the-week. No amount of app.ini tuning fixes a maintainer who has stopped answering.

What to actually do

Mitigate today, then plan the exit. Rapid7’s workarounds narrow the perimeter but none of them close the hole.

ActionEffectResidual risk
DISABLE_REGISTRATION = trueRemoves anonymous self-signupAny existing user can still exploit
MAX_CREATION_LIMIT = 0Blocks new repo creationExisting repo owners unaffected
Audit per-repo rebase settingsFinds enabled instances nowNo global lock; a repo owner can re-enable it
Log-watch for --exec= patternsCatches attempts after the factDetection, not prevention; evadable
Take internet-facing instances offlineEliminates external exposureService outage

Disabling registration is the highest-value move because the exploit needs an account. But Rapid7 is explicit that even that leaves a hole: anyone who already has write or admin access to any repo can re-enable “Rebase before merging” at the repo level, and Gogs has no global or org-level setting to lock that down. Taking the instance offline is the only thing that actually eliminates the external vector. Everything else just makes the door smaller.

That is the mitigation. The decision underneath it is migration, and the timeline is “now, deliberately” rather than “later, in a panic.” Both Rapid7 and SonarSource recommend moving to Gitea or Forgejo, and SonarSource checked that none of the 2024 Gogs flaws were present in Gitea. Both forks share Gogs’ data format and most of its API, so this is a migration, not a rewrite. There is no CVE on this flaw, which means no NVD entry, no EPSS score, and no automated scanner flag to nag you into action. The clock is running quietly. If you are waiting for a CVE ID to land before you treat this as real, you have already misread the situation.

Run the mitigations this week. Schedule the Gitea or Forgejo cutover before the next quarter closes, and treat any unplanned outage on the Gogs box as the moment that timeline moves up. The question was never whether to leave a single-maintainer project that has gone dark on critical bugs twice in two years. It is only how calmly you get to do it.

We track exactly this kind of “patch exists / patch doesn’t / the only fix is leaving” call at PatchDay Alert, so the decision is sitting on your desk before the Metasploit traffic finds your box.

Sources

Share

Get the free CVE triage cheat sheet

Subscribe and we'll email you the one-page triage flow for fresh CVEs. Plus the weekday digest.

Subscribe