# Gogs allows users to write to readonly repositories using receive-pack + service=git-upload-pack confusion

Gogs authorizes git-receive-pack pushes using the client-supplied service=git-upload-pack query string, letting read-only collaborators push to repositories.

- Payout: Research
- Severity: high
- Program: Gogs
- Found by: Aikido-Security, JorianWoltjer, reindaelman, grumpinout1
- Disclosed: 2026-06-23
- CVE: CVE-2026-52810
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-wmfg-5p4h-5fw3
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-wmfg-5p4h-5fw3
- Tags: area:web domain:web impact:integrity impact:privesc kind:research platform:ghsa sev:high tech:go technique:param-pollution vuln:access-control vuln:auth-bypass vuln:business-logic

**Target:** Git Smart HTTP RPC endpoints (/git-receive-pack, /git-upload-pack)
**Root cause:** The Smart HTTP handler derives the authorization policy from the client-supplied `service` query parameter rather than the actual RPC path being dispatched, so a receive-pack request claiming `service=git-upload-pack` is authorized as a read.
**Steps:**
1. Set up Gogs with users `victim` and `attacker`; victim creates a private repo and adds attacker as Read collaborator.
2. Run a local HTTP proxy that rewrites any request whose path ends in `/git-receive-pack` to append `service=git-upload-pack` when absent.
3. Configure git to use that proxy via `http_proxy`/`HTTP_PROXY` env vars.
4. `git push -u origin poc/git-http-confusion` to the repo URL; the proxy rewrites the receive-pack POST to carry `?service=git-upload-pack`.
5. Observe the push succeeds and the branch exists on the read-only repo.
**How found:** Noticed the Smart HTTP handler keys authorization off the client-controlled `service` query parameter instead of the executed RPC path, then tested sending a receive-pack POST with a forged upload-pack service string.
**Exploitation:** Attacker with only read access (or any signed-in user when REQUIRE_SIGNIN_VIEW=true) pushes commits to a repo they cannot write to; force push can overwrite main branch history, affecting availability.
**Escalation:** On instances with REQUIRE_SIGNIN_VIEW=true, every repository becomes writable by any authenticated user; force push enables history overwrite/availability impact.
**Insight:** When a handler picks an authz policy from a client-supplied parameter that is separate from the actual dispatched route, try mismatching them (route=write, param=read) — Git Smart HTTP's dual upload-pack/receive-pack endpoints are a classic spot.

## Proof of concept (copied exactly from the original report)

**Proxy rewriting receive-pack to service=git-upload-pack**

```
q = query or ""
        if path.endswith("/git-receive-pack") and "service=" not in q:
            query = f"{q}&service=git-upload-pack" if q else "service=git-upload-pack"
```

**Git push through the rewriting proxy**

```
env = os.environ.copy()
        proxy_url = f"http://127.0.0.1:{port}"
        env["http_proxy"] = proxy_url
        env["HTTP_PROXY"] = proxy_url
        env["https_proxy"] = proxy_url
        env["HTTPS_PROXY"] = proxy_url

        push = subprocess.run(
            ["git", "push", "-u", "origin", "poc/git-http-confusion"],
```

## Write-ups of the same bug (oldest first)
- 2026-06-23: [Gogs allows users to write to readonly repositories using receive-pack + service=git-upload-pack confusion](https://bugbountylibrary.com/r/ghsa%3AGHSA-wmfg-5p4h-5fw3) — Aikido-Security, JorianWoltjer, reindaelman, grumpinout1 (this one)
- 2026-08-19: [Yet another RCE in Gogs, but it's fixed this time!](https://bugbountylibrary.com/r/blog%3Aaikido-dev-blog-fixed-rce-gogs-cve-2026-52813) — Aikido Security

