fix(security): 转义 voicebox / step-audio-editx 成功页的请求可控插值(真反射型 XSS) - #153
Merged
Merged
Conversation
CodeQL #107/#108 (py/reflective-xss, high) 复核为真:两处 HTMLResponse 的 f-string 把 edit_type / edit_info(表单原文)、上传文件名派生的 basename、tau、target basename 直接 插进 HTML,audio_filename 还进了 4 处属性上下文;basename() 不去 < 与引号,属可实现 的反射型 XSS。统一改为 html.escape(..., quote=True),数字插值与 URL 语义不变。 同批复核的另 5 条判为误报(blob: URL / textContent / 固定相对重定向 / 模型输入去标签), 判定与依据写在 PR 描述,走 CodeQL dismiss,不在本 commit 改。 验证:80 条既有测试通过,且确认导入解析到本 worktree 副本(不是主仓另一分支那份); ruff check/format 通过、ast 可解析。未加路由级 XSS 断言(需 stub 引擎),列为后续项。 Signed-off-by: ReSerendipity <zengyangc@outlook.com>
ReSerendipity
enabled auto-merge (squash)
September 23, 2026 16:07
ReSerendipity
added a commit
that referenced
this pull request
Sep 23, 2026
新增 §7(现状以该节为准,§6 是 09-21 快照): - 本批 dismiss 16 条(routes/model.py 的 11 条 stack-trace 按 #96 绑 mitigated; 3 条 blob:/textContent 判误报;tabs.py 相对重定向 1 条;voxcpm2/design.py 去标签 属规则误用 1 条),每条在 CodeQL 上写了 280 字符内的绑定理由。open 76 → 56(实测分布 36 path-injection + 18 stack-trace + 2 reflective-xss,后者等 #153 合并消解)。 - 剩余 40 条逐条给判定:19 条已缓解可下批收口;17 条 path-injection 无强校验 (generation 3 / persona_metadata 6 / resolve_persona_ref 2 / voxcpm2 design+script 6); stack-trace 里确认 5 处 settings.py 把 str(exc) 原文放进响应,13 处待读。 - 写明一条口径:html.escape 只防 XSS,不防信息泄露,stack-trace 这族不能拿它交差。 - §7.3 衔接 issue #97(锁集已按"退"路自洽,但 4.52.x 的 16 条公告代价未见 pip-audit 命中/豁免说明)与 #99(3 处真 XSS 的 incomplete-sanitization 整族已归零,修法未复核)。 - SECURITY_REMEDIATION_TRACKER.md 补指向本表的反向链接(此前该链接依赖已关闭的 #81)。 Signed-off-by: ReSerendipity <zengyangc@outlook.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
修的是两条真反射型 XSS(CodeQL #107 / #108,
py/reflective-xsshigh)routes/generate/step_audio_editx/edit.py:196与routes/generate/voicebox/convert.py:186直接把请求可控值插进 HTML 文本与属性,无任何转义:
edit_type/edit_infoForm(...))source_path的 basenametau、target_pathbasenameaudio_filenamedata-audio-filename、src、href、download四处属性上下文basename()只去目录,不去<"—— 所以这不是理论风险。修法:统一html.escape(..., quote=True)(
quote=True才覆盖属性上下文),数字类插值(elapsed/duration)不变。验证与边界(说清楚,不夸大)
test_fe_be_consistency/test_a11y_static/test_engine_capability_contract/test_voice_clone_consent),且确认导入解析到本worktree 副本(
integrated_app.__file__实测在此路径下),不是主仓另一分支那份。ast可解析。契约/能力级覆盖。列为后续项(不假装测过)。
/api/audio/{filename}只做 HTML 转义,不做urllib.parse.quote;文件名由应用生成,现状不含需要 URL 编码的字符,避免顺手改行为。
同批复核但未改的 5 条(判定与依据在 PR 描述与 docs 里,走 dismiss)
js/xss-through-dom3 条(indextts20_clone.html:140、indextts2_clone.html:175、indextts2_duration.html:211):告警行是previewAudio.src = URL.createObjectURL(file),只能产同源
blob:URL,不可能是javascript:;同函数里的文件名走的是textContent(DOM 文本赋值,非 HTML 解析)→ 误报。py/url-redirectionbuild(deps): bump github/codeql-action from 3 to 4 #61(routes/tabs.py:292):RedirectResponse(url=f"/?tab={tab_name}")目标是固定相对路径,用户串落在 query 值里,不构成开放重定向;该文件另有 frozenset 白名单
显式拦
tab_name="../../config.yaml"→ 误报。py/bad-tag-filterfeat(ui): 模型切换器/语音创建表单/健康监控与样式增强;后端路由支撑 #62(engines/voxcpm2/design.py:82):这段正则去标签的对象是送进模型的文本提示(并受 300 字符硬限),不是 XSS 出口;全仓 Jinja 模板里
|safe仅 1 处(
partials/progress_bar.html,自有内容),渲染面由 autoescape 覆盖 → 规则误用。