fix(gateway): cap request body size at 8 MiB; return 413 instead of OOM#51
Open
YOMXXX wants to merge 1 commit into
Open
fix(gateway): cap request body size at 8 MiB; return 413 instead of OOM#51YOMXXX wants to merge 1 commit into
YOMXXX wants to merge 1 commit into
Conversation
`parseJsonBody` buffered every incoming request body into an unbounded `Buffer[]` and only validated JSON at end-of-stream. A single oversized or never-ending POST to /capture, /seed, /search/* etc. could grow the daemon's heap until it OOM-crashed — and on a no-token (Hermes backward-compat) daemon, any local process can trigger this without authentication. Fix: - Cap each request body at `TDAI_GATEWAY_MAX_BODY_BYTES` (default 8 MiB — generous for /seed payloads with hundreds of historical sessions, small enough that a single request cannot OOM a typical node process). - Fail fast when a present `Content-Length` declares more than the cap, before any buffering. - Track running total during streaming, so a client that lies about Content-Length (or omits it via Transfer-Encoding: chunked) is still caught. - Pause the request stream (not destroy) on cap hit, so the dispatcher can still write the 413 response on the same socket; Node closes the keep-alive connection after `res.end()`. - New `PayloadTooLargeError` lets `handleRequest` map cap violations to HTTP 413 + a warn log, instead of falling through to the generic 500 branch that retried clients would interpret as a transient server bug. Malformed env values (`TDAI_GATEWAY_MAX_BODY_BYTES=not-a-number`, empty, negative) fall back to the default cap so a misconfig cannot brick the daemon. Tests: new src/gateway/__tests__/body-size.test.ts — 7 cases covering under-cap happy path, Content-Length fast-fail, chunked / lying-CL streaming guard, 413-not-500 dispatch contract, env override at construction time, malformed-env fallback. Signed-off-by: 李冠辰 <liguanchen@xiaomi.com>
This was referenced May 18, 2026
Collaborator
|
Hi @YOMXXX, 已收到关于 Gateway 请求体大小限制的修复 PR,感谢发现并修复!我们会评审后回复。 |
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.
Summary | 摘要
修复 TDAI Gateway 的请求体无上限 DoS 缺陷:
parseJsonBody此前把整个 body 累加到Buffer[]才校验,单个超大或永不结束的 POST 能把 daemon 堆内存撑到 OOM。无 token 的 Hermes backward-compat 模式下,任何本地进程都能无鉴权触发。Fix unbounded request-body DoS in TDAI Gateway:
parseJsonBodybuffered every incoming body into anBuffer[]and only validated JSON at end-of-stream — a single oversized or never-ending POST could grow daemon heap until OOM. On a no-token (Hermes backward-compat) daemon, any local process can trigger this without auth.Fix | 修复
TDAI_GATEWAY_MAX_BODY_BYTES(默认 8 MiB:足够容纳/seed几百个历史 session 的批量导入;远小于会让典型 Node 进程 OOM 的边界)。Content-Length且声明大小超过 limit,未读取任何 body 字节 就 413。Transfer-Encoding: chunked不带 CL 时,运行时累计字节数仍会触发 limit。req.pause()(不 destroy)—— 让 dispatcher 在同一个 socket 上写完 413 response,再由 Node 自然关闭 keep-alive 连接。直接 destroy 会让 response 写不出去退化到 500。PayloadTooLargeError,handleRequest的 catch 块识别后映射到 HTTP 413 + warn 日志,不再走 500 fallback —— 这对会在 5xx 重试但不重试 4xx 的客户端尤其重要。环境变量解析容错:
TDAI_GATEWAY_MAX_BODY_BYTES为非数字、空、负数时退回默认 cap,misconfig 不会让 daemon 启不起来。Tests
新建
src/gateway/__tests__/body-size.test.ts(7 cases):Content-Length > limit→ 413(fast-fail,不 buffer)Transfer-Encoding: chunkedbody > limit → 413 或 ECONNRESET(流式守门)exceeds 1024 bytes)TDAI_GATEWAY_MAX_BODY_BYTES=50生效(小 cap → 413)TDAI_GATEWAY_MAX_BODY_BYTES=not-a-number退回默认 8 MiBScope | 范围
parseJsonBody是 module-level function,签名修改向后兼容(新增可选参数有默认值)body-parser的limit选项语义DCO
Commit
c27498b带Signed-off-by: 李冠辰 <liguanchen@xiaomi.com>。