Critical Gitea Docker Vulnerability (CVE-2026-20896): Patch Your Self-Hosted Git Server Now

A CVSS 9.8 critical vulnerability in Gitea Docker images allows attackers to impersonate any user via reverse proxy misconfiguration. The flaw is under active exploitation. Here's how to check if you're affected and patch immediately.

Prerequisites

  • Docker installed
  • Access to your Gitea instance
A terminal window showing a Docker container security alert with red warning text against a dark background, representing the urgency of patching the Gitea vulnerability

If you run a self-hosted Gitea instance using the official Docker image, stop what you are doing and read this. A critical vulnerability tracked as CVE-2026-20896 has been assigned a CVSS score of 9.8 out of 10, and it is under active exploitation in the wild. The Singapore Cyber Security Agency issued an alert on July 8 confirming that attackers are actively using this flaw to gain unauthorized access to Gitea instances. The vulnerability does not require sophisticated exploit chains, privilege escalation, or any user interaction. It is exploitable with a single HTTP request.

The vulnerability is not a code execution bug or a memory corruption issue. It is a configuration default that trusts too much — and that makes it both easy to exploit and easy to fix, provided you act before an attacker finds your instance.

What the vulnerability actually does

The problem sits in how Gitea Docker images handle reverse proxy authentication. When you put a reverse proxy like Nginx, Traefik, or Caddy in front of Gitea, one common configuration is to let the proxy handle authentication and pass the authenticated username to Gitea via an HTTP header. This is useful when you want single sign-on across multiple services or when you are using an external identity provider that your reverse proxy already integrates with.

Here is how the flow is supposed to work: a user makes a request to your Gitea instance. The reverse proxy intercepts it, authenticates the user against your identity provider, and then forwards the request to Gitea with an added X-WEBAUTH-USER header containing the authenticated username. Gitea reads this header and treats the user as logged in without requiring a separate Gitea password.

The critical safety mechanism in this setup is that Gitea must only trust this header when it comes from the reverse proxy. If anyone on the internet can send a request with a forged X-WEBAUTH-USER header and Gitea accepts it, the authentication system collapses entirely. That is what happened here.

The trusted proxy list is controlled by the REVERSE_PROXY_TRUSTED_PROXIES environment variable. In affected Gitea Docker images — version 1.26.2 and earlier — the default value for this variable is an empty string, which Gitea interprets as “trust all IP addresses.” Translation: if reverse proxy authentication is enabled and REVERSE_PROXY_TRUSTED_PROXIES has not been explicitly set, anyone on the internet can send a request with a forged X-WEBAUTH-USER header and Gitea will treat them as that user.

If an attacker knows or guesses an administrator’s username — and most Gitea instances have a predictable admin account name like admin, root, or gitea — they can impersonate that administrator and gain full control of the Gitea instance. That means access to every repository, every private key, every commit, and potentially every secret stored in CI/CD pipeline configurations or repository settings. A single HTTP header is all it takes.

Check if your instance is affected

First, verify which Gitea Docker image version you are running:

docker inspect gitea | grep -i "image\|GITEA_VERSION"

Or, if you use Docker Compose:

docker compose exec gitea gitea --version

If you are running Gitea Docker image version 1.26.2 or earlier and have reverse proxy authentication enabled, you are vulnerable. Even if you think reverse proxy authentication is disabled, check your configuration explicitly. The relevant environment variables are REVERSE_PROXY_AUTHENTICATION_USER (or REVERSE_PROXY_AUTH_USER) and REVERSE_PROXY_TRUSTED_PROXIES.

Check your current settings with:

docker compose exec gitea env | grep REVERSE_PROXY

If you see REVERSE_PROXY_TRUSTED_PROXIES= (empty) or the variable is not set at all, and REVERSE_PROXY_AUTHENTICATION_USER is set to any value, your instance is exposed.

Patch immediately

The fix has two layers: update the Docker image and harden the proxy trust configuration.

Step 1: Pull the latest Gitea Docker image

docker pull gitea/gitea:latest

The patched version is 1.26.3 and above. If you use a specific version tag in your Compose file, update it:

services:
  gitea:
    image: gitea/gitea:1.26.3

Then redeploy:

docker compose down && docker compose up -d

Step 2: Explicitly set REVERSE_PROXY_TRUSTED_PROXIES

Even after updating, do not rely on the new default. Explicitly set the trusted proxy IP range in your environment configuration:

environment:
  - REVERSE_PROXY_TRUSTED_PROXIES=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16

