Severity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
Primary rating from GitHub Advisory.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
Lifecycle Timeline
4DescriptionGitHub Advisory
Summary
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.
Details
In the first file below, the rate-limit for unauthenticated users can be observed being populated with the ip value. In the second file, it shows it using the c.RealIP() function for the ip case. Due to this, the rate-limit will rely on the value of one of the two mentioned headers (X-Forwarded-For or X-Real-IP). These can be spoofed by users client-side in order to completely bypass any unauthenticated rate-limits in place.
Some reverse proxies like Traefik will overwrite this value by default, but others will not, leaving any deployment that either isn't using a reserve proxy that specifically overwrites the header's value or isn't using a reverse proxy vulnerable.
File 1: pkg\routes\routes.go:318
// This is the group with no auth
// It is its own group to be able to rate limit this based on different heuristics
n := a.Group("")
setupRateLimit(n, "ip")
// Docs
n.GET("/docs.json", apiv1.DocsJSON)
n.GET("/docs", apiv1.RedocUI)
// Prometheus endpoint
setupMetrics(n)
// Separate route for unauthenticated routes to enable rate limits for it
ur := a.Group("")
rate := limiter.Rate{
Period: 60 * time.Second,
Limit: config.RateLimitNoAuthRoutesLimit.GetInt64(),
}
rateLimiter := createRateLimiter(rate)
ur.Use(RateLimit(rateLimiter, "ip"))File 2: pkg\routes\rate_limit.go:41
// RateLimit is the rate limit middleware
func RateLimit(rateLimiter *limiter.Limiter, rateLimitKind string) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c *echo.Context) (err error) {
var rateLimitKey string
switch rateLimitKind {
case "ip":
rateLimitKey = c.RealIP()
case "user":
auth, err := auth2.GetAuthFromClaims(c)
if err != nil {
log.Errorf("Error getting auth from jwt claims: %v", err)
}
rateLimitKey = "user_" + strconv.FormatInt(auth.GetID(), 10)
default:
log.Errorf("Unknown rate limit kind configured: %s", rateLimitKind)
}PoC
- Download and run the default docker compose file via the instructions here: https://vikunja.io/install/. Do not configure a proxy.
- Once running, navigate to the application in a web browser that is using a web proxy, such as Burp Suite.
- Attempt to authenticate to the application with an invalid username and password.
- In the web proxy's logs, locate the request to the
/api/v1/loginendpoint. Observe that the response contains rate-limit details:
HTTP/1.1 403 Forbidden
Cache-Control: no-store
Content-Type: application/json
Vary: Origin
X-Ratelimit-Limit: 10
X-Ratelimit-Remaining: 9
X-Ratelimit-Reset: 1772224455
Date: Fri, 27 Feb 2026 20:33:16 GMT
Content-Length: 54
{"code":1011,"message":"Wrong username or password."}- Add the
X-Forwarded-Forheader with an arbitrary value, like so:X-Forwarded-For: FakeValue. Send the request 10 times, or until the rate-limit is at zero. - Modify the
X-Forwarded-Forheaders value to be different, like so:X-Forwarded-For: NewValue. - Observe that the
X-Ratelimit-Remainingheader's value has reset its countdown and is back at9.
Impact
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.
AnalysisAI
Vikunja API fails to properly validate the source IP address for rate-limiting unauthenticated endpoints, allowing attackers to bypass rate limits by spoofing the X-Forwarded-For or X-Real-IP headers. This affects Vikunja API (pkg:go/code.vikunja.io_api) and enables unlimited brute-force attacks against login endpoints and other unauthenticated routes. A functional proof-of-concept has been published demonstrating the bypass mechanism, making this vulnerability readily exploitable without authentication or user interaction.
Technical ContextAI
Vikunja's rate-limiting middleware (pkg/routes/rate_limit.go) uses Echo framework's c.RealIP() function to extract the client IP address, which by specification returns values from X-Forwarded-For or X-Real-IP headers when present, prioritizing these over the actual TCP socket source IP. This design is vulnerable under CWE-807 (Reliance on Untrusted Inputs in a Security Decision) because it trusts user-supplied headers for security enforcement. The affected component is the Go package code.vikunja.io/api, which implements this flawed rate-limiting logic across unauthenticated route groups. While some reverse proxies like Traefik overwrite these headers to prevent spoofing, deployments without such protective proxies or using proxies that pass headers through transparently remain vulnerable. The vulnerability fundamentally stems from the framework's header-based IP detection being used directly in security decisions without validation of proxy trustworthiness.
RemediationAI
Upgrade Vikunja API to the patched version containing commit a498dd69915a006c07e9d82660a2185d7e8136ee or later as documented in the official GitHub Security Advisory (https://github.com/go-vikunja/vikunja/security/advisories/GHSA-m547-hp4w-j6jx). The patch addresses the root cause by implementing proper trusted proxy validation instead of blindly trusting X-Forwarded-For headers. Until patching is possible, deploy Vikunja behind a reverse proxy (such as Traefik, Nginx, or HAProxy configured with the X-Forwarded-For rewriting enabled) that actively overwrites these headers with the genuine client IP from its own trustworthy source, or disable rate-limit reliance on IP-based detection entirely by implementing authentication-based rate limiting as the primary mechanism. Additionally, restrict network access to the Vikunja API to trusted internal networks only and monitor login endpoint request patterns for evidence of brute-force attacks.
An issue was discovered in Appsmith before 1.52. Rated critical severity (CVSS 9.8), this vulnerability is remotely expl
runc through version 1.0-rc6 (used in Docker before 18.09.2) contains a container escape vulnerability that allows attac
Netmaker makes networks with WireGuard. Rated high severity (CVSS 7.5), this vulnerability is remotely exploitable, no a
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
The News & Blog Designer Pack - WordPress Blog Plugin - (Blog Post Grid, Blog Post Slider, Blog Post Carousel, Blog Post
Docker 1.3.2 allows remote attackers to execute arbitrary code with root privileges via a crafted (1) image or (2) build
Remote code execution in NocoBase Workflow Script Node (npm @nocobase/plugin-workflow-javascript) allows authenticated l
Docker Desktop Community Edition before 2.1.0.1 allows local users to gain privileges by placing a Trojan horse docker-c
Vasion Print (formerly PrinterLogic) Virtual Appliance Host prior to version 25.2.169 and Application prior to version 2
An issue in Plone Docker Official Image 5.2.13 (5221) open-source software that could allow for remote code execution du
Tandoor Recipes is an application for managing recipes, planning meals, and building shopping lists. Rated critical seve
Unauthenticated remote code execution in 9router (npm package) versions 0.4.30 through 0.4.36 allows network-adjacent at
Vendor StatusVendor
SUSE
Severity: Medium| Product | Status |
|---|---|
| openSUSE Leap 15.6 | Fixed |
| SUSE Linux Enterprise Module for Package Hub 15 SP5 | Fixed |
| SUSE Linux Enterprise Module for Package Hub 15 SP6 | Fixed |
| openSUSE Leap 15.5 | Fixed |
Share
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-13706
GHSA-m547-hp4w-j6jx