Vulnerability advisory

GHSA-w6j9-vw59-27wv

Gogs has an Authentication Bypass via Unvalidated Reverse Proxy Headers

Published Updated OSV record ↗

Also known as CVE-2026-25119GO-2026-5695

Severity
  • CVSS 4.0CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:P

Affected versions

AffectedFixed in
All versions before 0.14.30.14.3

Description

Summary

When ENABLE_REVERSE_PROXY_AUTHENTICATION is enabled, Gogs accepts the configured authentication header (default: X-WEBAUTH-USER) directly from client requests without validating that the request originated from a trusted reverse proxy. Any remote attacker who can reach the Gogs service can forge this header to impersonate any user or trigger automatic account creation, completely bypassing authentication.

Root Cause

The vulnerability exists because Gogs reads the authentication header directly from the incoming HTTP request without any verification that the header was set by a trusted reverse proxy.

Vulnerable Code Flow

In internal/context/auth.go lines 206-234:

func authenticatedUser(store AuthStore, ctx *macaron.Context, sess session.Store) (_ *database.User, isBasicAuth, isTokenAuth bool) {
    // ... existing auth checks ...

    if uid <= 0 {
        if conf.Auth.EnableReverseProxyAuthentication {
            // Reads header DIRECTLY from client request - NO VALIDATION!
            webAuthUser := ctx.Req.Header.Get(conf.Auth.ReverseProxyAuthenticationHeader)
            if len(webAuthUser) > 0 {
                user, err := store.GetUserByUsername(ctx.Req.Context(), webAuthUser)
                if err != nil {
                    if !database.IsErrUserNotExist(err) {
                        log.Error("Failed to get user by name: %v", err)
                        return nil, false, false
                    }

                    // Check if enabled auto-registration.
                    if conf.Auth.EnableReverseProxyAutoRegistration {
                        // Creates new user with forged username!
                        user, err = store.CreateUser(
                            ctx.Req.Context(),
                            webAuthUser,
                            gouuid.NewV4().String()+"@localhost",
                            database.CreateUserOptions{
                                Activated: true,
                            },
                        )
                        if err != nil {
                            log.Error("Failed to create user %q: %v", webAuthUser, err)
                            return nil, false, false
                        }
                    }
                }
                // Returns user as authenticated without any verification!
                return user, false, false
            }
        }
        // ... fallback to basic auth ...
    }
    // ...
}

The code has zero validation that:

  1. The request came through a reverse proxy
  2. The header was set by the proxy (not the client)
  3. Gogs is actually behind a reverse proxy
  4. The direct access to Gogs is restricted

The vulnerability occurs when:

  • Gogs is publicly accessible (e.g., 0.0.0.0:3000)
  • ENABLE_REVERSE_PROXY_AUTHENTICATION = true

Proof of Concept

Prerequisites

Gogs instance with the following configuration in custom/conf/app.ini:

[auth]
ENABLE_REVERSE_PROXY_AUTHENTICATION = true

An attacker can impersonate any user including administrators:

# Become admin instantly
curl http://gogs.example.com/ -H "X-WEBAUTH-USER: <username>"

[image: impersonation_example]

Recommended Fixes

Add validation to ensure headers come from trusted sources:

func authenticatedUser(store AuthStore, ctx *macaron.Context, sess session.Store) (_ *database.User, isBasicAuth, isTokenAuth bool) {
    // ... existing code ...

    if uid <= 0 {
        if conf.Auth.EnableReverseProxyAuthentication {
            // Validate request is from trusted proxy
            if !isRequestFromTrustedProxy(ctx.Req) {
                log.Warn("Reverse proxy auth header received from untrusted source: %s", ctx.RemoteAddr())
                return nil, false, false
            }

            webAuthUser := ctx.Req.Header.Get(conf.Auth.ReverseProxyAuthenticationHeader)
            // ... rest of the code ...
        }
    }
    // ...
}

// New validation function
func isRequestFromTrustedProxy(req *http.Request) bool {
    // Check if request is from localhost/trusted IPs
    remoteIP := getRemoteIP(req)

    // Only accept from localhost by default
    if remoteIP.IsLoopback() {
        return true
    }

    // Check against configured trusted proxy IPs
    for _, trustedIP := range conf.Auth.TrustedProxyIPs {
        if remoteIP.String() == trustedIP {
            return true
        }
    }

    return false
}

Add configuration option:

[auth]
ENABLE_REVERSE_PROXY_AUTHENTICATION = false
REVERSE_PROXY_AUTHENTICATION_HEADER = X-WEBAUTH-USER
; Comma-separated list of trusted proxy IPs (default: 127.0.0.1)
TRUSTED_PROXY_IPS = 127.0.0.1,::1
; Whether to require trusted proxy validation (recommended: true)
REQUIRE_TRUSTED_PROXY = true

References

References

  • Codex
  • Claude Code
  • VS Code
  • GitHub Copilot
  • Cursor
  • Cline
  • Windsurf
  • Google Anti-gravity
  • OpenCode
  • Pi
  • Gemini CLI
  • Hermes Agent
  • Zed
  • Junie
  • Qwen Code
  • Kiro
  • Kilo Code
  • Factory Droid

Set up GitHits for your agents

Run this command:

<> bash
npx githits@latest init

What happens next:

  1. Opens your browser to authorize GitHits
  2. Asks whether to set up GitHits at the user or project level
  3. Detects your supported AI coding tools
  4. Lets you choose which tools to configure
  5. Configures the selected tools