Replace the CIDR ranges above with the actual IP addresses of your reverse proxy. If your reverse proxy runs on the same Docker network as Gitea, use the container’s network subnet. You can find it with:

docker network inspect gitea_default | jq '.[0].IPAM.Config'

If your reverse proxy is on the same host and connecting via localhost, set:

- REVERSE_PROXY_TRUSTED_PROXIES=127.0.0.1/32

Step 3: If you cannot update immediately, apply the workaround

If upgrading the image right now is not possible, the workaround is to set REVERSE_PROXY_TRUSTED_PROXIES to a specific value on your current version. This closes the attack surface without requiring an image update:

docker compose stop gitea
# Edit your docker-compose.yml to add REVERSE_PROXY_TRUSTED_PROXIES
docker compose up -d gitea

This workaround is effective because the vulnerability is entirely in the configuration default, not in the application code.

Check your logs for signs of compromise

After patching, carefully review your Gitea access logs for suspicious activity. Look for administrative actions and privileged operations performed by unexpected users or from unexpected IP addresses:

docker compose exec gitea cat /data/gitea/log/gitea.log | grep -i "admin\|sudo"

Pay particular attention to any log entries that show user impersonation — a regular user performing admin-level actions, or activity originating from IP addresses outside your expected range. Specifically look for log lines where the authenticated user differs from the user who performed the action, or where administrative API endpoints were accessed by non-admin accounts. If you find evidence of compromise, rotate all secrets stored in the Gitea instance, including repository deploy keys, webhook secrets, and any credentials stored in CI/CD pipeline configurations. Assume every repository that was accessible to the impersonated user is compromised and audit commit history for unauthorized changes.

Why this keeps happening with Docker images

The REVERSE_PROXY_TRUSTED_PROXIES default is part of a broader pattern in self-hosted software where Docker images ship with development-convenient defaults that become security liabilities in production. An empty trusted proxy list is easier to get started with — you do not have to figure out your proxy’s IP address before the application works — but it is exactly the kind of default that should never survive into a tagged release image.

Gitea is not alone here. PostgreSQL Docker images used to ship with trust authentication by default, meaning any connection to the database was accepted without a password. Redis images exposed unauthenticated access for years. MongoDB’s default configuration allowed unauthenticated remote connections until a widely publicized ransomware campaign forced a change. Each time, the fix followed the same pattern: the maintainers changed the default in a new version, and every self-hoster who did not read the release notes stayed vulnerable until they manually updated their configuration or got breached.

The self-hosted software ecosystem has a structural tension between onboarding ease and production security. Maintainers want their software to work immediately after a docker run command. Users want to try things without reading 50 pages of configuration documentation. The compromise, almost always, is a set of defaults that prioritize “it works” over “it is safe.” The problem becomes visible only when a CVE drops and thousands of instances are suddenly exploitable by anyone who can send an HTTP request.

If you run self-hosted services, checking for insecure defaults in environment variables should be part of your deployment checklist, not something you do after a CVE drops. Look for variables that contain the words “trusted,” “allowed,” “authenticated,” or “enabled.” If any of them default to empty, wildcard, or 0.0.0.0/0, understand what they control before you expose the service to a network.

Beyond this CVE: auditing your reverse proxy authentication setup

If you use reverse proxy authentication for any service — not just Gitea — this is a good moment to audit your configuration across the board. The class of vulnerability is not specific to Gitea. Any application that delegates authentication to a reverse proxy and trusts headers without verifying their origin has the same exposure.

For each service behind your reverse proxy that uses header-based authentication, verify three things:

First, confirm that the application’s trusted proxy list is explicitly set to the IP addresses or CIDR ranges of your reverse proxy. An empty or wildcard value is a red flag.

Second, check that your reverse proxy is stripping incoming authentication headers before adding its own. If your proxy passes through a header that the client sent, the client can forge it. In Nginx, this means using proxy_set_header directives that explicitly set the header value rather than passing through the client’s value. In Traefik, use the headers.customrequestheaders middleware. In Caddy, use the header_down directive to strip client-supplied headers before the proxy adds its own.

Third, review whether you actually need reverse proxy authentication for each service. It adds complexity and expands your attack surface. If a service has its own robust authentication system and you do not need SSO across multiple services, disabling reverse proxy authentication entirely is often the safer choice. Simplicity is a security feature that never gets a CVE.

The patch window for CVE-2026-20896 is closing fast because the vulnerability is trivially exploitable. An attacker only needs to send a crafted HTTP header to a publicly accessible Gitea instance. No exploit code, no chain of chained vulnerabilities, just a single header. If your instance is exposed, patch it now — not after you finish reading, not after lunch, now.