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注入, 协议分析, 暗色界面, 暴力破解, 权限提升, 自定义脚本