xmall 后台订单打印页存在由前台订单字段触发的存储型 XSS
漏洞描述
在审计 xmall 源码时发现,前台订单创建接口会信任并持久化请求体中的收货地址和商品名称,后台订单打印页随后把这些字段写入 HTML Sink,形成跨前台用户到后台订单人员的存储型 XSS。
该数据流已在授权的本地测试环境中完成无害触发验证。为避免扩大风险,本 Issue 不提供可执行 payload。
受影响版本
README 将订单打印功能列为 v1.1 功能;仓库没有发布 tag。当前 master 提交 19e7917d5ed3bd2a2421a3a246ad494c133ba94c 仍保留该链路,首个修复版本未知。
漏洞位置
- 输入入口:
POST /member/addOrder - 攻击者可控字段:
streetName、goodsList[*].productName - 持久化位置:
xmall-sso/xmall-sso-service/src/main/java/cn/exrick/sso/service/impl/OrderServiceImpl.java - 渲染位置:
xmall-manager-web/src/main/webapp/WEB-INF/jsp/order-print.jsp:132,140
漏洞分析
数据流如下:
streetName / goodsList[*].productName
→ OrderController.addOrder
→ OrderServiceImpl.createOrder
→ tb_order_shipping.receiver_address / tb_order_item.title
→ 后台 GET /order/detail/{orderId}
→ order-print.jsp 中的 .html() 和 HTML 字符串拼接。
前台模块注册的 LimitRaterInterceptor 只执行限流并始终放行,不进行登录、token 或 body.userId 归属校验;createOrder 只检查请求中的 userId 是否对应现有会员。后台打印页由 Shiro 的最终 /* = authc 规则保护,因此触发者是独立的已登录后台人员,而不是输入者本人。
关键 Sink:
$("#expressAdress").html(data.result.tbOrderShipping.receiverAddress);
$("#products").append("<tr class='text-c'><td>" + products[i].title + "</td>...");影响
能够访问前台接口的攻击者可创建包含恶意文本字段的订单;后台订单人员查看或打印该订单时,攻击者控制的内容会在后台浏览器上下文中执行。可能影响后台会话中的数据读取和操作完整性,但需要受害者打开对应订单,故按中等严重度报告。
与已有 CVE 的边界
CVE-2025-65540 / Issue #101 涉及 member-list.jsp、member-show.jsp 中会员 username/description 的渲染。本 Issue 涉及不同的输入接口、数据库字段、后台页面和修复位置:/member/addOrder → 订单地址/商品标题 → order-print.jsp。Issue #103 讨论前台会员接口缺失鉴权;该问题会放大本链路,但没有覆盖订单打印页的 XSS Sink。
修复建议
- 在订单打印页使用
.text()、textContent或文本节点渲染普通文本字段,避免字符串拼接 HTML。 - 创建订单时从服务端会话确定会员身份,并根据商品 ID 从服务端重新读取商品名称,不信任请求体快照字段。
- 对地址等文本字段增加合理的长度和值域约束。
- 增加从前台订单输入到后台打印页的回归测试。
参考:
- CVE-2025-65540:https://nvd.nist.gov/vuln/detail/CVE-2025-65540
- Issue #101:https://github.com/Exrick/xmall/issues/101
- Issue #103:https://github.com/Exrick/xmall/issues/103
Source: Exrick/xmall