High severity7.2OSV Advisory· Published Oct 8, 2025· Updated Apr 15, 2026
CVE-2025-61524
CVE-2025-61524
Description
An issue in the permission verification module and organization/application editing interface in Casdoor v2.26.0 and before, and fixed in v.2.63.0, allows remote authenticated administrators of any organization within the system to bypass the system's permission verification mechanism by directly concatenating URLs after login
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/casdoor/casdoorGo | < 2.63.0 | 2.63.0 |
Affected products
1Patches
1d883db907bb6feat: improve authz_filter (#4195)
11 files changed · +37 −13
authz/authz.go+4 −0 modified@@ -143,6 +143,10 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o return false } + if user.IsGlobalAdmin() { + return true + } + if user.IsAdmin && (subOwner == objOwner || (objOwner == "admin")) { return true }
controllers/application.go+1 −1 modified@@ -237,7 +237,7 @@ func (c *ApiController) UpdateApplication() { return } - c.Data["json"] = wrapActionResponse(object.UpdateApplication(id, &application)) + c.Data["json"] = wrapActionResponse(object.UpdateApplication(id, &application, c.IsGlobalAdmin())) c.ServeJSON() }
controllers/resource.go+1 −1 modified@@ -364,7 +364,7 @@ func (c *ApiController) UploadResource() { } applicationObj.TermsOfUse = fileUrl - _, err = object.UpdateApplication(applicationId, applicationObj) + _, err = object.UpdateApplication(applicationId, applicationObj, true) if err != nil { c.ResponseError(err.Error()) return
controllers/syncer.go+1 −1 modified@@ -103,7 +103,7 @@ func (c *ApiController) UpdateSyncer() { return } - c.Data["json"] = wrapActionResponse(object.UpdateSyncer(id, &syncer)) + c.Data["json"] = wrapActionResponse(object.UpdateSyncer(id, &syncer, c.IsGlobalAdmin())) c.ServeJSON() }
controllers/token.go+1 −1 modified@@ -105,7 +105,7 @@ func (c *ApiController) UpdateToken() { return } - c.Data["json"] = wrapActionResponse(object.UpdateToken(id, &token)) + c.Data["json"] = wrapActionResponse(object.UpdateToken(id, &token, c.IsGlobalAdmin())) c.ServeJSON() }
controllers/webhook.go+1 −1 modified@@ -105,7 +105,7 @@ func (c *ApiController) UpdateWebhook() { return } - c.Data["json"] = wrapActionResponse(object.UpdateWebhook(id, &webhook)) + c.Data["json"] = wrapActionResponse(object.UpdateWebhook(id, &webhook, c.IsGlobalAdmin())) c.ServeJSON() }
object/application.go+6 −2 modified@@ -640,13 +640,17 @@ func GetAllowedApplications(applications []*Application, userId string, lang str return res, nil } -func UpdateApplication(id string, application *Application) (bool, error) { +func UpdateApplication(id string, application *Application, isGlobalAdmin bool) (bool, error) { owner, name := util.GetOwnerAndNameFromId(id) oldApplication, err := getApplication(owner, name) if oldApplication == nil { return false, err } + if !isGlobalAdmin && oldApplication.Organization != application.Organization { + return false, fmt.Errorf("auth:Unauthorized operation") + } + if name == "app-built-in" { application.Name = name } @@ -723,7 +727,7 @@ func AddApplication(application *Application) (bool, error) { } func deleteApplication(application *Application) (bool, error) { - affected, err := ormer.Engine.ID(core.PK{application.Owner, application.Name}).Delete(&Application{}) + affected, err := ormer.Engine.ID(core.PK{application.Owner, application.Name}).Where("organization = ?", application.Organization).Delete(&Application{}) if err != nil { return false, err }
object/syncer.go+4 −2 modified@@ -153,13 +153,15 @@ func GetMaskedSyncers(syncers []*Syncer, errs ...error) ([]*Syncer, error) { return syncers, nil } -func UpdateSyncer(id string, syncer *Syncer) (bool, error) { +func UpdateSyncer(id string, syncer *Syncer, isGlobalAdmin bool) (bool, error) { owner, name := util.GetOwnerAndNameFromId(id) s, err := getSyncer(owner, name) if err != nil { return false, err } else if s == nil { return false, nil + } else if !isGlobalAdmin && s.Organization != syncer.Organization { + return false, fmt.Errorf("auth:Unauthorized operation") } session := ormer.Engine.ID(core.PK{owner, name}).AllCols() @@ -218,7 +220,7 @@ func AddSyncer(syncer *Syncer) (bool, error) { } func DeleteSyncer(syncer *Syncer) (bool, error) { - affected, err := ormer.Engine.ID(core.PK{syncer.Owner, syncer.Name}).Delete(&Syncer{}) + affected, err := ormer.Engine.ID(core.PK{syncer.Owner, syncer.Name}).Where("organization = ?", syncer.Organization).Delete(&Syncer{}) if err != nil { return false, err }
object/token.go+4 −2 modified@@ -180,12 +180,14 @@ func (token *Token) popularHashes() { } } -func UpdateToken(id string, token *Token) (bool, error) { +func UpdateToken(id string, token *Token, isGlobalAdmin bool) (bool, error) { owner, name := util.GetOwnerAndNameFromId(id) if t, err := getToken(owner, name); err != nil { return false, err } else if t == nil { return false, nil + } else if !isGlobalAdmin && t.Organization != token.Organization { + return false, nil } token.popularHashes() @@ -210,7 +212,7 @@ func AddToken(token *Token) (bool, error) { } func DeleteToken(token *Token) (bool, error) { - affected, err := ormer.Engine.ID(core.PK{token.Owner, token.Name}).Delete(&Token{}) + affected, err := ormer.Engine.ID(core.PK{token.Owner, token.Name}).Where("organization = ?", token.Organization).Delete(&Token{}) if err != nil { return false, err }
object/webhook.go+4 −2 modified@@ -104,12 +104,14 @@ func GetWebhook(id string) (*Webhook, error) { return getWebhook(owner, name) } -func UpdateWebhook(id string, webhook *Webhook) (bool, error) { +func UpdateWebhook(id string, webhook *Webhook, isGlobalAdmin bool) (bool, error) { owner, name := util.GetOwnerAndNameFromId(id) if w, err := getWebhook(owner, name); err != nil { return false, err } else if w == nil { return false, nil + } else if !isGlobalAdmin && w.Organization != webhook.Organization { + return false, fmt.Errorf("auth:Unauthorized operation") } affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(webhook) @@ -130,7 +132,7 @@ func AddWebhook(webhook *Webhook) (bool, error) { } func DeleteWebhook(webhook *Webhook) (bool, error) { - affected, err := ormer.Engine.ID(core.PK{webhook.Owner, webhook.Name}).Delete(&Webhook{}) + affected, err := ormer.Engine.ID(core.PK{webhook.Owner, webhook.Name}).Where("organization = ?", webhook.Organization).Delete(&Webhook{}) if err != nil { return false, err }
routers/authz_filter.go+10 −0 modified@@ -32,6 +32,7 @@ type Object struct { Name string `json:"name"` AccessKey string `json:"accessKey"` AccessSecret string `json:"accessSecret"` + Organization string `json:"organization"` } func getUsername(ctx *context.Context) (username string) { @@ -110,6 +111,15 @@ func getObject(ctx *context.Context) (string, string, error) { return "", "", nil } + if strings.HasSuffix(path, "-application") || strings.HasSuffix(path, "-token") || + strings.HasSuffix(path, "-syncer") || strings.HasSuffix(path, "-webhook") { + return obj.Organization, obj.Name, nil + } + + if strings.HasSuffix(path, "-organization") { + return obj.Name, obj.Name, nil + } + if path == "/api/delete-resource" { tokens := strings.Split(obj.Name, "/") if len(tokens) >= 5 {
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-5m9m-j5p7-m7f9ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-61524ghsaADVISORY
- casdoor.comnvdWEB
- gist.github.com/DevHjz/e75cea851d48e5f5478ac2a90757851anvdWEB
- github.com/casdoor/casdoor/commit/d883db907bb6e0b95737ef8e8b57b7da9078cbddnvdWEB
- github.com/casdoor/casdoor/releases/tag/v2.63.0nvdWEB
News mentions
0No linked articles in our index yet.