Skip to content

fix: 修复 safeUrl 未拦截危险 URL scheme - #5

Open
Zi-Yi-Ming wants to merge 1 commit into
AlephAITech:mainfrom
Zi-Yi-Ming:fix/safe-url-scheme
Open

Zi-Yi-Ming wants to merge 1 commit into
AlephAITech:mainfrom
Zi-Yi-Ming:fix/safe-url-scheme

Conversation

@Zi-Yi-Ming

Copy link
Copy Markdown

改动内容

  • 修复 site/js/markdown.jssafeUrl() 对 URL scheme 校验过于宽松的问题。
  • 拦截 javascript:data:vbscript:file:blob:about: 等危险 scheme,同时兼容大小写及 URL 编码形式。
  • 增加 safeUrl() 回归测试,并补充链接、图片、视频渲染层面的安全测试。
  • 增加 malformed percent-encoding 场景测试,确保异常编码不会导致渲染器抛出异常。

Why

原有 safeUrl() 在部分 URL 上仅通过首字符检查(/^[\w./-]/),导致包含危险 scheme 的值可能继续进入 HTML 的 hrefsrcdata-zoom 属性。

本次采用最小范围修复,仅收紧 URL scheme 校验,不引入新的依赖,也不改变正常的 http(s)、站内路径及相对路径行为。

验证方式

  • node --test tests/markdown.test.mjs12/12 通过
  • git diff --check通过(无空白字符错误)
  • npm run audit通过(需将 CHROME_PATH 指向本机 Chrome;相关工具默认硬编码 macOS 路径 /Applications/Google Chrome.app/Contents/MacOS/Google Chrome,在 Windows 上无法启动浏览器)
  • npm test部分通过后失败,失败项与本次修改无关,详见下方说明

npm test 失败说明(与本次修改无关)

设置 CHROME_PATH 后,npm test 依次执行:

  • tools/build-site-index.mjs — 通过
  • tools/check-boot.mjs — 通过
  • tools/check-landing.mjs — 通过
  • tools/check-features.mjs — 通过
  • tools/check-mobile.mjs失败360px articleWhere 对比度应至少达到 3:1

该断言读取的是 .article__wheregetComputedStyle().color(颜色来自未改动的 site/css/article.css 中的 var(--ink-faded)),与本次 URL scheme 校验无关。对照实验确认:将页面所用脚本替换为修改前 HEAD 版本markdown.js 后,失败信息完全一致(同样为 360px articleWhere 对比度应至少达到 3:1)。因此这是既有问题,本次未作修改。

安全影响

修复 Markdown renderer 中的 URL scheme 校验缺陷,避免危险 scheme 进入生成的 HTML URL 属性。

当前仓库的 Markdown 内容来自站内静态文件(content/site-index.jsoncontent/site-content.json,同源 fetch),未发现"外部不可信 Markdown 输入 → renderer → 真实浏览器执行"的完整链路。因此本问题准确定位为 URL sanitization / unsafe URL scheme validation 安全缺陷,并存在潜在 XSS 风险(一旦内容来源变为用户可控,<a href="javascript:..."> 将成为可点击的 XSS 向量),而非已确认的远程 XSS。

Product fact updates

不涉及。

safeUrl() 原先只校验 URL 首字符(/^[\w./-]/),导致 javascript:、data:、
vbscript:、file:、blob:、about: 等危险 scheme 可进入生成的 HTML URL 属性
(<a href>、<img src>、<video src>、data-zoom)。

现在对命中该分支的候选值先做 decodeURIComponent() 提取 scheme,再与 denylist
比对,命中则返回空字符串;decode 包裹在 try/catch 中,畸形百分号编码不会抛异常。
正常 http(s)、//、站内绝对路径与相对路径行为保持不变,HTML escaping 未被削弱。

新增 tests/markdown.test.mjs 回归测试:覆盖正常 URL、危险 scheme、大小写变体、
百分号编码、畸形编码,以及渲染层 href / src / data-zoom 输出。
Copilot AI lite review requested due to automatic review settings September 14, 2026 10:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants