MoonshotAI / MoonshotAI/kimi-code

web: 消息内容含 `[` + 大量 `\"` 转义时,打开该 session 渲染线程永久卡死(正则灾难性回溯)

Open
#3,622 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
7.5k
Forks
1.2k
Avg merge
11h 53m
Merged PRs (30d)
350

Description

你运行的 Kimi Code 版本是?

v0.41.0

你使用的是哪个开放平台/订阅?

Kimi Code (kimi.com/code)

你使用的是哪个模型?

k3-256k

你的电脑平台是?

Darwin 25.6.0 arm64 arm

你遇到了什么问题?

在 web UI(kimi web)中打开某个特定 session 时,浏览器标签页永久卡死:主线程 100% CPU 硬锁死,DevTools 里最后一批请求全部停在 pending,页面始终不可交互。同一个 session 在 TUI(kimi --continue)和 kimi vis 里完全正常,其他 session 在 web UI 也正常——卡死由该 session 的内容触发,且 session 已完全退出、未在任何地方运行时依然复现

与 #3519 不同:#3519 是「正在 streaming 的 session 打开时卡在 Loading」,本 issue 是内容触发的 ReDoS,session 完全空闲/退出状态下即可稳定复现。

复现步骤?
  1. 在任意 session 中粘贴下面的保证复现串[ + 60 组 \";该正则为指数级回溯,55 组起卡死 >20s,浏览器里等同永久):
[\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"

真实场景中的触发源是复制日志时带入的内嵌转义 JSON(如飞书卡片 payload,特征相同:[ 紧跟大量 \")。脱敏后的真实触发片段(204 字符,约卡 0.7s,仅用于说明原理,单独用不足以观察到卡死):

[{\"tag\":\"div\",\"text\":{\"content\":\"Savings XXXX XXXX, XXXX:0, XXXXX:0000000X, XXXXXX:0000000, XX:00X\",\"tag\":\"lark_md\"}},{\"tag\":\"hr\"},{\"tag\":\"div\",\"text\":{\"content\":\"XXXX: 00.00
  1. 完全退出该 CLI session。
  2. 运行 kimi web,在 web UI 打开该 session。
  3. 标签页在首次渲染时卡死,永不恢复。
期望的行为是什么?
  • 预期:session 正常渲染(慢一点也没关系)。
  • 实际:渲染主线程死循环,标签页彻底卡死。DevTools 中会话状态类请求(/status/goal/warnings/skillsPOST /fs:git_status)显示为 pending——但这只是表象:服务端响应全部正常(已用 curl 验证,单个和并发突发全部 <1s 返回 200)。pending 只是因为渲染线程冻结后永远无法处理响应回调。
补充信息

根因

渲染线程卡死在 web bundle(assets/index-*.js,压缩后函数名 t6)里的一个正则匹配中:

// 输入框附件引用解析正则
/(?<![!\\])\[(?:\\.|[^\]\n])+\]\(kimi-code-composer:\/\/attachments\/([1-9]\d*)\)/g

内层 (?:\\.|[^\]\n])+ 存在歧义:每个反斜杠位置两个分支都能消费(\\. 吃 2 字符,[^\]\n] 只吃反斜杠本身)。当输入以 [ 开头、包含数百个 \"永远匹配不到结尾的 ](kimi-code-composer://attachments/...) 时,匹配尝试按指数级回溯 → 灾难性回溯(ReDoS)。

证据

  • 对冻结的标签页发送 CDP Debugger.pause,间隔 1.5s 采样 3 次——三次调用栈逐字节相同,定格在同一指令:
t6   @ index-*.js L307:C6916   <- matchAll(i7e) 内部
t7e  @ index-*.js L307:C5247
iw   @ index-*.js L322:C895
V7e  @ index-*.js L326:C8514
t    @ index-*.js L326:C12696
(anonymous) @ L754:C6816
bB / Z5 / get dirty / C / n2 / PB  (响应式框架帧)
  • 在 Node 中用该正则直接对该 session 的 wire.jsonlmatchAll:挂死(>20s,手动杀掉)。用带超时的 worker 逐行二分定位到单条消息,再在消息内收缩得到上述 204 字符触发串(204 字符约耗时 0.7s;真实 7.5KB 消息等同永久)。
  • 服务端已排除:受影响 session 的 GET /status|goal|warnings|skillsPOST /fs:git_status 用 curl 单独/并发调用全部 <1s 返回 200。

修复建议

消除内层分组的歧义即可消灭指数回溯,例如让单字符分支排除反斜杠:

/(?<![!\\])\[(?:\\.|[^\]\\\n])+\]\(kimi-code-composer:\/\/attachments\/([1-9]\d*)\)/g

或者限制扫描长度 / 改成手写扫描器。另外建议用上面的触发串加一个回归测试,成本很低。

临时绕过方案

受影响的 session 用 TUI(kimi --continue)或 kimi vis 查看,避免在 web UI 打开。任何「[ + 大量 \"」形态的粘贴内容(复制含转义 JSON 的日志时很常见)都会触发此 bug。

Contribution
  • 我愿意自己提交修复此 bug 的 PR(请先等待维护者在本 issue 中批准)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the attachment-reference regex in assets/index-*.js around L307, and reproduce the hang with the supplied escape-string input or the Node matchAll check. Trace the bundled code to its web source, add the supplied trigger as a regression test, and confirm the affected session renders normally in kimi web without the main thread stalling.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend, performance, testing-qa, web-dev
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.