From 74fad546ff01002ebc91dbfc98c8aa545aec3020 Mon Sep 17 00:00:00 2001 From: Linghong Date: Sat, 12 Sep 2026 07:17:16 +0000 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20Responses=20=E6=A7=BD?= =?UTF-8?q?=E4=BD=8D=E5=AE=89=E5=85=A8=E4=BF=9D=E9=99=A9=E4=B8=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 拒绝超出 4096 的 output_index,避免异常上游输入触发巨额扩容 补充安全边界测试且不限制正常输出内容 --- server-rs/crates/platform-llm/src/lib.rs | 27 ++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/server-rs/crates/platform-llm/src/lib.rs b/server-rs/crates/platform-llm/src/lib.rs index f759cc8c0..d21c888d5 100644 --- a/server-rs/crates/platform-llm/src/lib.rs +++ b/server-rs/crates/platform-llm/src/lib.rs @@ -2276,7 +2276,7 @@ where accumulation.responses_output = output; } for (slot, item) in output_items { - upsert_responses_output_item(&mut accumulation.responses_output, slot, item); + upsert_responses_output_item(&mut accumulation.responses_output, slot, item)?; } if is_completion { @@ -3744,12 +3744,19 @@ fn upsert_responses_output_item( output: &mut Vec, slot: u64, item: serde_json::Value, -) { +) -> Result<(), LlmError> { + const MAX_RESPONSES_OUTPUT_SLOT: u64 = 4096; + if slot >= MAX_RESPONSES_OUTPUT_SLOT { + return Err(LlmError::Deserialize(format!( + "解析 LLM Responses SSE 事件失败:output_index 超出安全上限({slot} >= {MAX_RESPONSES_OUTPUT_SLOT})" + ))); + } let index = slot as usize; if index >= output.len() { output.resize(index + 1, serde_json::Value::Null); } output[index] = item; + Ok(()) } fn patch_responses_output_arguments(output: &mut [serde_json::Value], slot: u64, arguments: &str) { @@ -4103,6 +4110,22 @@ mod tests { use super::*; + #[test] + fn responses_output_slot_safety_fuse_rejects_only_out_of_range_indices() { + let mut output = Vec::new(); + upsert_responses_output_item(&mut output, 4095, serde_json::json!({"type": "message"})) + .expect("slot below the safety fuse should be accepted"); + assert_eq!(output.len(), 4096); + + let error = + upsert_responses_output_item(&mut output, 4096, serde_json::json!({"type": "message"})) + .expect_err("slot at the safety fuse should be rejected"); + assert!( + matches!(error, LlmError::Deserialize(message) if message.contains("output_index")) + ); + assert_eq!(output.len(), 4096); + } + #[test] fn llm_error_kind_is_stable_for_adapter_mapping() { assert_eq!(