CVE-2026-57458 Overview
Vikunja is an open-source self-hosted task management platform affected by a privilege escalation flaw in version 2.3.0. A scoped API token restricted to the oauth.authorize permission can call POST /api/v1/oauth/authorize to obtain an OAuth authorization code. The attacker then exchanges that code at POST /api/v1/oauth/token for a full bearer JSON Web Token (JWT) and refresh token. The resulting credentials ignore the original API token's scope and grant access to routes outside the token's declared permissions for the same user. The issue is tracked under [CWE-269: Improper Privilege Management] and is fixed in version 2.4.0.
Critical Impact
A limited API token can be exchanged for a full-privilege JWT, breaking the token scoping model and allowing lateral access to any API route authorized for the token's owning user.
Affected Products
- Vikunja 2.3.0
- go-vikunja self-hosted deployments running the affected version
- Any Vikunja instance issuing scoped API tokens with oauth.authorize permission
Discovery Timeline
- 2026-10-09 - CVE-2026-57458 published to the National Vulnerability Database (NVD)
- 2026-10-16 - Last updated in NVD database
Technical Details for CVE-2026-57458
Vulnerability Analysis
Vikunja supports two authentication primitives: scoped API tokens and OAuth2-issued JWTs. Scoped API tokens are intended to restrict callers to a narrow set of route groups. The OAuth2 authorize endpoint, however, did not reject requests authenticated with an API token. An attacker holding a token scoped to oauth.authorize could invoke the authorize flow, receive a short-lived authorization code, and swap it at the /api/v1/oauth/token endpoint for a standard bearer JWT and refresh token.
The resulting JWT represents the user, not the scoped token. It carries no record of the originating token's restrictions. The attacker gains the full API surface the user is entitled to, including routes the API token was never meant to reach. This is a Broken Access Control condition expressed as a privilege boundary bypass across two authentication subsystems.
Root Cause
The root cause is missing enforcement at the OAuth authorize handler. The handler trusted whatever authentication middleware produced, including API-token authentication. The scoping logic in pkg/models/api_routes.go also did not treat the oauth_authorize route group as a privilege-sensitive endpoint, so tokens granted that scope could reach the handler without additional checks.
Attack Vector
An authenticated attacker with any scoped API token that includes the oauth.authorize permission sends a crafted authorize request over the network. No user interaction is required. The attacker receives a JWT with the full privileges of the token owner and can call any API endpoint accessible to that user.
// Patch: pkg/modules/auth/oauth2server/authorize.go
// Reject API tokens at the OAuth authorize endpoint (GHSA-v3p6-34mc-hj7v)
func HandleAuthorize(c *echo.Context) error {
if c.Get("api_token") != nil {
return echo.NewHTTPError(http.StatusForbidden,
"API tokens cannot be used to authorize OAuth clients")
}
var req AuthorizeRequest
if err := c.Bind(&req); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid request body")
}
// ...
}
Source: GitHub commit 4ae2e09
// Patch: pkg/models/api_routes.go
// Treat oauth_authorize as a privilege-sensitive route group
routeGroupName == "subscriptions" ||
routeGroupName == "tokens" ||
routeGroupName == "*" ||
routeGroupName == "oauth_authorize" ||
strings.HasPrefix(routeGroupName, "user_") {
return
}
Source: GitHub commit 4ae2e09
Detect Identity Attacks the Moment Authentication Fails
Singularity™ Identity surfaces credential misuse, lateral movement, and privilege escalation in real time, so you can contain the breach before it spreads.
Stop Identity AttacksDetection Methods for CVE-2026-57458
Indicators of Compromise
- POST /api/v1/oauth/authorize requests carrying API-token authentication headers rather than session cookies or user bearer tokens.
- Immediate follow-up POST /api/v1/oauth/token requests from the same client IP exchanging an authorization code.
- Newly issued JWTs tied to users who have scoped API tokens configured with the oauth.authorize permission.
- API activity from a user account that spans route groups beyond the scope of their active API tokens.
Detection Strategies
- Correlate authorize and token endpoint calls by client IP, user agent, and user ID to flag API-token-to-JWT exchanges.
- Baseline API token usage per user and alert on sudden broadening of accessed route groups after an OAuth token exchange.
- Inspect reverse-proxy and application logs for oauth.authorize-scoped tokens hitting any endpoint other than those expected by legitimate OAuth client registration workflows.
Monitoring Recommendations
- Enable verbose audit logging for /api/v1/oauth/authorize and /api/v1/oauth/token and ship logs to a central SIEM.
- Alert on HTTP 200 responses from /api/v1/oauth/authorize where the authenticated principal is an API token.
- Track refresh token issuance rates and investigate spikes tied to accounts with programmatic API token usage.
How to Mitigate CVE-2026-57458
Immediate Actions Required
- Upgrade Vikunja to version 2.4.0 or later, which rejects API tokens at the OAuth authorize endpoint.
- Audit all existing scoped API tokens and revoke any that include the oauth.authorize permission unless strictly required.
- Invalidate active JWTs and refresh tokens that may have been issued through the vulnerable flow since deploying 2.3.0.
- Review user activity logs for unexpected route access following OAuth token exchanges.
Patch Information
The fix is included in Vikunja v2.4.0. The code changes are documented in GitHub commit 4ae2e09 and GitHub Security Advisory GHSA-v3p6-34mc-hj7v. The patch adds an explicit check in HandleAuthorize that returns HTTP 403 when the request is authenticated with an API token, and adds oauth_authorize to the list of privilege-sensitive route groups in pkg/models/api_routes.go.
Workarounds
- If upgrading is not immediately possible, remove the oauth.authorize permission from every scoped API token in the deployment.
- Block POST /api/v1/oauth/authorize at a reverse proxy for any request presenting an API token header rather than a user session cookie.
- Restrict OAuth client registration and authorization workflows to administrator accounts that do not issue scoped API tokens.
# Example nginx rule to block API-token authenticated authorize requests
location = /api/v1/oauth/authorize {
if ($http_authorization ~* "^Bearer tk_") {
return 403;
}
proxy_pass http://vikunja_upstream;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

