Gitea Docker Image Reverse-Proxy Authentication Bypass — "One Header, Any User" (CVE-2026-20896)
by rz1027 (reporter, credited in Gitea's advisory; PoC repo author) · 2026-07-11
- Severity
- Critical
- CVE
- CVE-2026-20896 (GHSA-f75j-4cw6-rmx4)
- Category
- web
- Affected product
- Gitea — official Docker images (gitea/gitea), both root and rootless variants
- Affected versions
- Docker images up to and including 1.26.2. Binary/self-built installs that follow app.example.ini are **not** affected — this is a Docker-packaging defect, not a code-level bug in Gitea itself.
- Disclosed
- 2026-07-11
- Patch status
- patched
Tags
References
- https://www.cve.org/CVERecord?id=CVE-2026-20896
- https://github.com/go-gitea/gitea/security/advisories/GHSA-f75j-4cw6-rmx4
- https://blog.gitea.com/release-of-1.26.3-and-1.26.4/
- https://github.com/rz1027/CVE-2026-20896
- https://thehackernews.com/2026/07/threat-actors-probe-gitea-docker-flaw.html
- https://www.bleepingcomputer.com/news/security/hackers-exploit-critical-auth-bypass-in-gitea-docker-image/
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-11 |
| Last Updated | 2026-07-11 |
| Author / Researcher | rz1027 (reporter, credited in Gitea’s advisory; PoC repo author) |
| CVE / Advisory | CVE-2026-20896 (GHSA-f75j-4cw6-rmx4) |
| Category | web |
| Severity | Critical |
| CVSS Score | 9.8 (CVSS 3.1, AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| Status | Weaponized (public PoC + detector script, actively exploited in the wild per Sysdig) |
| Tags | gitea, docker, authentication-bypass, reverse-proxy, header-spoofing, unauthenticated, remote, cwe-290, actively-exploited |
| Related | Other Gitea/Gogs auth-related entries in this archive: 2026-07-05_cve-2026-27771-gitea-registry-auth-bypass, 2026-07-05_cve-2026-28699-gitea-oauth2-scope-bypass — different bugs, same product family |
Affected Target
| Field | Value |
|---|---|
| Software / System | Gitea — official Docker images (gitea/gitea), both root and rootless variants |
| Versions Affected | Docker images up to and including 1.26.2. Binary/self-built installs that follow app.example.ini are not affected — this is a Docker-packaging defect, not a code-level bug in Gitea itself. |
| Language / Platform | Go (Gitea), Docker container config |
| Authentication Required | No — the entire bug is that no authentication is required despite reverse-proxy auth being “enabled” |
| Network Access Required | Yes — direct network reachability to the Gitea container’s HTTP port |
Summary
Gitea supports reverse-proxy authentication: put it behind a proxy that sets an X-WEBAUTH-USER header, and Gitea trusts that header for the username, gated by REVERSE_PROXY_TRUSTED_PROXIES — an IP allowlist meant to ensure only the actual proxy can set that header. The documented-safe default (app.example.ini) is 127.0.0.0/8,::1/128 (loopback only). The official Docker image, however, hard-codes REVERSE_PROXY_TRUSTED_PROXIES = * in its packaged app.ini template (docker/root/etc/templates/app.ini:55, and the rootless equivalent) — a wildcard that trusts every source IP. Any operator who enables reverse-proxy login on the stock Docker image, without realizing the packaged default differs from the documented one, exposes an unauthenticated impersonation bypass: any client that can reach the container directly can send X-WEBAUTH-USER: <username> and be logged into that account, no password or token required. With auto-registration also enabled, an attacker can create and log into brand-new admin-named accounts on the spot. Reported to Gitea 2026-05-26, CVE published 2026-07-03, fixed in 1.26.3/1.26.4. Sysdig reported active in-the-wild probing/exploitation starting within about two weeks of disclosure.
Vulnerability Details
Root Cause
The vulnerability is a packaging/configuration defect, not a code bug — tracked as CWE-290 (Authentication Bypass by Spoofing) / CWE-1188 (Insecure Default Initialization of Resource). Gitea’s reverse-proxy-auth feature is designed so that a client-supplied X-WEBAUTH-USER header is only honored when the request’s source IP falls within REVERSE_PROXY_TRUSTED_PROXIES. The official Docker image’s bundled app.ini template sets this allowlist to *, which matches any IP and therefore defeats the entire access-control check. Once ENABLE_REVERSE_PROXY_AUTHENTICATION=true is set (a normal, documented SSO configuration step), the header-trust gate that should have restricted identity injection to the proxy alone is a no-op — because the packaged default silently diverges from the documented-safe default (127.0.0.0/8,::1/128) that binary/self-built installs use.
Attack Vector
- Identify a Gitea instance running the official Docker image with reverse-proxy authentication enabled and directly reachable (not exclusively behind the intended authenticating proxy — e.g., misconfigured network exposure, missing firewall rules, or a proxy that doesn’t strip client-supplied headers).
- Send any HTTP request to the instance with
X-WEBAUTH-USER: <target-username>set. - Gitea’s web session layer accepts the header at face value (the trusted-proxies check passes because it’s
*) and logs the request in as that user — no password, no session cookie, no token. - If reverse-proxy auto-registration is also enabled, a header naming a non-existent username causes Gitea to create that account on the spot and log the attacker in as it — including admin-sounding usernames if the attacker can guess or brute-force one that doesn’t collide with an existing account.
The bypass affects the web session interface only; Gitea’s token API at /api/v1/... ignores the X-WEBAUTH-USER header and is not affected by this specific bug.
Impact
Full unauthenticated account impersonation, up to and including administrator takeover — an attacker who knows or guesses an admin username (admin, gitea_admin, etc.) gains full administrative control of the Gitea instance: source code access across all repos, CI/CD (Actions) configuration, webhook/integration secrets, and the ability to push malicious commits or backdoor pipelines. With auto-registration enabled, the impact extends to on-demand creation of arbitrary accounts. Sysdig’s telemetry shows real-world reconnaissance/exploitation attempts against exposed instances beginning within roughly two weeks of the CVE’s publication.
Environment / Lab Setup
Target: gitea/gitea:1.26.2 (official Docker image, vulnerable)
Attacker: Any host with Python 3 (standard library only — no dependencies)
Tools: Docker + docker compose, python3
Setup Steps
| |
Proof of Concept
See
poc.py,detect.py, anddocker-compose.ymlin this folder — mirrored verbatim from rz1027/CVE-2026-20896 (MIT licensed), the researcher’s own PoC repository. Verified before ingestion: all files referenced in the upstream README actually exist,poc.py/detect.pyuse only the Python standard library with no obfuscation or suspicious network calls, anddocker-compose.ymlstands up the unmodified officialgitea/gitea:1.26.2image — no scam, dropper, or phantom-exploit indicators found.
Step-by-Step Reproduction
- Stand up the vulnerable target —
docker-compose.ymlin this folder bootsgitea/gitea:1.26.2withENABLE_REVERSE_PROXY_AUTHENTICATION=trueandENABLE_REVERSE_PROXY_AUTO_REGISTRATION=true, deliberately leavingREVERSE_PROXY_TRUSTED_PROXIESunset so it inherits the image’s vulnerable*default. - Confirm unauthenticated baseline — request
/user/settingswith no header; expect an HTTP 303 redirect to login (not authenticated). - Send the spoofed header — request
/user/settingswithX-WEBAUTH-USER: <victim>set; the response is HTTP 200 and the page content shows the requester logged in as<victim>. - Confirm account creation — request
/<victim>’s profile page; HTTP 200 confirms the account was auto-created on the fly.
Exploit Code
| |
A non-destructive detect.py is also included, for checking an instance you own/are authorized to test — it sends a single probe with an obviously-fake username (cve-2026-20896-probe) and compares the response against an unauthenticated baseline, rather than attempting real impersonation.
Expected Output
1) /user/settings with no header -> HTTP 303 (redirect to login = not authed)
2) /user/settings with X-WEBAUTH-USER -> HTTP 200
logged in as 'pocadmin' - no password, no token, any source IP
3) /pocadmin profile page -> HTTP 200 (account created on the fly)
Detection & Indicators of Compromise
GET /user/settings ... X-WEBAUTH-USER: <any> -> 200, from unexpected/direct-external IPs
SIEM / IDS Rule (example):
alert http any any -> any any (msg:"Possible CVE-2026-20896 Gitea reverse-proxy auth bypass attempt"; content:"X-WEBAUTH-USER:"; http_header; sid:9000201; rev:1;)
Remediation
| Action | Detail |
|---|---|
| Patch | Upgrade to Gitea 1.26.3 / 1.26.4 or later — reverse-proxy auth is opt-in with a safe default in the fixed images, and the wildcard is no longer shipped. |
| Workaround (if patching isn’t immediate) | Explicitly set REVERSE_PROXY_TRUSTED_PROXIES to your actual reverse proxy’s IP/CIDR (never *), or disable ENABLE_REVERSE_PROXY_AUTHENTICATION entirely if you don’t use SSO via reverse proxy. |
| Config Hardening | Ensure the Gitea container’s HTTP port is never directly reachable from outside the trusted proxy’s network path; audit any exposed Gitea Docker deployment’s app.ini for the packaged default rather than assuming documentation matches shipped config. |
References
- CVE-2026-20896 — CVE.org
- Gitea Security Advisory — GHSA-f75j-4cw6-rmx4
- Gitea 1.26.3 / 1.26.4 release notes
- Public PoC — rz1027/CVE-2026-20896
- The Hacker News — Threat Actors Probe Gitea Docker Flaw
- BleepingComputer — Hackers Exploit Critical Auth Bypass in Gitea Docker Image
Notes
Surfaced via a daily all-platforms CVE discovery pass (WebSearch/news sweep) on 2026-07-11, then verified before ingestion per this archive’s standing rule: the PoC repository’s actual file contents were fetched and read (not just the README description), confirming poc.py/detect.py/docker-compose.yml all genuinely exist, contain clean stdlib-only Python with no obfuscation or suspicious behavior, and match the described exploit exactly. The repo author (rz1027) is the credited reporter in Gitea’s own advisory and explicitly disputes a different repo (“Exploitarium”) having been wrongly credited for this finding in some press coverage — noted here for attribution accuracy, not verified independently beyond what the advisory itself confirms (reporter credit in GHSA-f75j-4cw6-rmx4 matches).
| |