Scratch 这件事最反常的地方,不是又冒出一个 SVG 漏洞。
反常的是,它几乎每年都在同一个坑边补砖:用户上传 SVG,平台清洗,浏览器又从新的 SVG / CSS 入口绕回来。
危险动作很具体。Scratch 会解析用户控制的 SVG,并把它短暂插入主 document,用来测量边界等操作。时间很短,但浏览器不讲情面。只要内容进了主文档,脚本、请求、样式都有机会发生。
受影响的是加载恶意项目的 Scratch 用户。风险也要分开看:XSS 可能代用户操作;HTTP leak 可能在无点击情况下暴露 IP;样式污染可以隐藏按钮、诱导点击,甚至伪装成 scratch.mit.edu 页面内的提示。它不是“所有账号必然被接管”,但已经足够构成平台级风险。
时间线:补丁一直在追语法
这条漏洞史很适合用一张表看。它不是一次事故,而是一组重复模式。
| 时间 | 绕过入口 | 主要风险 | 修补方式 |
|---|---|---|---|
| 2019 | <script> | XSS | 正则删除脚本 |
| 2020 | 大小写、事件处理器等 | XSS | 引入 DOMPurify |
| 2022 | <image href> | 外部请求、IP 泄露 | DOMPurify hook 删除远程 href |
| 2023 | CSS @import | 外部请求 | 加 CSS parser |
| 2024 | Paper.js 接收未清洗 SVG | 编辑器侧 XSS | 扩展清洗流程 |
| 2025/2026 | url()、转义、多个 URL、CSS 变量 | 外部请求 | 继续加规则 |
| 2026 | 长 transition、image-set() | 样式残留、外部请求 | 披露时仍未修复 |
这里不能简单把锅扣给 DOMPurify。DOMPurify 不承诺阻止所有 HTTP leak。SVG 和 CSS 里能触发网络请求的路径太多,清洗器本来就很难替平台兜完整个浏览器行为。
真正的错位在 Scratch 的使用场景。它想把“不可信内容”变成“清洗后可临时进入主文档的内容”。这一步一旦成立,后面每一层过滤都会变成军备竞赛。
对普通 Scratch 用户、家长和教育机构,现实动作很朴素:不要把陌生项目当成完全无害的玩具页面;课堂或社群里如果要打开未知项目,尽量使用低权限账号和受控网络环境。风险不是天天发生,但一旦发生,用户很难靠肉眼识别。
对做 Web 安全和前端架构的人,重点也不在“再写一个更聪明的正则”。重点是检查自己的产品里有没有同类动作:把用户生成的 SVG、HTML、富文本、Markdown 渲染结果,哪怕短暂塞进主 document。
判断:复杂度不是护城河,是培养皿
Scratch 的修补路线很熟悉:正则不够,上 DOMPurify;DOMPurify 不管网络请求,加 hook;hook 不够,加 CSS parser;parser 漏了转义、变量、函数,再继续补。
看起来越来越专业,实际越来越脆。
SVG 不是一张简单图片。它能带 CSS,能引用外部资源,还会吃浏览器实现细节。CSS 更麻烦。今天是 url(),明天是 image-set()。规范和实验实现里还有未来可能打开入口的 src()、image()。
这些未来入口不能写成当前主流浏览器都可利用。现在还只能说,它们说明了一个方向:浏览器语法还在长,手写 sanitizer 的追赶成本不会下降。
更麻烦的是页面样式污染。它绕开的不是脚本执行,而是样式系统本身。2026 年披露的长 transition 技巧,可以让 SVG 被移除后,样式仍在全页残留。
这类问题不一定像 XSS 那样直接。但它很适合社工:盖住按钮,藏掉入口,把钓鱼提示伪装成站内内容。对儿童和教育场景来说,这个风险更刺眼,因为用户本来就更信任页面本身。
“千里之堤,溃于蚁穴。”这句话放在这里很合适。平台安全最怕的不是某个洞很大,而是边界留了一条缝,然后指望规则永远补得比浏览器快。
对维护 UGC 平台的开发者,动作层面已经很明确:延后把用户 SVG 直接放进主文档的设计;把测量、预览、转换放到隔离 iframe、沙箱环境、离屏文档或受限管线;如果采购或选型第三方渲染组件,要把“是否进入主 document”列成硬指标,而不是只问“有没有 sanitizer”。
该观察的不是补丁数量,而是边界有没有移走
早期浏览器安全也走过类似路。先盯危险标签、危险属性、特殊协议,后来才走向同源策略、沙箱和隔离上下文。不完全一样,但重复的是同一种结构:黑名单能挡一阵,边界设计才决定上限。
Scratch 更合理的方向也应当如此:不让攻击者控制的 SVG 进入主 document。需要测量,就在隔离环境里测。需要展示,就降级成更受限的格式或渲染结果。
服务器端保护也要审慎看。现有材料只能说,作者没有看到明确证据;Scratch support 声称有保护。没有更多细节前,不能断言服务器端防护不存在,也不能把“据说有保护”当成前端边界可以放松的理由。
接下来最该看三件事。
| 观察点 | 为什么重要 |
|---|---|
| Scratch 是否移除“插入主 document 测量”的路径 | 这是架构边界,不是局部补丁 |
长 transition 和 image-set() 是否被修复 | 这是 2026 年披露时仍在的问题 |
| 是否说明服务端规整、沙箱或隔离策略 | 这决定风险是否从根上收窄 |
平台总爱继续加过滤规则。原因不复杂:便宜、局部、短期不伤产品体验。产品经理能接受,工程改动也小。
代价是安全债滚雪球。每修一次,团队都以为离安全更近;下一年,新语法、新实现、新遗漏又把缺口打开。
这件事对所有 UGC 平台的提醒很硬:用户生成内容一旦进入主文档,你就已经把战场交给浏览器规范。到那时,复杂度不是盾牌,而是漏洞的温床。
