Skip to content

GHSA-6rvj-qwjf-3m4q CVE-2026-91972 GO-2026-6721

Vikunja: Every /api/v2 pre-auth endpoint is unthrottled on a stock install while its /api/v1 twin is rate limited

High Go
Severity
0.0 / 10
High · CVSS 4.0
Exploit chance (EPSS)
0.63%
Chance of exploitation in the next 30 days. Higher than 50.37% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-307 Improper Restriction of Excessive Authentication Attempts
Fix
2.6.0
Upgrade code.vikunja.io/api to this version or later

Description

Summary

registerAPIRoutesV2 never applies the unconditional pre-auth rate-limit floor (unauthRateLimit()) to the v2 public routes — it passes that limiter only to /api/v2/ws — and otherwise relies on setupRateLimit, which registers nothing when ratelimit.enabled is false (the default). So on a stock install every v2 pre-auth endpoint (login, register, password-reset token, oauth token) is unthrottled, while its v1 twin is throttled.

Details

unauthRateLimit() -> perMinuteIPRateLimit("noauth", RateLimitNoAuthRoutesLimit) (pkg/routes/rate_limit.go, ~lines 100-118) is an unconditional per-IP floor (default 10/60s) that deliberately ignores RateLimitEnabled, which is why v1's pre-auth routes are throttled even with the global limiter off. v1 applies it: ur := a.Group(""); ur.Use(unauthRateLimit()) (pkg/routes/routes.go ~line 459). registerAPIRoutesV2 (~lines 405-431) passes the unauthRateLimit() instance only to /api/v2/ws; its auth routes get only setupRateLimit(a, ...), which is config-gated and registers nothing by default.

PoC (verified at runtime against v2.5.0)

POST /api/v1/login              x25 -> 429 from attempt 5
POST /api/v2/login              x25 -> 403 x25, 429 x0
POST /api/v1/user/password/token     -> 429 (throttled)
POST /api/v2/user/password/token x20 -> 404 x20, 429 x0

Request bodies are byte-identical across versions (shared user.Login / user.PasswordTokenRequest). Both v2 endpoints reach their handlers (403/404, not route-404), so the comparison is valid.

Impact

The pre-auth rate-limit floor — the instance's only default anti-brute-force / anti-abuse control — is absent on all v2 public endpoints. Enables unbounded credential guessing, account-enumeration probing, and password-reset flooding on a default install. Reported as an authentication-control bypass, not a DoS.

Fix

Apply unauthRateLimit() to the v2 public route group, matching v1.

Affected versions

Go

PackageVulnerableFixed in
code.vikunja.io/api
< 2.6.0
2.6.0
code.vikunja.io/api
all versions
No fix yet

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

code.vikunja.io/api Go → 2.6.0

go
go get code.vikunja.io/api@v2.6.0 && go mod tidy

Severity breakdown

CVSS 4.0 0.0

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

Attack vector
Network
Attack complexity
Low
Attack requirements
None
Privileges required
None
User interaction
None
Confidentiality (vulnerable system)
High
Integrity (vulnerable system)
None
Availability (vulnerable system)
None
Confidentiality (subsequent systems)
None
Integrity (subsequent systems)
None
Availability (subsequent systems)
None

CVSS 3.1 7.5

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
None
Availability
None

Weakness

CWE-307: Improper Restriction of Excessive Authentication Attempts

The product does not implement sufficient measures to prevent multiple failed authentication attempts within a short time frame.

How to prevent it
  • Architecture and Design: Common protection mechanisms include: Disconnecting the user after a small number of failed attempts Implementing a timeout Locking out a targeted account Requiring a computational task on the user's part.
  • Architecture and Design: Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid [REF-1482]. Consider using libraries with authentication capabilities such as OpenSSL or the ESAPI Authenticator. [REF-45]

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-m687-p538-r5hp
Vikunja: Permissive Cross-domain Security Policy trusts every localhost origin which should not be trusted
Medium Also affects code.vikunja.io/api
GHSA-fmmf-xq98-g327
Vikunja: Write-level project members can delete admin-tier link shares through an unloaded permission check
Medium Also affects code.vikunja.io/api
GHSA-pjr3-86v4-5p7w
Vikunja: Explicit lower-permission share on a sub-project is silently overridden by an inherited parent permission (broken access control / privilege-management regression in v2.6.0)
Medium Also affects code.vikunja.io/api
GHSA-hjx8-qv73-f7cm
Vikunja: Webhooks and link shares survive every revocation path, so a removed collaborator keeps a live feed
High Also affects code.vikunja.io/api
GHSA-fprf-r6rv-xg99
Vikunja: Saved filter creation with an empty filter string recalculates task positions across all tenants
Medium Also affects code.vikunja.io/api
GHSA-4hv6-xc92-j86g
Vikunja: WebSocket authentication ignores server-side session state, so revoked sessions keep receiving live pushes
High Also affects code.vikunja.io/api
GHSA-w2ch-4xgr-22ww
Vikunja: Task relation deletion does not check read access to the other task, allowing cross-project relation removal
Low Also affects code.vikunja.io/api
GHSA-8wvg-r2j4-3737
Vikunja: Assignee email addresses disclosed to read-only project members via the task assignees endpoint
Medium Also affects code.vikunja.io/api
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor