VYPR
Moderate severityNVD Advisory· Published Mar 20, 2026· Updated Mar 20, 2026

Vikunja has Rate-Limit Bypass for Unauthenticated Users via Spoofed Headers

CVE-2026-29794

Description

Vikunja is an open-source self-hosted task management platform. Starting in version 0.8 and prior to version 2.2.0, unauthenticated users are able to bypass the application's built-in rate-limits by spoofing the X-Forwarded-For or X-Real-IP headers due to the rate-limit relying on the value of (echo.Context).RealIP. Unauthenticated users can abuse endpoints available to them for different potential impacts. The immediate concern would be brute-forcing usernames or specific accounts' passwords. This bypass allows unlimited requests against unauthenticated endpoints. Version 2.2.0 patches the issue.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Vikunja task management platform v0.8 to v2.1 allows unauthenticated users to bypass IP-based rate limits by spoofing X-Forwarded-For or X-Real-IP headers, enabling brute-force attacks.

Vulnerability

Overview

CVE-2026-29794 is a rate-limit bypass vulnerability in the Vikunja open-source task management platform affecting versions 0.8 through 2.1.x. The root cause lies in the rate-limiting middleware relying on Echo's RealIP() function, which trusts the X-Forwarded-For and X-Real-IP headers without validation [1][3]. When no reverse proxy overwrites these headers, an attacker can spoof them to reset their perceived IP address for each request, effectively evading the per-IP rate limits [3]. The flaw exists in the unauthenticated routes group, where rate limits are keyed by the IP address obtained from c.RealIP() [3].

Exploitation

An unauthenticated attacker can send requests to any publicly accessible endpoint—such as login, registration, or password reset forms—while arbitrarily manipulating the X-Forwarded-For header in each request [1][3]. Because the rate limiter uses the spoofed value as the client identifier, the attacker is not throttled and can fire unlimited requests. This bypass does not require any authentication or prior access [1].

Impact

The direct consequence is that an attacker can perform unlimited brute-force attempts against usernames and passwords, increasing the risk of account compromise [1]. Additionally, other unauthenticated endpoints could be flooded, potentially leading to resource exhaustion or information disclosure, though the description highlights password brute-forcing as the primary concern [1][2].

Mitigation

The issue is fixed in Vikunja version 2.2.0, released on 2026-03-20 [1][2]. The patch configures Echo's IPExtractor to either extract the IP directly from the TCP connection (ignoring client-supplied headers) or to validate those headers against a list of trusted proxy CIDR ranges [4]. Administrators are strongly encouraged to update immediately. Users running a reverse proxy that overwrites the X-Forwarded-For or X-Real-IP headers (e.g., Traefik) are partially protected, but full mitigation requires upgrading [3].

AI Insight generated on May 18, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
code.vikunja.io/apiGo
>= 0.8, < 2.2.02.2.0

Affected products

2
  • Vikunja/Vikunjallm-fuzzy
    Range: >=0.8, <2.2.0
  • go-vikunja/vikunjav5
    Range: >= 0.8, < 2.2.0

Patches

1
a498dd69915a

fix: configure Echo IPExtractor to prevent rate limit bypass via spoofed headers

https://github.com/go-vikunja/vikunjakolaenteMar 20, 2026via ghsa
1 file changed · +40 0
  • pkg/routes/routes.go+40 0 modified
    @@ -54,6 +54,7 @@ package routes
     import (
     	"context"
     	"log/slog"
    +	"net"
     	"strings"
     	"time"
     
    @@ -125,6 +126,24 @@ func NewEcho() *echo.Echo {
     		}),
     	})
     
    +	// Configure IP extraction to prevent rate limit bypass via spoofed headers.
    +	// Echo's default RealIP() trusts X-Forwarded-For and X-Real-IP unconditionally,
    +	// which allows attackers to bypass IP-based rate limits.
    +	// See: https://echo.labstack.com/docs/ip-address
    +	switch config.ServiceIPExtractionMethod.GetString() {
    +	case "xff":
    +		trustOptions := parseTrustedProxies(config.ServiceTrustedProxies.GetString())
    +		e.IPExtractor = echo.ExtractIPFromXFFHeader(trustOptions...)
    +		log.Debugf("IP extraction: X-Forwarded-For with %d trusted proxy ranges", len(trustOptions))
    +	case "realip":
    +		trustOptions := parseTrustedProxies(config.ServiceTrustedProxies.GetString())
    +		e.IPExtractor = echo.ExtractIPFromRealIPHeader(trustOptions...)
    +		log.Debugf("IP extraction: X-Real-IP with %d trusted proxy ranges", len(trustOptions))
    +	default:
    +		e.IPExtractor = echo.ExtractIPDirect()
    +		log.Debugf("IP extraction: direct (TCP remote address)")
    +	}
    +
     	e.Logger = log.NewEchoLogger(config.LogEnabled.GetBool(), config.LogHTTP.GetString(), config.LogFormat.GetString())
     
     	// Logger
    @@ -181,6 +200,27 @@ func NewEcho() *echo.Echo {
     	return e
     }
     
    +func parseTrustedProxies(proxies string) []echo.TrustOption {
    +	if proxies == "" {
    +		return nil
    +	}
    +
    +	var options []echo.TrustOption
    +	for _, cidr := range strings.Split(proxies, ",") {
    +		cidr = strings.TrimSpace(cidr)
    +		if cidr == "" {
    +			continue
    +		}
    +		_, ipNet, err := net.ParseCIDR(cidr)
    +		if err != nil {
    +			log.Warningf("Invalid trusted proxy CIDR %q: %v", cidr, err)
    +			continue
    +		}
    +		options = append(options, echo.TrustIPRange(ipNet))
    +	}
    +	return options
    +}
    +
     func setupSentry(e *echo.Echo) {
     	if !config.SentryEnabled.GetBool() {
     		return
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.