BiiTts/CVE-2026-46490-samlify-SAML-Attribute-Injection
GitHub: BiiTts/CVE-2026-46490-samlify-SAML-Attribute-Injection
该项目复现了 samlify <2.13.0 中因 AttributeValue 元素文本未做 XML 转义而导致的 SAML 属性注入漏洞(CVE-2026-46490),完整演示了从 XML 注入到签名有效的权限提升攻击链。
Stars: 0 | Forks: 0
# CVE-2026-46490 — samlify SAML `AttributeValue` XML 注入 → 权限提升
| | |
|---|---|
| **CVE** | CVE-2026-46490 |
| **安全公告** | [GHSA-34r5-q4jw-r36m](https://github.com/tngan/samlify/security/advisories/GHSA-34r5-q4jw-r36m) |
| **受影响版本** | samlify `< 2.13.0` |
| **修复版本** | `2.13.0` |
| **类别** | CWE-91 (XML 注入) → 权限提升 |
| **CVSS** | `8.8` (高危) |
| **认证要求** | 已认证的低权限用户(可控制其自身的某个属性值) |
| **状态** | **已确认** — 使用 `samlify@2.12.0` 完整复现了 IdP→SP 攻击链 |
## 根本原因
`src/libsaml.ts` 通过 `replaceTagsByValue` → `escapeTag` 替换 `{tag}` 占位符:
```
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
};
}
```
正则表达式捕获了一个可选的**前置 `"`** 作为 `quote`。在属性上下文
(`Name="{Name}"`) 中,`quote` 已赋值且该值会经过 `xmlEscape` 转义;而在**元素文本**
(`>{attrEmail}<`) 中,由于没有前置引号,该值会被**原样输出**。
默认的属性模板将值放置在元素文本中:
```
{Value}
```
因此,攻击者控制的包含 `<`/`>` 的属性值会注入原始 XML。
## 漏洞利用
攻击者将其自身的配置文件属性(此处的 `email`)设置为:
```
eve@evil.com
admin
```
这会闭合 `email` 属性,**添加一个伪造的 `role=admin` 属性**,并
重新开启一个一次性属性,以便模板末尾的
` ` 保持标签平衡。然后 IdP 会对
断言进行**签名** —— 涵盖了伪造的属性。符合标准的 SP 会验证
签名(有效)并读取 `role=admin`。
## 复现
```
cd lab && ./setup.sh # npm i samlify@2.12.0 + generate IdP/SP keypairs
node poc.js
```
输出:
```
>>> INJECTION CONFIRMED: forged admin smuggled into the signed assertion
extracted attributes: {"email":"eve@evil.com","role":"admin","ignore":[]}
>>> PRIVILEGE ESCALATION CONFIRMED: SP accepted a signature-valid assertion granting role=admin
```
该 PoC 驱动了 samlify 自身的 IdP(`createLoginResponse`,执行了
存在漏洞的 `replaceTagsByValue` 替换并进行签名)和 SP
(`parseLoginResponse`,**验证签名**并提取属性)。
SP 会输出 `role: "admin"` —— 这是攻击者伪造的属性,而不是 IdP
本意要签发的属性。
## 影响
任何能够影响基于 samlify 的 IdP 上自身 SAML 属性值(如 email、显示
名称等)的用户,都可以生成一个携带任意额外属性的**有效签名**断言 —— 包括组/角色成员资格、权限、`isAdmin`
标志等 —— 并在所有信任该 IdP 的 SP 上提升权限。SAML 签名
验证在此无济于事:因为伪造行为发生在已签名的范围内。
## 修复方案
* 升级至 **samlify ≥ 2.13.0**,该版本不仅对属性上下文,也会对元素上下文中的插值进行 XML 转义。
* 纵深防御:在服务端验证/规范化用户提供的属性值;建议在 SP 端优先使用白名单机制的属性 schema。
## 检测
检查已签发/已消费的断言中是否包含带有 XML 标记的属性值
(``, `` 元素的断言。
有关替换正则表达式、引号启发式规则以及
补丁的详细信息,请参阅 [`ANALYSIS.md`](ANALYSIS.md)。
* 作者:**Caio Fabrício** — [github.com/BiiTts](https://github.com/BiiTts)
* 漏洞致谢属于最初的报告者/供应商安全公告;本代码库
仅供防御和教育目的的独立复现。仅限用于授权的
安全测试。
标签:Apache-2.0, MITM代理, Modbus, PoC, SAML, XML注入, 协议分析, 暗色界面, 暴力破解, 权限提升, 自定义脚本