From 91087332d93c71c81f2587bcf09dad80a8178d60 Mon Sep 17 00:00:00 2001 From: ReSerendipity Date: Thu, 24 Sep 2026 00:05:59 +0800 Subject: [PATCH] =?UTF-8?q?fix(security):=20=E8=BD=AC=E4=B9=89=20step-audi?= =?UTF-8?q?o-editx=20/=20voicebox=20=E6=88=90=E5=8A=9F=E9=A1=B5=E7=9A=84?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E5=8F=AF=E6=8E=A7=E6=8F=92=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../routes/generate/step_audio_editx/edit.py | 20 +++++++++++++------ .../routes/generate/voicebox/convert.py | 19 ++++++++++++------ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/app/integrated_app/routes/generate/step_audio_editx/edit.py b/app/integrated_app/routes/generate/step_audio_editx/edit.py index 04c4c485..65bf602b 100644 --- a/app/integrated_app/routes/generate/step_audio_editx/edit.py +++ b/app/integrated_app/routes/generate/step_audio_editx/edit.py @@ -32,6 +32,7 @@ - 失败:HTMX HTML 错误片段 """ +import html import logging import os import time @@ -193,20 +194,27 @@ async def step_audio_editx_edit_endpoint( return _error_html(request, result.message, status_code=500) audio_filename = os.path.basename(result.audio_path) + # 这些值全部或部分来自请求(edit_type / edit_info 是表单原文,source_path 由上传 + # 文件名派生),此前直接插进 HTML 文本与属性 -> 反射型 XSS。quote=True 同时覆盖 + # 属性上下文(data-audio-filename / src / href / download)。 + esc_filename = html.escape(audio_filename, quote=True) + esc_source = html.escape(os.path.basename(source_path or ""), quote=True) + esc_edit_type = html.escape(str(edit_type), quote=True) + esc_edit_info = html.escape(edit_info or "(无)", quote=True) success_html = f""" -
+

✅ 音频编辑完成(耗时 {elapsed:.1f}s)

-

编辑类型: {edit_type}

-

编辑标签: {edit_info or "(无)"}

-

参考音频: {os.path.basename(source_path or "")}

+

编辑类型: {esc_edit_type}

+

编辑标签: {esc_edit_info}

+

参考音频: {esc_source}

输出时长: {result.duration:.2f}s

- + 下载编辑后的音频
diff --git a/app/integrated_app/routes/generate/voicebox/convert.py b/app/integrated_app/routes/generate/voicebox/convert.py index d0e04b1f..43a3a507 100644 --- a/app/integrated_app/routes/generate/voicebox/convert.py +++ b/app/integrated_app/routes/generate/voicebox/convert.py @@ -27,6 +27,7 @@ 3. 点击转换,输出用目标音色重说源内容的音频 """ +import html import logging import os import time @@ -183,20 +184,26 @@ async def voicebox_convert_endpoint( # 构建 HTMX 成功响应 audio_filename = os.path.basename(result.audio_path) + # 同 step_audio_editx/edit.py:audio_filename / 两个 basename / tau 均可被请求侧 + # 影响(上传文件名、表单值),此前直接插进 HTML 文本与属性 -> 反射型 XSS。 + esc_filename = html.escape(audio_filename, quote=True) + esc_source = html.escape(os.path.basename(source_path or ""), quote=True) + esc_target = html.escape(os.path.basename(target_path or ""), quote=True) + esc_tau = html.escape(str(tau), quote=True) success_html = f""" -
+

✅ 音色转换完成(耗时 {elapsed:.1f}s)

-

源音频: {os.path.basename(source_path or "")}

-

目标音色: {os.path.basename(target_path or "")}

-

转换强度 (tau): {tau}

+

源音频: {esc_source}

+

目标音色: {esc_target}

+

转换强度 (tau): {esc_tau}

输出时长: {result.duration:.2f}s

- + 下载转换后的音频